diff --git a/frontend/controls/controls.tsx b/frontend/controls/controls.tsx index 5195c58ba..5149af504 100644 --- a/frontend/controls/controls.tsx +++ b/frontend/controls/controls.tsx @@ -10,6 +10,7 @@ import { Move } from "./move/move"; import { BooleanSetting } from "../session_keys"; import { SensorReadings } from "./sensor_readings/sensor_readings"; import { isBotOnline } from "../devices/must_be_online"; +import { hasSensors } from "../devices/components/firmware_hardware_support"; /** Controls page. */ export class RawControls extends React.Component { @@ -24,7 +25,8 @@ export class RawControls extends React.Component { } get hideSensors() { - return this.props.getWebAppConfigVal(BooleanSetting.hide_sensors); + return this.props.getWebAppConfigVal(BooleanSetting.hide_sensors) + || !hasSensors(this.props.firmwareHardware); } move = () => { - {!isExpressBoard(props.firmwareHardware) && + {hasEncoders(props.firmwareHardware) && getValue(BooleanSetting.scaled_encoders) && } - {!isExpressBoard(props.firmwareHardware) && + {hasEncoders(props.firmwareHardware) && getValue(BooleanSetting.raw_encoders) && @@ -36,7 +36,7 @@ export const MoveWidgetSettingsMenu = ( - {!isExpressBoard(firmwareHardware) && + {hasEncoders(firmwareHardware) &&

{t("Display Encoder Data")}

", () => { clickButton(wrapper, 3, "stock"); expect(p.dispatch).toHaveBeenCalledTimes(expectedAdds); }); + + it("hides stock button", () => { + const p = fakeProps(); + p.firmwareHardware = "none"; + const wrapper = mount(); + wrapper.setState({ isEditing: true }); + const btn = wrapper.find("button").at(3); + expect(btn.text().toLowerCase()).toContain("stock"); + expect(btn.props().hidden).toBeTruthy(); + }); }); diff --git a/frontend/controls/peripherals/index.tsx b/frontend/controls/peripherals/index.tsx index 69decd905..de5e6eba3 100644 --- a/frontend/controls/peripherals/index.tsx +++ b/frontend/controls/peripherals/index.tsx @@ -108,7 +108,7 @@ export class Peripherals - {!isExpressBoard(this.props.firmwareHardware) && - } + {this.showPins()} diff --git a/frontend/css/farm_designer/farm_designer_panels.scss b/frontend/css/farm_designer/farm_designer_panels.scss index 6c5a5614d..e67e5ac60 100644 --- a/frontend/css/farm_designer/farm_designer_panels.scss +++ b/frontend/css/farm_designer/farm_designer_panels.scss @@ -958,3 +958,10 @@ margin-right: 1.5rem; &:hover { color: $white; } } + +.desktop-hide { + display: none !important; + @media screen and (max-width: 1075px) { + display: block !important; + } +} diff --git a/frontend/css/global.scss b/frontend/css/global.scss index e8530d2c6..9b63e725d 100644 --- a/frontend/css/global.scss +++ b/frontend/css/global.scss @@ -407,6 +407,18 @@ a { } } +.load-progress-bar-wrapper { + position: absolute; + top: 3.2rem; + bottom: 0; + right: 0; + width: 100%; + height: 1px; + .load-progress-bar { + height: 100%; + } +} + .firmware-setting-export-menu { button { margin-bottom: 1rem; @@ -1654,3 +1666,9 @@ textarea:focus { background-color: transparent; box-shadow: none; } + +.read-only-icon { + margin: 9px 0px 0px 9px; + float: right; + box-sizing: inherit; +} diff --git a/frontend/css/sequences.scss b/frontend/css/sequences.scss index be3cdff30..83472c0e4 100644 --- a/frontend/css/sequences.scss +++ b/frontend/css/sequences.scss @@ -322,6 +322,9 @@ border-left: 4px solid transparent; &.active { border-left: 4px solid $dark_gray; + p { + font-weight: bold; + } } .fa-chevron-down, .fa-chevron-right { position: absolute; @@ -330,11 +333,11 @@ font-size: 1.1rem; } .folder-settings-icon, - .fa-bars { + .fa-arrows-v { position: absolute; right: 0; } - .fa-bars, .fa-ellipsis-v { + .fa-arrows-v, .fa-ellipsis-v { display: none; } .fa-ellipsis-v { @@ -342,8 +345,14 @@ display: block; } } + @media screen and (max-width: 450px) { + .fa-arrows-v, .fa-ellipsis-v { + display: block; + margin-right: 0.5rem; + } + } &:hover { - .fa-bars, .fa-ellipsis-v { + .fa-arrows-v, .fa-ellipsis-v { display: block; } } @@ -367,7 +376,7 @@ white-space: nowrap; text-overflow: ellipsis; font-size: 1.2rem; - font-weight: bold; + font-weight: normal; width: 75%; padding: 0.5rem; padding-left: 0; diff --git a/frontend/devices/components/__tests__/hardware_settings_test.tsx b/frontend/devices/components/__tests__/hardware_settings_test.tsx index 427070cce..840ada969 100644 --- a/frontend/devices/components/__tests__/hardware_settings_test.tsx +++ b/frontend/devices/components/__tests__/hardware_settings_test.tsx @@ -12,6 +12,8 @@ import { clickButton } from "../../../__test_support__/helpers"; import { buildResourceIndex } from "../../../__test_support__/resource_index_builder"; +import type { FirmwareConfig } from "farmbot/dist/resources/configs/firmware"; +import { Color } from "../../../ui"; describe("", () => { const fakeProps = (): HardwareSettingsProps => ({ @@ -68,4 +70,41 @@ describe("", () => { const wrapper = shallow(); expect(wrapper.html()).toContain("fa-download"); }); + + it("shows setting load progress", () => { + type ConsistencyLookup = Record; + const consistent: Partial = + ({ id: false, encoder_invert_x: true, encoder_enabled_y: false }); + const consistencyLookup = consistent as ConsistencyLookup; + const p = fakeProps(); + const fakeConfig: Partial = + ({ id: 0, encoder_invert_x: 1, encoder_enabled_y: 0 }); + p.firmwareConfig = fakeConfig as FirmwareConfig; + p.sourceFwConfig = x => + ({ value: p.firmwareConfig?.[x], consistent: consistencyLookup[x] }); + const wrapper = mount(); + const barStyle = wrapper.find(".load-progress-bar").props().style; + expect(barStyle?.background).toEqual(Color.white); + expect(barStyle?.width).toEqual("50%"); + }); + + it("shows setting load progress: 0%", () => { + const p = fakeProps(); + p.firmwareConfig = fakeFirmwareConfig().body; + p.sourceFwConfig = () => ({ value: 0, consistent: false }); + const wrapper = mount(); + const barStyle = wrapper.find(".load-progress-bar").props().style; + expect(barStyle?.width).toEqual("0%"); + expect(barStyle?.background).toEqual(Color.darkGray); + }); + + it("shows setting load progress: 100%", () => { + const p = fakeProps(); + p.firmwareConfig = fakeFirmwareConfig().body; + p.sourceFwConfig = () => ({ value: 0, consistent: true }); + const wrapper = mount(); + const barStyle = wrapper.find(".load-progress-bar").props().style; + expect(barStyle?.width).toEqual("100%"); + expect(barStyle?.background).toEqual(Color.darkGray); + }); }); diff --git a/frontend/devices/components/firmware_hardware_support.ts b/frontend/devices/components/firmware_hardware_support.ts index 71756e221..d3c4d95e3 100644 --- a/frontend/devices/components/firmware_hardware_support.ts +++ b/frontend/devices/components/firmware_hardware_support.ts @@ -16,15 +16,31 @@ export const getFwHardwareValue = return isFwHardwareValue(value) ? value : undefined; }; -const TMC_BOARDS = ["express_k10", "farmduino_k15"]; +const NO_BUTTONS = ["arduino", "farmduino", "none"]; const EXPRESS_BOARDS = ["express_k10"]; +const NO_SENSORS = [...EXPRESS_BOARDS]; +const NO_ENCODERS = [...EXPRESS_BOARDS]; +const NO_TOOLS = [...EXPRESS_BOARDS]; +const NO_TMC = ["arduino", "farmduino", "farmduino_k14"]; export const isTMCBoard = (firmwareHardware: FirmwareHardware | undefined) => - !!(firmwareHardware && TMC_BOARDS.includes(firmwareHardware)); + !firmwareHardware || !NO_TMC.includes(firmwareHardware); export const isExpressBoard = (firmwareHardware: FirmwareHardware | undefined) => !!(firmwareHardware && EXPRESS_BOARDS.includes(firmwareHardware)); +export const hasButtons = (firmwareHardware: FirmwareHardware | undefined) => + !firmwareHardware || !NO_BUTTONS.includes(firmwareHardware); + +export const hasEncoders = (firmwareHardware: FirmwareHardware | undefined) => + !firmwareHardware || !NO_ENCODERS.includes(firmwareHardware); + +export const hasSensors = (firmwareHardware: FirmwareHardware | undefined) => + !firmwareHardware || !NO_SENSORS.includes(firmwareHardware); + +export const hasUTM = (firmwareHardware: FirmwareHardware | undefined) => + !firmwareHardware || !NO_TOOLS.includes(firmwareHardware); + export const getBoardIdentifier = (firmwareVersion: string | undefined): string => firmwareVersion ? firmwareVersion.split(".")[3] : "undefined"; diff --git a/frontend/devices/components/hardware_settings.tsx b/frontend/devices/components/hardware_settings.tsx index 1f12f68fe..f4a2c6612 100644 --- a/frontend/devices/components/hardware_settings.tsx +++ b/frontend/devices/components/hardware_settings.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { MCUFactoryReset, bulkToggleControlPanel } from "../actions"; -import { Widget, WidgetHeader, WidgetBody } from "../../ui/index"; -import { HardwareSettingsProps } from "../interfaces"; +import { Widget, WidgetHeader, WidgetBody, Color } from "../../ui/index"; +import { HardwareSettingsProps, SourceFwConfig } from "../interfaces"; import { isBotOnline } from "../must_be_online"; import { ToolTips } from "../../constants"; import { DangerZone } from "./hardware_settings/danger_zone"; @@ -19,6 +19,8 @@ import { t } from "../../i18next_wrapper"; import { PinBindings } from "./hardware_settings/pin_bindings"; import { ErrorHandling } from "./hardware_settings/error_handling"; import { maybeOpenPanel } from "./maybe_highlight"; +import type { FirmwareConfig } from "farmbot/dist/resources/configs/firmware"; +import type { McuParamName } from "farmbot"; export class HardwareSettings extends React.Component { @@ -36,7 +38,10 @@ export class HardwareSettings extends const botDisconnected = !isBotOnline(sync_status, botToMqttStatus); const commonProps = { dispatch, controlPanelState }; return - + + +
; diff --git a/frontend/farm_designer/__tests__/plant_test.ts b/frontend/farm_designer/__tests__/plant_test.ts new file mode 100644 index 000000000..12bb2eac5 --- /dev/null +++ b/frontend/farm_designer/__tests__/plant_test.ts @@ -0,0 +1,19 @@ +import { Plant } from "../plant"; + +describe("Plant()", () => { + it("returns defaults", () => { + expect(Plant({})).toEqual({ + created_at: "", + id: undefined, + meta: {}, + name: "Untitled Plant", + openfarm_slug: "not-set", + plant_stage: "planned", + pointer_type: "Plant", + radius: 25, + x: 0, + y: 0, + z: 0, + }); + }); +}); diff --git a/frontend/farm_designer/__tests__/reducer_test.ts b/frontend/farm_designer/__tests__/reducer_test.ts index 375b6106c..432e9aa14 100644 --- a/frontend/farm_designer/__tests__/reducer_test.ts +++ b/frontend/farm_designer/__tests__/reducer_test.ts @@ -94,6 +94,19 @@ describe("designer reducer", () => { }); }); + it("uses current point color", () => { + const action: ReduxAction = { + type: Actions.SET_CURRENT_POINT_DATA, + payload: { cx: 10, cy: 20, r: 30 } + }; + const state = oldState(); + state.currentPoint = { cx: 0, cy: 0, r: 0, color: "red" }; + const newState = designer(state, action); + expect(newState.currentPoint).toEqual({ + cx: 10, cy: 20, r: 30, color: "red" + }); + }); + it("sets opened saved garden", () => { const payload = "savedGardenUuid"; const action: ReduxAction = { diff --git a/frontend/farm_designer/designer_panel.tsx b/frontend/farm_designer/designer_panel.tsx index 3fc41850d..dd369abf5 100644 --- a/frontend/farm_designer/designer_panel.tsx +++ b/frontend/farm_designer/designer_panel.tsx @@ -90,7 +90,7 @@ export const DesignerPanelTop = (props: DesignerPanelTopProps) => {
{!props.noIcon && - } + } {props.children} diff --git a/frontend/farm_designer/farm_events/edit_farm_event.tsx b/frontend/farm_designer/farm_events/edit_farm_event.tsx index 5a86238d3..a89af9150 100644 --- a/frontend/farm_designer/farm_events/edit_farm_event.tsx +++ b/frontend/farm_designer/farm_events/edit_farm_event.tsx @@ -23,7 +23,7 @@ export class RawEditFarmEvent extends React.Component + title={t("Edit event")} /> executableOptions={this.props.executableOptions} dispatch={this.props.dispatch} findExecutable={this.props.findExecutable} - title={t("Edit Event")} + title={t("Edit event")} deleteBtn={true} timeSettings={this.props.timeSettings} autoSyncEnabled={this.props.autoSyncEnabled} diff --git a/frontend/farm_designer/farm_events/edit_fe_form.tsx b/frontend/farm_designer/farm_events/edit_fe_form.tsx index d2bb3d66b..681ef3a91 100644 --- a/frontend/farm_designer/farm_events/edit_fe_form.tsx +++ b/frontend/farm_designer/farm_events/edit_fe_form.tsx @@ -41,6 +41,7 @@ import { } from "../../sequences/locals_list/locals_list_support"; import { t } from "../../i18next_wrapper"; import { TimeSettings } from "../../interfaces"; +import { ErrorBoundary } from "../../error_boundary"; export const NEVER: TimeUnit = "never"; /** Separate each of the form fields into their own interface. Recombined later @@ -360,19 +361,24 @@ export class EditFEForm extends React.Component { render() { const { farmEvent } = this.props; return
- this.commitViewModel()}> - - + + this.commitViewModel()}> + + + + +
{ noFolder: (localMetaAttributes[PARENTLESS] || {}).sequences || [] }; const index = folders.map(setDefaultParentId).reduce(addToIndex, emptyIndex); - const childrenOf = (i: number) => sortBy(index[i] || [], (x) => x.name.toLowerCase()); + const childrenOf = (i: number) => + sortBy(index[i] || [], (x) => x.name.toLowerCase()); const terminal = (x: FolderNode): FolderNodeTerminal => ({ ...x, kind: "terminal", content: (localMetaAttributes[x.id] || {}).sequences || [], - open: true, + open: false, editing: false, // children: [], ...(localMetaAttributes[x.id] || {}) @@ -55,7 +56,7 @@ export const ingest: IngestFn = ({ folders, localMetaAttributes }) => { const medial = (x: FolderNode): FolderNodeMedial => ({ ...x, kind: "medial", - open: true, + open: false, editing: false, children: childrenOf(x.id).map(terminal), content: (localMetaAttributes[x.id] || {}).sequences || [], @@ -67,7 +68,7 @@ export const ingest: IngestFn = ({ folders, localMetaAttributes }) => { return output.folders.push({ ...root, kind: "initial", - open: true, + open: false, editing: false, children, content: (localMetaAttributes[root.id] || {}).sequences || [], diff --git a/frontend/help/tours.ts b/frontend/help/tours.ts index 26f78eda6..505f9a626 100644 --- a/frontend/help/tours.ts +++ b/frontend/help/tours.ts @@ -7,7 +7,7 @@ import { selectAllTools } from "../resources/selectors"; import { store } from "../redux/store"; import { getFbosConfig } from "../resources/getters"; import { - isExpressBoard, getFwHardwareValue + getFwHardwareValue, hasUTM } from "../devices/components/firmware_hardware_support"; export enum Tours { @@ -25,26 +25,26 @@ export const tourNames = () => [ const hasTools = () => selectAllTools(store.getState().resources.index).length > 0; -const isExpress = () => - isExpressBoard(getFwHardwareValue( +const noUTM = () => + !hasUTM(getFwHardwareValue( getFbosConfig(store.getState().resources.index))); const toolsStep = () => hasTools() ? [{ target: ".tools", - content: isExpress() + content: noUTM() ? t(TourContent.ADD_SEED_CONTAINERS) : t(TourContent.ADD_TOOLS), - title: isExpress() + title: noUTM() ? t("Add seed containers") : t("Add tools and seed containers"), }] : [{ target: ".tools", - content: isExpress() + content: noUTM() ? t(TourContent.ADD_SEED_CONTAINERS_AND_SLOTS) : t(TourContent.ADD_TOOLS_AND_SLOTS), - title: isExpress() + title: noUTM() ? t("Add seed containers and slots") : t("Add tools and slots"), }]; diff --git a/frontend/logs/__tests__/index_test.tsx b/frontend/logs/__tests__/index_test.tsx index 9d68e66af..66c4d5498 100644 --- a/frontend/logs/__tests__/index_test.tsx +++ b/frontend/logs/__tests__/index_test.tsx @@ -1,7 +1,7 @@ const mockStorj: Dictionary = {}; import * as React from "react"; -import { mount } from "enzyme"; +import { mount, shallow } from "enzyme"; import { RawLogs as Logs } from "../index"; import { ToolTips } from "../../constants"; import { TaggedLog, Dictionary } from "farmbot"; @@ -172,4 +172,12 @@ describe("", () => { wrapper.setState({ markdown: false }); expect(wrapper.html()).not.toContain("message"); }); + + it("changes search term", () => { + const p = fakeProps(); + const wrapper = shallow(); + wrapper.find("input").first().simulate("change", + { currentTarget: { value: "one" } }); + expect(wrapper.state().searchTerm).toEqual("one"); + }); }); diff --git a/frontend/logs/components/__tests__/filter_menu_test.tsx b/frontend/logs/components/__tests__/filter_menu_test.tsx index 968fcd1b4..e885bdccb 100644 --- a/frontend/logs/components/__tests__/filter_menu_test.tsx +++ b/frontend/logs/components/__tests__/filter_menu_test.tsx @@ -9,7 +9,8 @@ const logTypes = MESSAGE_TYPES; describe("", () => { const fakeState: LogsState = { - autoscroll: true, markdown: false, success: 1, busy: 1, warn: 1, + autoscroll: true, markdown: false, searchTerm: "", + success: 1, busy: 1, warn: 1, error: 1, info: 1, fun: 1, debug: 1, assertion: 1, }; @@ -24,7 +25,7 @@ describe("", () => { const wrapper = mount(); logTypes.filter(x => x !== "assertion").map(string => expect(wrapper.text().toLowerCase()).toContain(string.toLowerCase())); - ["autoscroll", "markdown"].map(string => + ["autoscroll", "markdown", "searchTerm"].map(string => expect(wrapper.text().toLowerCase()).not.toContain(string)); }); @@ -34,7 +35,7 @@ describe("", () => { const wrapper = mount(); logTypes.map(string => expect(wrapper.text().toLowerCase()).toContain(string.toLowerCase())); - ["autoscroll", "markdown"].map(string => + ["autoscroll", "markdown", "searchTerm"].map(string => expect(wrapper.text().toLowerCase()).not.toContain(string)); }); diff --git a/frontend/logs/components/__tests__/logs_table_test.tsx b/frontend/logs/components/__tests__/logs_table_test.tsx new file mode 100644 index 000000000..fa5eff31a --- /dev/null +++ b/frontend/logs/components/__tests__/logs_table_test.tsx @@ -0,0 +1,20 @@ +import { fakeTimeSettings } from "../../../__test_support__/fake_time_settings"; +import { bySearchTerm } from "../logs_table"; +import { fakeLog } from "../../../__test_support__/fake_state/resources"; + +describe("bySearchTerm()", () => { + it("includes log", () => { + const log = fakeLog(); + log.body.message = "include this log"; + const result = bySearchTerm("include", fakeTimeSettings())(log); + expect(result).toBeTruthy(); + }); + + it("excludes log", () => { + const log = fakeLog(); + log.body.created_at = undefined; + log.body.message = "exclude this log"; + const result = bySearchTerm("include", fakeTimeSettings())(log); + expect(result).toBeFalsy(); + }); +}); diff --git a/frontend/logs/components/filter_menu.tsx b/frontend/logs/components/filter_menu.tsx index 12e8c6cd9..74cafce74 100644 --- a/frontend/logs/components/filter_menu.tsx +++ b/frontend/logs/components/filter_menu.tsx @@ -28,7 +28,7 @@ const menuSort = (a: string, b: string) => export const filterStateKeys = (state: LogsState, shouldDisplay: ShouldDisplay) => Object.keys(state) - .filter(key => !["autoscroll", "markdown"].includes(key)) + .filter(key => !["autoscroll", "markdown", "searchTerm"].includes(key)) .filter(key => shouldDisplay(Feature.assertion_block) || key !== "assertion"); diff --git a/frontend/logs/components/logs_table.tsx b/frontend/logs/components/logs_table.tsx index 71f9076fe..14277cd72 100644 --- a/frontend/logs/components/logs_table.tsx +++ b/frontend/logs/components/logs_table.tsx @@ -3,7 +3,7 @@ import { TaggedLog, ALLOWED_MESSAGE_TYPES } from "farmbot"; import { LogsState, LogsTableProps, Filters } from "../interfaces"; import { formatLogTime } from "../index"; import { Classes } from "@blueprintjs/core"; -import { isNumber, startCase } from "lodash"; +import { isNumber, startCase, some } from "lodash"; import { t } from "../../i18next_wrapper"; import { TimeSettings } from "../../interfaces"; import { UUID } from "../../resources/interfaces"; @@ -81,6 +81,7 @@ export const LogsTable = (props: LogsTableProps) => { {filterByVerbosity(getFilterLevel(props.state), props.logs) + .filter(bySearchTerm(props.state.searchTerm, props.timeSettings)) .map((log: TaggedLog) => + (log: TaggedLog) => { + const { x, y, z, created_at, message, type } = log.body; + const displayedTime = formatLogTime(created_at || NaN, timeSettings); + const displayedPosition = xyzTableEntry(x, y, z); + const lowerSearchTerm = searchTerm.toLowerCase(); + return some([message, type] + .map(string => string.toLowerCase().includes(lowerSearchTerm)) + .concat([ + displayedTime.toLowerCase().includes(lowerSearchTerm), + displayedPosition.includes(lowerSearchTerm), + ])); + }; diff --git a/frontend/logs/index.tsx b/frontend/logs/index.tsx index cb7b8ffd2..a6a5e13ed 100644 --- a/frontend/logs/index.tsx +++ b/frontend/logs/index.tsx @@ -49,6 +49,7 @@ export class RawLogs extends React.Component> { fun: this.initialize(NumericSetting.fun_log, 1), debug: this.initialize(NumericSetting.debug_log, 1), assertion: this.initialize(NumericSetting.assertion_log, 1), + searchTerm: "", markdown: true, }; @@ -85,13 +86,13 @@ export class RawLogs extends React.Component> { const filterBtnColor = this.filterActive ? "green" : "gray"; return - +

{t("Logs")}

- +
@@ -121,6 +122,19 @@ export class RawLogs extends React.Component> {
+ + +
+
+ + + this.setState({ searchTerm: e.currentTarget.value })} + placeholder={t("Search logs...")} /> +
+
+ +
; export interface LogsState extends Filters { autoscroll: boolean; + searchTerm: string; markdown: boolean; } diff --git a/frontend/nav/additional_menu.tsx b/frontend/nav/additional_menu.tsx index 4e0b1290f..f9e627495 100644 --- a/frontend/nav/additional_menu.tsx +++ b/frontend/nav/additional_menu.tsx @@ -9,23 +9,23 @@ export const AdditionalMenu = (props: AccountMenuProps) => { return
- + {t("Account Settings")}
- + {t("Logs")}
- + {t("Help")} diff --git a/frontend/read_only_mode/index.tsx b/frontend/read_only_mode/index.tsx index 67ca1d555..1166ded2b 100644 --- a/frontend/read_only_mode/index.tsx +++ b/frontend/read_only_mode/index.tsx @@ -3,6 +3,7 @@ import { store } from "../redux/store"; import { warning } from "../toast/toast"; import React from "react"; import { appIsReadonly } from "./app_is_read_only"; +import { t } from "../i18next_wrapper"; export const readOnlyInterceptor = (config: AxiosRequestConfig) => { const method = (config.method || "get").toLowerCase(); @@ -10,7 +11,7 @@ export const readOnlyInterceptor = (config: AxiosRequestConfig) => { if (relevant && appIsReadonly(store.getState().resources.index)) { if (!(config.url || "").includes("web_app_config")) { - warning("Refusing to modify data in read-only mode"); + warning(t("Refusing to modify data in read-only mode")); return Promise.reject(config); } } @@ -18,19 +19,12 @@ export const readOnlyInterceptor = (config: AxiosRequestConfig) => { return Promise.resolve(config); }; -const MOVE_ME_ELSEWHERE: React.CSSProperties = { - float: "right", - boxSizing: "inherit", - margin: "9px 0px 0px 9px" -}; - export const ReadOnlyIcon = (p: { locked: boolean }) => { if (p.locked) { - return
- - + return
+ +
; - } else { return
; } diff --git a/frontend/regimens/index.tsx b/frontend/regimens/index.tsx index 502a8c086..14b2f2e72 100644 --- a/frontend/regimens/index.tsx +++ b/frontend/regimens/index.tsx @@ -42,8 +42,7 @@ export class RawRegimens extends React.Component { + title={t("Regimens")}>
- + + placeholder={t("Search regimens...")} />
diff --git a/frontend/resources/selectors_by_id.ts b/frontend/resources/selectors_by_id.ts index 95fe95624..dc00eb0fe 100644 --- a/frontend/resources/selectors_by_id.ts +++ b/frontend/resources/selectors_by_id.ts @@ -11,8 +11,6 @@ import { isTaggedGenericPointer, isTaggedSavedGarden, isTaggedFolder, - isTaggedPoint, - isTaggedPointGroup, } from "./tagged_resources"; import { ResourceName, @@ -127,20 +125,6 @@ export function maybeFindGenericPointerById(index: ResourceIndex, id: number) { if (resource && isTaggedGenericPointer(resource)) { return resource; } } -/** Unlike other findById methods, this one allows undefined (missed) values */ -export function maybeFindPointById(index: ResourceIndex, id: number) { - const uuid = index.byKindAndId[joinKindAndId("Point", id)]; - const resource = index.references[uuid || "nope"]; - if (resource && isTaggedPoint(resource)) { return resource; } -} - -/** Unlike other findById methods, this one allows undefined (missed) values */ -export function maybeFindGroupById(index: ResourceIndex, id: number) { - const uuid = index.byKindAndId[joinKindAndId("PointGroup", id)]; - const resource = index.references[uuid || "nope"]; - if (resource && isTaggedPointGroup(resource)) { return resource; } -} - /** Unlike other findById methods, this one allows undefined (missed) values */ export function maybeFindSavedGardenById(index: ResourceIndex, id: number) { const uuid = index.byKindAndId[joinKindAndId("SavedGarden", id)]; diff --git a/frontend/sequences/step_tiles/tile_if/index.tsx b/frontend/sequences/step_tiles/tile_if/index.tsx index 393abb6d0..ddac3eadb 100644 --- a/frontend/sequences/step_tiles/tile_if/index.tsx +++ b/frontend/sequences/step_tiles/tile_if/index.tsx @@ -100,7 +100,7 @@ export function InnerIf(props: IfParams) { confirmStepDeletion={confirmStepDeletion}> {recursive && - +  {t("Recursive condition.")} } diff --git a/frontend/ui/back_arrow.tsx b/frontend/ui/back_arrow.tsx index f317111bf..b386d1934 100644 --- a/frontend/ui/back_arrow.tsx +++ b/frontend/ui/back_arrow.tsx @@ -10,6 +10,6 @@ export function BackArrow(props: BackArrowProps) { }; return - + ; }