Merge pull request #1577 from gabrielburnworth/staging

Panel updates and fixes
pull/1578/head
Rick Carlino 2019-11-20 14:21:36 -06:00 committed by GitHub
commit 8ac0c0625e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 193 additions and 104 deletions

View File

@ -212,6 +212,15 @@
background-color: darken($panel_blue, 5%) !important;
}
}
&.panel-navy {
background-color: $panel_navy;
box-shadow: 0 2px 0px 0px darken($panel_navy, 12%);
&:focus,
&:hover,
&.active {
background-color: darken($panel_navy, 5%) !important;
}
}
&.panel-brown {
background-color: $panel_brown;
box-shadow: 0 2px 0px 0px darken($panel_brown, 12%);

View File

@ -47,6 +47,8 @@ $panel_medium_light_gray: #e6e6e6;
$panel_light_gray: #f9fbfc;
$panel_blue: #026365;
$panel_light_blue: #f0f8f8;
$panel_navy: #334970;
$panel_light_navy: #f3f5f9;
$panel_brown: #9e630a;
$panel_light_brown: #fbf7f0;
$panel_teal: #1eb287;

View File

@ -411,8 +411,6 @@
}
.garden-snapshot {
margin-left: 2rem;
margin-right: 2rem;
button {
&.pseudo-disabled {
cursor: not-allowed;
@ -421,7 +419,7 @@
}
.saved-garden-list {
.saved-garden-row {
.saved-garden-search-item {
padding: 0.25rem;
button {
margin-bottom: 1rem;
@ -431,7 +429,7 @@
line-height: 3rem;
cursor: pointer;
padding-right: 0;
label {
span {
margin: 0;
pointer-events: none;
margin-left: 1rem;
@ -443,16 +441,6 @@
margin-right: 1rem;
}
}
&:hover {
background: $light_gray;
}
&.selected {
background: $gray;
p,
input {
font-weight: bold;
}
}
}
}

View File

@ -114,6 +114,15 @@
}
}
}
&.navy-panel {
background-color: $panel_light_navy;
div[class*="search-item"] {
&:hover,
&.hovered {
background: darken($panel_light_navy, 10%);
}
}
}
&.teal-panel {
background-color: $panel_light_teal;
div[class*="search-item"] {
@ -161,6 +170,9 @@
&.blue-panel {
background-color: $panel_blue;
}
&.navy-panel {
background-color: $panel_navy;
}
&.teal-panel {
background-color: $panel_teal;
}
@ -321,25 +333,31 @@
.point-creation-panel {
.panel-content {
.row {
margin-left: 0;
margin-right: 0;
ul {
margin-bottom: 0;
}
margin-top: 1rem;
label {
margin-top: 0;
}
p {
margin-top: 1rem;
}
padding: 0 3rem;
padding-right: 0;
padding-left: 0;
.fb-button {
margin: 1rem;
&.green {
margin-right: 1.5rem;
}
&.delete {
float: left;
margin-top: 1rem;
}
}
.saucer {
margin-top: 0.25rem;
margin-left: 1rem;
margin: 1rem;
margin-left: 2rem;
}
.delete-row {
padding-left: 1rem;
margin: 1.5rem;
}
}
}
@ -350,7 +368,7 @@
margin: 1rem;
margin-left: 2rem;
}
.red {
.fb-button & .red {
display: block;
margin-top: 3rem;
}
@ -477,7 +495,7 @@
}
.move-to-panel-content {
margin-top: 6rem;
margin-top: 1rem;
margin-left: 1rem;
margin-right: 1rem;
button {
@ -531,7 +549,10 @@
.saved-garden-panel-content {
padding: 0;
.row {
margin: 0;
margin-top: 1rem;
margin-left: 1rem;
margin-right: 1rem;
}
hr {
width: 100%;
@ -572,8 +593,6 @@
}
.saved-garden-edit-panel-content {
margin-left: 3rem;
margin-right: 3rem;
button {
margin-left: 0.5rem;
margin-top: 1rem;
@ -583,6 +602,9 @@
text-align: center;
padding: 3rem;
}
.row {
margin: 0;
}
}
.clear-button {
text-transform: uppercase;

View File

@ -875,7 +875,11 @@ ul {
p,
h5,
a {
color: $panel_green;
color: $panel_navy;
}
.empty-state-graphic {
filter: hue-rotate(135deg) brightness(0.5);
color: $panel_navy;
}
}
&.events {

View File

@ -38,7 +38,7 @@ type HOUR =
type TimeTable = Record<HOUR, DropDownItem>;
type EveryTimeTable = Record<PreferredHourFormat, TimeTable>;
const TIME_TABLE_12H: TimeTable = {
0: { label: "Midnight", value: 0 },
0: { label: t("Midnight"), value: 0 },
1: { label: "1:00 AM", value: 1 },
2: { label: "2:00 AM", value: 2 },
3: { label: "3:00 AM", value: 3 },
@ -50,7 +50,7 @@ const TIME_TABLE_12H: TimeTable = {
9: { label: "9:00 AM", value: 9 },
10: { label: "10:00 AM", value: 10 },
11: { label: "11:00 AM", value: 11 },
12: { label: "Noon", value: 12 },
12: { label: t("Noon"), value: 12 },
13: { label: "1:00 PM", value: 13 },
14: { label: "2:00 PM", value: 14 },
15: { label: "3:00 PM", value: 15 },
@ -62,7 +62,7 @@ const TIME_TABLE_12H: TimeTable = {
21: { label: "9:00 PM", value: 21 },
22: { label: "10:00 PM", value: 22 },
23: { label: "11:00 PM", value: 23 },
[IMMEDIATELY]: { label: "as soon as possible", value: IMMEDIATELY },
[IMMEDIATELY]: { label: t("as soon as possible"), value: IMMEDIATELY },
};
const TIME_TABLE_24H: TimeTable = {
0: { label: "00:00", value: 0 },
@ -89,7 +89,7 @@ const TIME_TABLE_24H: TimeTable = {
21: { label: "21:00", value: 21 },
22: { label: "22:00", value: 22 },
23: { label: "23:00", value: 23 },
[IMMEDIATELY]: { label: "as soon as possible", value: IMMEDIATELY },
[IMMEDIATELY]: { label: t("as soon as possible"), value: IMMEDIATELY },
};
const DEFAULT_HOUR: keyof TimeTable = IMMEDIATELY;

View File

@ -40,7 +40,7 @@ describe("<DesignerNavTabs />", () => {
mockPath = "/app/designer/gardens";
mockDev = true;
const wrapper = shallow(<DesignerNavTabs />);
expect(wrapper.hasClass("green-panel")).toBeTruthy();
expect(wrapper.hasClass("navy-panel")).toBeTruthy();
expect(wrapper.html()).toContain("active");
});

View File

@ -28,6 +28,7 @@ export enum PanelColor {
lightGray = "light-gray",
yellow = "yellow",
blue = "blue",
navy = "navy",
teal = "teal",
red = "red",
}
@ -36,7 +37,7 @@ export const TAB_COLOR: { [key in Panel]: PanelColor } = {
[Panel.Map]: PanelColor.gray,
[Panel.Plants]: PanelColor.green,
[Panel.FarmEvents]: PanelColor.yellow,
[Panel.SavedGardens]: PanelColor.green,
[Panel.SavedGardens]: PanelColor.navy,
[Panel.Tools]: PanelColor.gray,
[Panel.Settings]: PanelColor.gray,
[Panel.Points]: PanelColor.teal,

View File

@ -115,8 +115,8 @@ describe("<CreatePoints />", () => {
const p = fakeProps();
p.currentPoint = { cx: 0, cy: 0, r: 100 };
const panel = mount<CreatePoints>(<CreatePoints {...p} />);
const wrapper = shallow(panel.instance().PointName());
wrapper.find("BlurableInput").simulate("commit", {
const wrapper = shallow(panel.instance().PointProperties());
wrapper.find("BlurableInput").first().simulate("commit", {
currentTarget: { value: "new name" }
});
expect(p.dispatch).toHaveBeenCalledWith({
@ -208,7 +208,7 @@ describe("<CreatePoints />", () => {
const wrapper = shallow<CreatePoints>(<CreatePoints {...p} />);
const PP = wrapper.instance().PointProperties;
const component = shallow(<PP />);
component.find("BlurableInput").first().simulate("commit", {
component.find("BlurableInput").at(1).simulate("commit", {
currentTarget: { value: "10" }
});
expect(p.dispatch).toHaveBeenCalledWith({

View File

@ -8,7 +8,7 @@ import { shallow } from "enzyme";
import {
EditPointLocation, EditPointLocationProps,
EditPointRadius, EditPointRadiusProps,
EditPointColor, EditPointColorProps, updatePoint,
EditPointColor, EditPointColorProps, updatePoint, EditPointName, EditPointNameProps,
} from "../point_edit_actions";
import { fakePoint } from "../../../__test_support__/fake_state/resources";
import { edit, save } from "../../../api/crud";
@ -28,6 +28,22 @@ describe("updatePoint()", () => {
});
});
describe("<EditPointName />", () => {
const fakeProps = (): EditPointNameProps => ({
updatePoint: jest.fn(),
name: "point name",
});
it("edits name", () => {
const p = fakeProps();
const wrapper = shallow(<EditPointName {...p} />);
wrapper.find("BlurableInput").first().simulate("commit", {
currentTarget: { value: "new point name" }
});
expect(p.updatePoint).toHaveBeenCalledWith({ name: "new point name" });
});
});
describe("<EditPointLocation />", () => {
const fakeProps = (): EditPointLocationProps => ({
updatePoint: jest.fn(),

View File

@ -46,7 +46,7 @@ describe("<EditPoint />", () => {
it("renders with points", () => {
mockPath = "/app/designer/points/1";
const wrapper = mount(<EditPoint {...fakeProps()} />);
expect(wrapper.text()).toContain("Edit Point 1");
expect(wrapper.text()).toContain("Edit point");
});
it("moves the device to a particular point", () => {

View File

@ -5,7 +5,7 @@ jest.mock("../../../history", () => ({
}));
import * as React from "react";
import { mount } from "enzyme";
import { mount, shallow } from "enzyme";
import {
RawEditWeed as EditWeed, EditWeedProps, mapStateToProps
} from "../weeds_edit";
@ -14,6 +14,8 @@ import { fakeState } from "../../../__test_support__/fake_state";
import {
buildResourceIndex
} from "../../../__test_support__/resource_index_builder";
import { Actions } from "../../../constants";
import { DesignerPanelHeader } from "../designer_panel";
describe("<EditWeed />", () => {
const fakeProps = (): EditWeedProps => ({
@ -36,6 +38,19 @@ describe("<EditWeed />", () => {
const wrapper = mount(<EditWeed {...p} />);
expect(wrapper.text().toLowerCase()).toContain("edit");
});
it("goes back", () => {
mockPath = "/app/designer/weeds/1";
const p = fakeProps();
const point = fakePoint();
point.body.id = 1;
p.findPoint = () => point;
const wrapper = shallow(<EditWeed {...p} />);
wrapper.find(DesignerPanelHeader).simulate("back");
expect(p.dispatch).toHaveBeenCalledWith({
type: Actions.TOGGLE_HOVERED_POINT, payload: undefined
});
});
});
describe("mapStateToProps()", () => {

View File

@ -24,6 +24,7 @@ import { parseIntInput } from "../../util";
import { t } from "../../i18next_wrapper";
import { Panel } from "../panel_header";
import { getPathArray } from "../../history";
import { ListItem } from "./plant_panel";
export function mapStateToProps(props: Everything): CreatePointsProps {
const { position } = props.bot.hardware.location_data;
@ -178,54 +179,59 @@ export class RawCreatePoints
this.cancel();
this.loadDefaultPoint();
}
PointName = () =>
<Row>
<Col xs={12}>
<label>{t("Name")}</label>
<BlurableInput
name="name"
type="text"
onCommit={this.updateValue("name")}
value={this.attr("name") || this.defaultName} />
</Col>
</Row>;
PointProperties = () => {
return <Row>
<Col xs={3}>
<label>{t("X")}</label>
<BlurableInput
name="cx"
type="number"
onCommit={this.updateValue("cx")}
value={this.attr("cx", this.props.deviceX)} />
</Col>
<Col xs={3}>
<label>{t("Y")}</label>
<BlurableInput
name="cy"
type="number"
onCommit={this.updateValue("cy")}
value={this.attr("cy", this.props.deviceY)} />
</Col>
<Col xs={3}>
<label>{t("radius")}</label>
<BlurableInput
name="r"
type="number"
onCommit={this.updateValue("r")}
value={this.attr("r")}
min={0} />
</Col>
<Col xs={3}>
<label>{t("color")}</label>
<ColorPicker
current={(this.attr("color") || this.defaultColor) as ResourceColor}
onChange={this.changeColor} />
</Col>
</Row>;
}
PointProperties = () =>
<ul>
<li>
<div>
<label>{t("Name")}</label>
<BlurableInput
name="name"
type="text"
onCommit={this.updateValue("name")}
value={this.attr("name") || this.defaultName} />
</div>
</li>
<ListItem name={t("Location")}>
<Row>
<Col xs={6}>
<label>{t("X (mm)")}</label>
<BlurableInput
name="cx"
type="number"
onCommit={this.updateValue("cx")}
value={this.attr("cx", this.props.deviceX)} />
</Col>
<Col xs={6}>
<label>{t("Y (mm)")}</label>
<BlurableInput
name="cy"
type="number"
onCommit={this.updateValue("cy")}
value={this.attr("cy", this.props.deviceY)} />
</Col>
</Row>
</ListItem>
<ListItem name={t("Size")}>
<Row>
<Col xs={6}>
<label>{t("radius")}</label>
<BlurableInput
name="r"
type="number"
onCommit={this.updateValue("r")}
value={this.attr("r")}
min={0} />
</Col>
</Row>
</ListItem>
<ListItem name={t("Color")}>
<Row>
<ColorPicker
current={(this.attr("color") || this.defaultColor) as ResourceColor}
onChange={this.changeColor} />
</Row>
</ListItem>
</ul>
PointActions = () =>
<Row>
@ -272,7 +278,6 @@ export class RawCreatePoints
backTo={`/app/designer/${this.panel}`}
description={panelDescription} />
<DesignerPanelContent panelName={"point-creation"}>
<this.PointName />
<this.PointProperties />
<this.PointActions />
{this.DeleteAllPoints(this.panel == "weeds" ? "weed" : "point")}

View File

@ -26,6 +26,13 @@ export interface EditPointPropertiesProps {
export const EditPointProperties = (props: EditPointPropertiesProps) =>
<ul>
<li>
<div>
<EditPointName
name={props.point.body.name}
updatePoint={props.updatePoint} />
</div>
</li>
<ListItem name={t("Location")}>
<EditPointLocation
location={{ x: props.point.body.x, y: props.point.body.y }}
@ -66,6 +73,22 @@ export const PointActions = ({ x, y, z, uuid, dispatch }: PointActionsProps) =>
</button>
</div>;
export interface EditPointNameProps {
updatePoint(update: Partial<TaggedGenericPointer["body"]>): void;
name: string;
}
export const EditPointName = (props: EditPointNameProps) =>
<Row>
<Col xs={12}>
<label>{t("Name")}</label>
<BlurableInput
type="text"
value={props.name}
onCommit={e => props.updatePoint({ name: e.currentTarget.value })} />
</Col>
</Row>;
export interface EditPointLocationProps {
updatePoint(update: Partial<TaggedGenericPointer["body"]>): void;
location: Record<"x" | "y", number>;

View File

@ -45,7 +45,7 @@ export class RawEditPoint extends React.Component<EditPointProps, {}> {
<DesignerPanelHeader
panelName={this.panelName}
panel={Panel.Points}
title={`${t("Edit")} ${point.body.name}`}
title={t("Edit point")}
backTo={this.backTo}
onBack={() => this.props.dispatch({
type: Actions.TOGGLE_HOVERED_POINT, payload: undefined

View File

@ -12,6 +12,7 @@ import { Panel } from "../panel_header";
import {
EditPointProperties, PointActions, updatePoint
} from "./point_edit_actions";
import { Actions } from "../../constants";
export interface EditWeedProps {
dispatch: Function;
@ -44,8 +45,11 @@ export class RawEditWeed extends React.Component<EditWeedProps, {}> {
<DesignerPanelHeader
panelName={this.panelName}
panel={Panel.Weeds}
title={`${t("Edit")} ${point.body.name}`}
backTo={this.backTo}>
title={t("Edit weed")}
backTo={this.backTo}
onBack={() => this.props.dispatch({
type: Actions.TOGGLE_HOVERED_POINT, payload: undefined
})}>
</DesignerPanelHeader>
<DesignerPanelContent panelName={this.panelName}>
<EditPointProperties point={point}

View File

@ -87,7 +87,7 @@ export class RawEditGarden extends React.Component<EditGardenProps, {}> {
{savedGarden
? <div>
<Row>
<label>{t("Garden name")}</label>
<label>{t("name")}</label>
<BlurableInput
value={savedGarden.body.name || ""}
onCommit={e => {

View File

@ -13,7 +13,7 @@ export const GardenInfo = (props: SavedGardenInfoProps) => {
return <div className="saved-garden-info"
onClick={() => dispatch(openSavedGarden(savedGarden.uuid))}>
<Col>
<label>{savedGarden.body.name}</label>
<span>{savedGarden.body.name}</span>
<p>{props.plantTemplateCount} {t("plants")}</p>
</Col>
</div>;
@ -21,8 +21,8 @@ export const GardenInfo = (props: SavedGardenInfoProps) => {
/** Info and actions for a single SavedGarden. */
const SavedGardenItem = (props: SavedGardenItemProps) => {
return <div
className={`saved-garden-row ${props.gardenIsOpen ? "selected" : ""}`}>
return <div className={
`saved-garden-search-item ${props.gardenIsOpen ? "selected" : ""}`}>
<GardenInfo
savedGarden={props.savedGarden}
plantTemplateCount={props.plantTemplateCount}

View File

@ -37,7 +37,7 @@ export class GardenSnapshot
render() {
return <div className="garden-snapshot">
<label>{t("new garden name")}</label>
<label>{t("name")}</label>
<input
onChange={e => this.setState({ name: e.currentTarget.value })}
value={this.state.name} />

View File

@ -103,6 +103,7 @@ namespace :api do
end
end
RELEASES_URL = "https://api.github.com/repos/farmbot/farmbot_os/releases"
VERSION = "tag_name"
TIMESTAMP = "created_at"
PRERELEASE = "prerelease"
@ -116,10 +117,9 @@ namespace :api do
# 60 days is the current policy.
cutoff = 60.days.ago
# Download release data from github
stringio = open("https://api.github.com/repos/farmbot/farmbot_os/releases")
string = stringio.read
data = JSON
.parse(string)
string_page_1 = open("#{RELEASES_URL}?per_page=100&page=1").read
string_page_2 = open("#{RELEASES_URL}?per_page=100&page=2").read
data = JSON.parse(string_page_1).push(*JSON.parse(string_page_2))
.map { |x| x.slice(VERSION, TIMESTAMP, PRERELEASE) } # Only grab keys that matter
.reject { |x| x.fetch(VERSION).include?("-") } # Remove RC/Beta releases
.reject { |x| x.fetch(PRERELEASE) } # Remove pre-releases

View File

@ -33,7 +33,7 @@
"@types/lodash": "4.14.149",
"@types/markdown-it": "0.0.9",
"@types/moxios": "0.4.9",
"@types/node": "12.12.9",
"@types/node": "12.12.11",
"@types/promise-timeout": "1.3.0",
"@types/react": "16.9.11",
"@types/react-color": "3.0.1",
@ -69,7 +69,7 @@
"redux": "4.0.4",
"redux-immutable-state-invariant": "2.1.0",
"redux-thunk": "2.3.0",
"sass": "1.23.6",
"sass": "1.23.7",
"sass-lint": "1.13.1",
"takeme": "0.11.3",
"ts-jest": "24.1.0",