Lots of ui improvments
This commit is contained in:
parent
1a9c1f5cbc
commit
fd9f67f555
@ -1,15 +1,16 @@
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// import DevTools from "mobx-react-devtools";
|
// import DevTools from "mobx-react-devtools";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Redirect, Route } from "react-router";
|
import { Redirect, Route, Switch } from "react-router";
|
||||||
import { BrowserRouter as Router } from "react-router-dom";
|
import { BrowserRouter as Router } from "react-router-dom";
|
||||||
import { Container } from "semantic-ui-react";
|
import { Container } from "semantic-ui-react";
|
||||||
|
|
||||||
import { DevicesView, MessagesView, MessageTest, NavBar } from "@app/components";
|
import { DevicesView, MessagesView, MessageTest, NavBar } from "@app/components";
|
||||||
|
|
||||||
import "@app/styles/app.css";
|
// tslint:disable:ordered-imports
|
||||||
import "font-awesome/css/font-awesome.css";
|
import "font-awesome/css/font-awesome.css";
|
||||||
import "semantic-ui-css/semantic.css";
|
import "semantic-ui-css/semantic.css";
|
||||||
|
import "@app/styles/app.scss";
|
||||||
|
|
||||||
function DevicePage() {
|
function DevicePage() {
|
||||||
return (
|
return (
|
||||||
@ -28,11 +29,13 @@ class App extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
<Container className="app">
|
<Container className="app">
|
||||||
<NavBar />
|
<NavBar/>
|
||||||
|
|
||||||
<Route path="/devices/grinklers" component={DevicePage}/>
|
<Switch>
|
||||||
<Route path="/messagesTest" component={MessagesTestPage}/>
|
<Route path="/devices/grinklers" component={DevicePage}/>
|
||||||
<Redirect to="/"/>
|
<Route path="/messagesTest" component={MessagesTestPage}/>
|
||||||
|
<Redirect to="/"/>
|
||||||
|
</Switch>
|
||||||
|
|
||||||
<MessagesView/>
|
<MessagesView/>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -1,24 +1,39 @@
|
|||||||
.device {
|
.device {
|
||||||
.header {
|
.header {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@media only screen and (min-width : 768px) {
|
@media only screen and (min-width: 768px) {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.connectionState {
|
}
|
||||||
@media only screen and (min-width : 768px) {
|
.ui.stackable.grid.in-container > .row > .column {
|
||||||
margin-left: .75em;
|
@media only screen and (max-width: 991px) {
|
||||||
}
|
padding-left: 0 !important;
|
||||||
font-size: .75em;
|
padding-right: 0 !important;
|
||||||
font-weight: lighter;
|
|
||||||
|
|
||||||
&.connected {
|
|
||||||
color: #13D213;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disconnected {
|
|
||||||
color: #D20000;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.ui.stackable.grid.in-container {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.connectionState {
|
||||||
|
@media only screen and (min-width: 768px) {
|
||||||
|
margin-left: .75em;
|
||||||
|
}
|
||||||
|
font-size: .75em;
|
||||||
|
font-weight: lighter;
|
||||||
|
|
||||||
|
&.connected {
|
||||||
|
color: #13D213;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disconnected {
|
||||||
|
color: #D20000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionRunner .queue {
|
||||||
|
max-height: 14em;
|
||||||
|
height: 14em;
|
||||||
|
overflow-y: scroll;
|
||||||
}
|
}
|
@ -64,16 +64,16 @@ class DeviceView extends React.Component<DeviceViewProps> {
|
|||||||
<Item.Meta>
|
<Item.Meta>
|
||||||
Raspberry Pi Grinklers Device
|
Raspberry Pi Grinklers Device
|
||||||
</Item.Meta>
|
</Item.Meta>
|
||||||
<Grid stackable>
|
<SectionRunnerView sectionRunner={sectionRunner} sections={sections}/>
|
||||||
<Grid.Column width="8">
|
<Grid>
|
||||||
|
<Grid.Column mobile="16" tablet="16" computer="8">
|
||||||
<SectionTable sections={sections}/>
|
<SectionTable sections={sections}/>
|
||||||
</Grid.Column>
|
</Grid.Column>
|
||||||
<Grid.Column width="8">
|
<Grid.Column mobile="16" tablet="16" computer="8">
|
||||||
<RunSectionForm sections={sections} uiStore={uiStore}/>
|
<RunSectionForm device={this.device} uiStore={uiStore}/>
|
||||||
</Grid.Column>
|
</Grid.Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
<ProgramTable programs={programs} sections={sections}/>
|
<ProgramTable programs={programs} sections={sections}/>
|
||||||
<SectionRunnerView sectionRunner={sectionRunner} sections={sections}/>
|
|
||||||
</Item.Content>
|
</Item.Content>
|
||||||
</Item>
|
</Item>
|
||||||
);
|
);
|
||||||
|
@ -30,9 +30,9 @@ export class ScheduleView extends React.Component<{ schedule: Schedule }> {
|
|||||||
const to = formatDateOfYear(schedule.to, "To ");
|
const to = formatDateOfYear(schedule.to, "To ");
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
At {times} <br />
|
At {times} <br/>
|
||||||
On {weekdays} <br />
|
On {weekdays} <br/>
|
||||||
{from} <br />
|
{from} <br/>
|
||||||
{to}
|
{to}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -40,7 +40,16 @@ export class ScheduleView extends React.Component<{ schedule: Schedule }> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export default class ProgramTable extends React.Component<{ programs: Program[], sections: Section[] }> {
|
export default class ProgramTable extends React.Component<{
|
||||||
|
programs: Program[], sections: Section[],
|
||||||
|
}, {
|
||||||
|
expandedPrograms: Program[],
|
||||||
|
}> {
|
||||||
|
constructor(p: any) {
|
||||||
|
super(p);
|
||||||
|
this.state = { expandedPrograms: [] };
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const programRows = Array.prototype.concat.apply([],
|
const programRows = Array.prototype.concat.apply([],
|
||||||
this.props.programs.map(this.renderRows));
|
this.props.programs.map(this.renderRows));
|
||||||
@ -54,8 +63,8 @@ export default class ProgramTable extends React.Component<{ programs: Program[],
|
|||||||
<Table.Row>
|
<Table.Row>
|
||||||
<Table.HeaderCell className="program--number">#</Table.HeaderCell>
|
<Table.HeaderCell className="program--number">#</Table.HeaderCell>
|
||||||
<Table.HeaderCell className="program--name">Name</Table.HeaderCell>
|
<Table.HeaderCell className="program--name">Name</Table.HeaderCell>
|
||||||
<Table.HeaderCell className="program--running">Running?</Table.HeaderCell>
|
|
||||||
<Table.HeaderCell className="program--enabled">Enabled?</Table.HeaderCell>
|
<Table.HeaderCell className="program--enabled">Enabled?</Table.HeaderCell>
|
||||||
|
<Table.HeaderCell className="program--running">Running?</Table.HeaderCell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
</Table.Header>
|
</Table.Header>
|
||||||
<Table.Body>
|
<Table.Body>
|
||||||
@ -78,25 +87,30 @@ export default class ProgramTable extends React.Component<{ programs: Program[],
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
const cancelOrRun = () => running ? program.cancel() : program.run();
|
const cancelOrRun = () => running ? program.cancel() : program.run();
|
||||||
return [(
|
const rows = [(
|
||||||
<Table.Row key={i}>
|
<Table.Row key={i}>
|
||||||
<Table.Cell className="program--number">{"" + (i + 1)}</Table.Cell>
|
<Table.Cell className="program--number">{"" + (i + 1)}</Table.Cell>
|
||||||
<Table.Cell className="program--name">{name}</Table.Cell>
|
<Table.Cell className="program--name">{name}</Table.Cell>
|
||||||
|
<Table.Cell className="program--enabled">{enabled ? "Enabled" : "Not enabled"}</Table.Cell>
|
||||||
<Table.Cell className="program--running">
|
<Table.Cell className="program--running">
|
||||||
{running ? "Running" : "Not running"}
|
<span>{running ? "Running" : "Not running"}</span>
|
||||||
<Button className="program--runningButton" onClick={cancelOrRun}>
|
<div className="flex-spacer"/>
|
||||||
|
<Button size="small" onClick={cancelOrRun}>
|
||||||
{running ? "Cancel" : "Run"}
|
{running ? "Cancel" : "Run"}
|
||||||
</Button>
|
</Button>
|
||||||
</Table.Cell>
|
</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">
|
|
||||||
<h4>Sequence: </h4> {sequenceItems}
|
|
||||||
<h4>Schedule: </h4> <ScheduleView schedule={schedule} />
|
|
||||||
</Table.Cell>
|
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
)];
|
)];
|
||||||
|
if (false) {
|
||||||
|
rows.push(
|
||||||
|
<Table.Row key={i + .5}>
|
||||||
|
<Table.Cell className="program--sequence" colSpan="4">
|
||||||
|
<h4>Sequence: </h4> {sequenceItems}
|
||||||
|
<h4>Schedule: </h4> <ScheduleView schedule={schedule}/>
|
||||||
|
</Table.Cell>
|
||||||
|
</Table.Row>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,13 @@ import { DropdownItemProps, DropdownProps, Form, Header, Segment } from "semanti
|
|||||||
import { UiStore } from "@app/state";
|
import { UiStore } from "@app/state";
|
||||||
import { Duration } from "@common/Duration";
|
import { Duration } from "@common/Duration";
|
||||||
import log from "@common/logger";
|
import log from "@common/logger";
|
||||||
import { Section } from "@common/sprinklers";
|
import { Section, SprinklersDevice } from "@common/sprinklers";
|
||||||
import { RunSectionResponse } from "@common/sprinklers/requests";
|
import { RunSectionResponse } from "@common/sprinklers/requests";
|
||||||
import DurationInput from "./DurationInput";
|
import DurationInput from "./DurationInput";
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export default class RunSectionForm extends React.Component<{
|
export default class RunSectionForm extends React.Component<{
|
||||||
sections: Section[],
|
device: SprinklersDevice,
|
||||||
uiStore: UiStore,
|
uiStore: UiStore,
|
||||||
}, {
|
}, {
|
||||||
duration: Duration,
|
duration: Duration,
|
||||||
@ -70,7 +70,7 @@ export default class RunSectionForm extends React.Component<{
|
|||||||
if (typeof this.state.section !== "number") {
|
if (typeof this.state.section !== "number") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const section: Section = this.props.sections[this.state.section];
|
const section: Section = this.props.device.sections[this.state.section];
|
||||||
const { duration } = this.state;
|
const { duration } = this.state;
|
||||||
section.run(duration.toSeconds())
|
section.run(duration.toSeconds())
|
||||||
.then(this.onRunSuccess)
|
.then(this.onRunSuccess)
|
||||||
@ -80,14 +80,15 @@ export default class RunSectionForm extends React.Component<{
|
|||||||
private onRunSuccess = (result: RunSectionResponse) => {
|
private onRunSuccess = (result: RunSectionResponse) => {
|
||||||
log.debug({ result }, "requested section run");
|
log.debug({ result }, "requested section run");
|
||||||
this.props.uiStore.addMessage({
|
this.props.uiStore.addMessage({
|
||||||
color: "green", header: "Section running",
|
success: true, header: "Section running",
|
||||||
|
content: result.message, timeout: 2000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRunError = (err: RunSectionResponse) => {
|
private onRunError = (err: RunSectionResponse) => {
|
||||||
log.error(err, "error running section");
|
log.error(err, "error running section");
|
||||||
this.props.uiStore.addMessage({
|
this.props.uiStore.addMessage({
|
||||||
color: "red", header: "Error running section",
|
error: true, header: "Error running section",
|
||||||
content: err.message,
|
content: err.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -98,7 +99,7 @@ export default class RunSectionForm extends React.Component<{
|
|||||||
|
|
||||||
@computed
|
@computed
|
||||||
private get sectionOptions(): DropdownItemProps[] {
|
private get sectionOptions(): DropdownItemProps[] {
|
||||||
return this.props.sections.map((s, i) => ({
|
return this.props.device.sections.map((s, i) => ({
|
||||||
text: s ? s.name : null,
|
text: s ? s.name : null,
|
||||||
value: i,
|
value: i,
|
||||||
}));
|
}));
|
||||||
|
@ -1,37 +1,116 @@
|
|||||||
import * as classNames from "classnames";
|
import * as classNames from "classnames";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Button, Icon, Segment } from "semantic-ui-react";
|
import { Button, Icon, Progress, Segment } from "semantic-ui-react";
|
||||||
|
|
||||||
import { Duration } from "@common/Duration";
|
import { Duration } from "@common/Duration";
|
||||||
|
import log from "@common/logger";
|
||||||
import { Section, SectionRun, SectionRunner } from "@common/sprinklers";
|
import { Section, SectionRun, SectionRunner } from "@common/sprinklers";
|
||||||
|
|
||||||
function PausedState({ paused }: { paused: boolean }) {
|
interface PausedStateProps {
|
||||||
|
paused: boolean;
|
||||||
|
togglePaused: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function PausedState({ paused, togglePaused }: PausedStateProps) {
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
"sectionRunner--pausedState": true,
|
"sectionRunner--pausedState": true,
|
||||||
"sectionRunner--pausedState-paused": paused,
|
"sectionRunner--pausedState-paused": paused,
|
||||||
"sectionRunner--pausedState-unpaused": !paused,
|
"sectionRunner--pausedState-unpaused": !paused,
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<span className={classes}>
|
<Button className={classes} size="tiny" onClick={togglePaused}>
|
||||||
<Icon name={paused ? "pause" : "play"} />
|
<Icon name={paused ? "pause" : "play"}/>
|
||||||
{paused ? "Paused" : "Processing"}
|
{paused ? "Paused" : "Processing"}
|
||||||
</span>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SectionRunView({ run, sections }:
|
class SectionRunView extends React.Component<{
|
||||||
{ run: SectionRun, sections: Section[] }) {
|
run: SectionRun;
|
||||||
const section = sections[run.section];
|
sections: Section[];
|
||||||
const current = run.startTime != null;
|
}, {
|
||||||
const duration = Duration.fromSeconds(run.duration);
|
now: number;
|
||||||
const cancel = run.cancel;
|
}> {
|
||||||
return (
|
animationFrameHandle: number | null = null;
|
||||||
<Segment inverted={current} color={current ? "green" : undefined}>
|
startTime: number;
|
||||||
'{section.name}' for {duration.toString()}
|
|
||||||
<Button onClick={cancel} icon><Icon name="remove" /></Button>
|
constructor(p: any) {
|
||||||
</Segment>
|
super(p);
|
||||||
);
|
const now = performance.now();
|
||||||
|
this.state = { now };
|
||||||
|
this.startTime = Date.now() - now;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.requestAnimationFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
this.requestAnimationFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.cancelAnimationFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelAnimationFrame = () => {
|
||||||
|
if (this.animationFrameHandle != null) {
|
||||||
|
cancelAnimationFrame(this.animationFrameHandle);
|
||||||
|
this.animationFrameHandle = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestAnimationFrame = () => {
|
||||||
|
const startTime = this.props.run.startTime;
|
||||||
|
if (startTime != null) {
|
||||||
|
if (this.animationFrameHandle == null) {
|
||||||
|
this.animationFrameHandle = requestAnimationFrame(this.updateNow);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.cancelAnimationFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNow = (now: number) => {
|
||||||
|
this.animationFrameHandle = null;
|
||||||
|
this.setState({
|
||||||
|
now: this.startTime + now,
|
||||||
|
});
|
||||||
|
this.requestAnimationFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { run, sections } = this.props;
|
||||||
|
let now = this.state.now;
|
||||||
|
const section = sections[run.section];
|
||||||
|
const duration = Duration.fromSeconds(run.duration);
|
||||||
|
const cancel = run.cancel;
|
||||||
|
const description = `'${section.name}' for ${duration.toString()}`;
|
||||||
|
let running: boolean = false;
|
||||||
|
let paused: boolean = false;
|
||||||
|
let progressBar: React.ReactNode | undefined;
|
||||||
|
if (run.startTime != null) {
|
||||||
|
running = true;
|
||||||
|
if (run.pauseTime) {
|
||||||
|
now = run.pauseTime.valueOf();
|
||||||
|
paused = true;
|
||||||
|
}
|
||||||
|
const elapsed = (now.valueOf() - run.startTime.valueOf()) / 1000;
|
||||||
|
const percentage = elapsed / run.duration;
|
||||||
|
progressBar =
|
||||||
|
<Progress color={paused ? "yellow" : "blue"} size="tiny" percent={percentage * 100}/>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Segment className="sectionRun">
|
||||||
|
<div className="flex-horizontal-space-between">
|
||||||
|
{description}
|
||||||
|
<Button onClick={cancel} icon size="mini"><Icon name="remove"/></Button>
|
||||||
|
</div>
|
||||||
|
{progressBar}
|
||||||
|
</Segment>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -42,15 +121,32 @@ export default class SectionRunnerView extends React.Component<{
|
|||||||
const { current, queue, paused } = this.props.sectionRunner;
|
const { current, queue, paused } = this.props.sectionRunner;
|
||||||
const { sections } = this.props;
|
const { sections } = this.props;
|
||||||
const queueView = queue.map((run) =>
|
const queueView = queue.map((run) =>
|
||||||
<SectionRunView key={run.id} run={run} sections={sections} />);
|
<SectionRunView key={run.id} run={run} sections={sections}/>);
|
||||||
|
if (current) {
|
||||||
|
queueView.unshift(<SectionRunView run={current} sections={sections}/>);
|
||||||
|
}
|
||||||
|
if (queueView.length === 0) {
|
||||||
|
queueView.push(<Segment>No items in queue</Segment>);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Segment>
|
<Segment className="sectionRunner">
|
||||||
<h4>Section Runner Queue <PausedState paused={paused} /></h4>
|
<div style={{ display: "flex", alignContent: "baseline" }}>
|
||||||
<Segment.Group>
|
<h4 style={{ marginBottom: 0 }}>Section Runner Queue</h4>
|
||||||
{current && <SectionRunView run={current} sections={sections} />}
|
<div className="flex-spacer"/>
|
||||||
|
<PausedState paused={paused} togglePaused={this.togglePaused}/>
|
||||||
|
</div>
|
||||||
|
<Segment.Group className="queue">
|
||||||
{queueView}
|
{queueView}
|
||||||
</Segment.Group>
|
</Segment.Group>
|
||||||
</Segment>
|
</Segment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
togglePaused = () => {
|
||||||
|
const { sectionRunner } = this.props;
|
||||||
|
const paused = !sectionRunner.paused;
|
||||||
|
sectionRunner.setPaused(paused)
|
||||||
|
.then((res) => log.info(res, "set section runner paused to " + paused))
|
||||||
|
.catch((err) => log.info({ err }, "error setting section runner paused status"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ export default class SectionTable extends React.Component<{ sections: Section[]
|
|||||||
render() {
|
render() {
|
||||||
const rows = this.props.sections.map(SectionTable.renderRow);
|
const rows = this.props.sections.map(SectionTable.renderRow);
|
||||||
return (
|
return (
|
||||||
<Table celled striped unstackable>
|
<Table celled striped unstackable compact>
|
||||||
<Table.Header>
|
<Table.Header>
|
||||||
<Table.Row>
|
<Table.Row>
|
||||||
<Table.HeaderCell colSpan="3">Sections</Table.HeaderCell>
|
<Table.HeaderCell colSpan="3">Sections</Table.HeaderCell>
|
||||||
|
@ -13,7 +13,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sectionRunner--pausedState-unpaused {
|
.sectionRunner--pausedState-unpaused {
|
||||||
color: #BBBBBB;
|
}
|
||||||
|
|
||||||
|
.flex-horizontal-space-between {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionRun .progress {
|
||||||
|
margin: 1em 0 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionRun .ui.progress .bar {
|
||||||
|
-webkit-transition: none;
|
||||||
|
transition: none;
|
||||||
|
min-width: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section--number,
|
.section--number,
|
||||||
@ -31,10 +46,16 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.program--runningButton {
|
.ui.table {
|
||||||
margin-left: 1em !important;
|
tr > td.program--running {
|
||||||
|
display: flex !important;
|
||||||
|
@media only screen and (min-width: 768px) {
|
||||||
|
//line-height: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.section--state-true {
|
.section--state-true {
|
||||||
color: green;
|
color: green;
|
||||||
}
|
}
|
||||||
@ -63,3 +84,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex-spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
@ -176,6 +176,7 @@ const getConfig = module.exports = (env) => {
|
|||||||
sourceMap: shouldUseSourceMap,
|
sourceMap: shouldUseSourceMap,
|
||||||
}),
|
}),
|
||||||
isDev && new webpack.HotModuleReplacementPlugin(),
|
isDev && new webpack.HotModuleReplacementPlugin(),
|
||||||
|
new webpack.NamedModulesPlugin(),
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -36,7 +36,7 @@ export const sectionRun: ModelSchema<s.SectionRun> = {
|
|||||||
section: primitive(),
|
section: primitive(),
|
||||||
duration: common.duration,
|
duration: common.duration,
|
||||||
startTime: common.date,
|
startTime: common.date,
|
||||||
endTime: common.date,
|
pauseTime: common.date,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user