Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(app): add any found hardcoded copy to i18n for translation #17095

Merged
merged 3 commits into from
Dec 16, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
refactor(app): add any found hardcoded copy to i18n for translation
fix EXEC-879, 878
smb2268 committed Dec 12, 2024
commit b851c3a744c63bd553d004b6f8ea54243b8c85d4
22 changes: 12 additions & 10 deletions app/src/App/DesktopApp.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useState, Fragment } from 'react'
import { useTranslation } from 'react-i18next'
import { Navigate, Route, Routes, useMatch } from 'react-router-dom'
import { ErrorBoundary } from 'react-error-boundary'

@@ -43,6 +44,7 @@ import { ReactQueryDevtools } from './tools'
import type { RouteProps } from './types'

export const DesktopApp = (): JSX.Element => {
const { t } = useTranslation('top_navigation')
useSoftwareUpdatePoll()
const [
isEmergencyStopModalDismissed,
@@ -52,55 +54,55 @@ export const DesktopApp = (): JSX.Element => {
const desktopRoutes: RouteProps[] = [
{
Component: ProtocolsLanding,
name: 'protocols',
name: t('protocols'),
navLinkTo: '/protocols',
path: '/protocols',
},
{
Component: ProtocolDetails,
name: 'Protocol Details',
name: t('protocol_details'),
path: '/protocols/:protocolKey',
},
{
Component: ProtocolTimeline,
name: 'Protocol Timeline',
name: t('protocol_timeline'),
path: '/protocols/:protocolKey/timeline',
},
{
Component: Labware,
name: 'labware',
name: t('labware'),
navLinkTo: '/labware',
path: '/labware',
},
{
Component: DevicesLanding,
name: 'devices',
name: t('devices'),
navLinkTo: '/devices',
path: '/devices',
},
{
Component: DeviceDetails,
name: 'Device',
name: t('device'),
path: '/devices/:robotName',
},
{
Component: RobotSettings,
name: 'Robot Settings',
name: t('robot_settings'),
path: '/devices/:robotName/robot-settings/:robotSettingsTab?',
},
{
Component: CalibrationDashboard,
name: 'Calibration Dashboard',
name: t('calibration_dashboard'),
path: '/devices/:robotName/robot-settings/calibration/dashboard',
},
{
Component: ProtocolRunDetails,
name: 'Run Details',
name: t('run_details'),
path: '/devices/:robotName/protocol-runs/:runId/:protocolRunDetailsTab?',
},
{
Component: AppSettings,
name: 'App Settings',
name: t('app_settings'),
path: '/app-settings/:appSettingsTab?',
},
]
5 changes: 1 addition & 4 deletions app/src/App/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { NavLink, useNavigate } from 'react-router-dom'
import styled from 'styled-components'
import debounce from 'lodash/debounce'
@@ -111,8 +110,6 @@ const LogoImg = styled('img')`
`

export function Navbar({ routes }: { routes: RouteProps[] }): JSX.Element {
const { t } = useTranslation('top_navigation')

const navigate = useNavigate()
const navRoutes = routes.filter(
({ navLinkTo }: RouteProps) => navLinkTo != null
@@ -151,7 +148,7 @@ export function Navbar({ routes }: { routes: RouteProps[] }): JSX.Element {
as="h3"
margin={`${SPACING.spacing8} 0 ${SPACING.spacing8} ${SPACING.spacing12}`}
>
{t(name)}
{name}
</LegacyStyledText>
</NavbarLink>
))}
7 changes: 7 additions & 0 deletions app/src/assets/localization/en/app_settings.json
Original file line number Diff line number Diff line change
@@ -36,7 +36,9 @@
"connect_ip_link": "Learn more about connecting a robot manually",
"discovery_timeout": "Discovery timed out.",
"dont_change": "Don’t change",
"dont_remind_me": "Don't remind me again",
"download_update": "Downloading update...",
"driver_out_of_date": "Realtek USB-to-Ethernet Driver Update Available",
"enable_dev_tools": "Developer Tools",
"enable_dev_tools_description": "Enabling this setting opens Developer Tools on app launch, enables additional logging and gives access to feature flags.",
"error_boundary_desktop_app_description": "You need to reload the app. Contact support with the following error message:",
@@ -45,6 +47,7 @@
"error_recovery_mode_description": "Pause on protocol errors instead of canceling the run.",
"feature_flags": "Feature Flags",
"general": "General",
"get_update": "get update",
"heater_shaker_attach_description": "Display a reminder to attach the Heater-Shaker properly before running a test shake or using it in a protocol.",
"heater_shaker_attach_visible": "Confirm Heater-Shaker Module Attachment",
"how_to_restore": "How to Restore a Previous Software Version",
@@ -65,6 +68,7 @@
"ot2_advanced_settings": "OT-2 Advanced Settings",
"override_path": "override path",
"override_path_to_python": "Override Path to Python",
"please_update_driver": "Please update your computer's driver to ensure a reliable connection to your OT-2.",
"prevent_robot_caching": "Prevent Robot Caching",
"prevent_robot_caching_description": "The app <strong>will immediately clear unavailable robots</strong> and will not remember unavailable robots while this is enabled. On networks with many robots, preventing caching may improve network performance at the expense of slower and less reliable robot discovery on app launch.",
"privacy": "Privacy",
@@ -93,6 +97,8 @@
"trash_bin": "Always use trash bin to calibrate",
"try_restarting_the_update": "Try restarting the update.",
"turn_off_updates": "Turn off software update notifications in App Settings.",
"u2e_driver_description": "The OT-2 uses this adapter for its USB connection to the Opentrons App.",
"u2e_driver_outdated_message": "There is an updated Realtek USB-to-Ethernet adapter driver available for your computer.",
"up_to_date": "Up to date",
"update_alerts": "Software Update Alerts",
"update_app_now": "Update app now",
@@ -112,5 +118,6 @@
"usb_to_ethernet_unknown_product": "Unknown Adapter",
"use_system_language": "Use system language",
"view_software_update": "View software update",
"view_adapter_info": "view adapter info",
"view_update": "View Update"
}
39 changes: 39 additions & 0 deletions app/src/assets/localization/en/device_settings.json
Original file line number Diff line number Diff line change
@@ -3,17 +3,20 @@
"about_calibration_description": "For the robot to move accurately and precisely, you need to calibrate it. Positional calibration happens in three parts: deck calibration, pipette offset calibration and tip length calibration.",
"about_calibration_description_ot3": "<block>For the robot to move accurately and precisely, you need to calibrate it. Pipette and gripper calibration is an automated process that uses a calibration probe or pin.</block><block>After calibration is complete, you can save the calibration data to your computer as a JSON file.</block>",
"about_calibration_title": "About Calibration",
"add_new": "Add new...",
"advanced": "Advanced",
"alpha_description": "Warning: alpha releases are feature-complete but may contain significant bugs.",
"alternative_security_types": "Alternative security types",
"app_change_in": "App Changes in {{version}}",
"apply_historic_offsets": "Apply Labware Offsets",
"are_you_sure_you_want_to_disconnect": "Are you sure you want to disconnect from {{ssid}}?",
"attach_a_pipette_before_calibrating": "Attach a pipette in order to perform calibration",
"authentication": "Authentication",
"boot_scripts": "Boot scripts",
"both": "Both",
"browse_file_system": "Browse file system",
"bug_fixes": "Bug Fixes",
"but_we_expected": "but we expected",
"calibrate_deck": "Calibrate deck",
"calibrate_deck_description": "For pre-2019 robots that do not have crosses etched on the deck.",
"calibrate_deck_to_dots": "Calibrate deck to dots",
@@ -28,8 +31,10 @@
"change_network": "Change network",
"characters_max": "17 characters max",
"check_for_updates": "Check for updates",
"check_to_verify_update": "Check your robot's settings page to verify whether or not the update was successful",
"checking_for_updates": "Checking for updates",
"choose": "Choose...",
"choose_a_network": "Choose a network...",
"choose_file": "Choose file",
"choose_network_type": "Choose network type",
"choose_reset_settings": "Choose reset settings",
@@ -56,7 +61,9 @@
"confirm_device_reset_heading": "Are you sure you want to reset your device?",
"connect": "Connect",
"connect_the_estop_to_continue": "Connect the E-stop to continue",
"connect_to_ssid": "Connect to {{ssid}}",
"connect_to_wifi_network": "Connect to Wi-Fi network",
"connect_to_wifi_network_failure": "Your robot was unable to connect to Wi-Fi network {{ssid}}",
"connect_via": "Connect via {{type}}",
"connect_via_usb_description_1": "1. Connect the USB A-to-B cable to the robot’s USB-B port.",
"connect_via_usb_description_2": "2. Connect the cable to an open USB port on your computer.",
@@ -65,6 +72,7 @@
"connected_to_ssid": "Connected to {{ssid}}",
"connected_via": "Connected via {{networkInterface}}",
"connecting_to": "Connecting to {{ssid}}...",
"connecting_to_wifi_network": "Connecting to Wi-Fi network {{ssid}}",
"connection_description_ethernet": "Connect to your lab's wired network.",
"connection_description_wifi": "Find a network in your lab or enter your own.",
"connection_to_robot_lost": "Connection to robot lost",
@@ -96,6 +104,7 @@
"display_sleep_settings": "Display Sleep Settings",
"do_not_turn_off": "This could take up to {{minutes}} minutes. Don't turn off the robot.",
"done": "Done",
"downgrade": "downgrade",
"download": "Download",
"download_calibration_data": "Download calibration logs",
"download_error": "Download error",
@@ -109,6 +118,7 @@
"enable_status_light_description": "Turn on or off the strip of color LEDs on the front of the robot.",
"engaged": "Engaged",
"enter_factory_password": "Enter factory password",
"enter_name_security_type": "Enter the network name and security type.",
"enter_network_name": "Enter network name",
"enter_password": "Enter password",
"estop": "E-stop",
@@ -127,6 +137,8 @@
"factory_resets_cannot_be_undone": "Factory resets cannot be undone.",
"failed_to_connect_to_ssid": "Failed to connect to {{ssid}}",
"feature_flags": "Feature Flags",
"field_is_required": "{{field}} is required",
"find_and_join_network": "Find and join a Wi-Fi network",
"finish_setup": "Finish setup",
"firmware_version": "Firmware Version",
"fully_calibrate_before_checking_health": "Fully calibrate your robot before checking calibration health",
@@ -154,6 +166,7 @@
"last_calibrated_label": "Last Calibrated",
"launch_jupyter_notebook": "Launch Jupyter Notebook",
"legacy_settings": "Legacy Settings",
"likely_incorrect_password": "Likely incorrect network password.",
"mac_address": "MAC Address",
"manage_oem_settings": "Manage OEM settings",
"minutes": "{{minute}} minutes",
@@ -171,7 +184,10 @@
"name_your_robot": "Name your robot",
"name_your_robot_description": "Don’t worry, you can always change this in your settings.",
"need_another_security_type": "Need another security type?",
"network_is_unsecured": "Wi-Fi network {{ssid}} is unsecured",
"network_name": "Network Name",
"network_requires_auth": "Wi-Fi network {{ssid}} requires 802.1X authentication",
"network_requires_wpa_password": "Wi-Fi network {{ssid}} requires a WPA2 password",
"network_settings": "Network Settings",
"networking": "Networking",
"never": "Never",
@@ -183,6 +199,7 @@
"no_modules_attached": "No modules attached",
"no_network_found": "No network found",
"no_pipette_attached": "No pipette attached",
"no_update_files": "Unable to retrieve update for this robot. Ensure your computer is connected to the internet and try again later.",
"none_description": "Not recommended",
"not_calibrated": "Not calibrated yet",
"not_calibrated_short": "Not calibrated",
@@ -197,8 +214,10 @@
"on": "On",
"one_hour": "1 hour",
"other_networks": "Other Networks",
"other_robot_updating": "Unable to update because the app is currently updating a different robot.",
"password": "Password",
"password_error_message": "Must be at least 8 characters",
"password_not_long_enough": "Password must be at least {{minLength}} characters",
"pause_protocol": "Pause protocol when robot door opens",
"pause_protocol_description": "When enabled, opening the robot door during a run will pause the robot after it has completed its current motion.",
"pipette_calibrations_description": "Pipette calibration uses a metal probe to determine the pipette's exact position relative to precision-cut squares on deck slots.",
@@ -208,6 +227,7 @@
"pipette_offset_calibration_recommended": "Pipette Offset calibration recommended",
"pipette_offset_calibrations_history": "See all Pipette Offset Calibration history",
"pipette_offset_calibrations_title": "Pipette Offset Calibrations",
"please_check_credentials": "Please double-check your network credentials",
"privacy": "Privacy",
"problem_during_update": "This update is taking longer than usual.",
"proceed_without_updating": "Proceed without update",
@@ -238,9 +258,12 @@
"returns_your_device_to_new_state": "This returns your device to a new state.",
"robot_busy_protocol": "This robot cannot be updated while a protocol is running on it",
"robot_calibration_data": "Robot Calibration Data",
"robot_has_bad_capabilities": "Robot has incorrect capabilities shape",
"robot_initializing": "Initializing robot...",
"robot_name": "Robot Name",
"robot_operating_update_available": "Robot Operating System Update Available",
"robot_reconnected_with version": "Robot reconnected with version",
"robot_requires_premigration": "This robot must be updated by the system before a custom update can occur",
"robot_serial_number": "Robot Serial Number",
"robot_server_version": "Robot Server Version",
"robot_settings": "Robot Settings",
@@ -259,7 +282,9 @@
"select_a_network": "Select a network",
"select_a_security_type": "Select a security type",
"select_all_settings": "Select all settings",
"select_auth_method_short": "Select authentication method",
"select_authentication_method": "Select authentication method for your selected network.",
"select_file": "Select file",
"sending_software": "Sending software...",
"serial": "Serial",
"setup_mode": "Setup mode",
@@ -275,6 +300,9 @@
"subnet_mask": "Subnet Mask",
"successfully_connected": "Successfully connected!",
"successfully_connected_to_network": "Successfully connected to {{ssid}}!",
"successfully_connected_to_ssid": "Your robot has successfully connected to Wi-Fi network {{ssid}}",
"successfully_connected_to_wifi": "Successfully connected to Wi-Fi",
"successfully_disconnected_from_wifi": "Successfully disconnected from Wi-Fi",
"supported_protocol_api_versions": "Supported Protocol API Versions",
"text_size": "Text Size",
"text_size_description": "Text on all screens will adjust to the size you choose below.",
@@ -286,6 +314,14 @@
"troubleshooting": "Troubleshooting",
"try_again": "Try again",
"try_restarting_the_update": "Try restarting the update.",
"unable_to_cancel_update": "Unable to cancel in-progress update session",
"unable_to_commit_update": "Unable to commit update",
"unable_to_connect": "Unable to connect to Wi-Fi",
"unable_to_disconnect": "Unable to disconnect from Wi-Fi",
"unable_to_find_system_file": "Unable to find system file for update",
"unable_to_find_robot_with_name": "Unable to find online robot with name",
"unable_to_restart": "Unable to restart robot",
"unable_to_start_update_session": "Unable to start update session",
"up_to_date": "up to date",
"update_available": "Update Available",
"update_channel_description": "Stable receives the latest stable releases. Beta allows you to try out new in-progress features before they launch in Stable channel, but they have not completed testing yet.",
@@ -294,7 +330,10 @@
"update_requires_restarting_robot": "Updating the robot software requires restarting the robot",
"update_robot_now": "Update robot now",
"update_robot_software": "Update robot software manually with a local file (.zip)",
"update_server_unavailable": "Unable to update because your robot's update server is not responding.",
"update_unavailable": "Update unavailable",
"updating": "Updating",
"upgrade": "upgrade",
"upload_custom_logo": "Upload custom logo",
"upload_custom_logo_description": "Upload a logo for the robot to display during boot up.",
"upload_custom_logo_dimensions": "The logo must fit within dimensions 1024 x 600 and be a PNG file (.png).",
2 changes: 0 additions & 2 deletions app/src/assets/localization/en/gripper_wizard_flows.json
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@
"before_you_begin": "Before you begin",
"begin_calibration": "Begin calibration",
"calibrate_gripper": "Calibrate Gripper",
"calibration_pin": "Calibration Pin",
"calibration_pin_touching": "The calibration pin will touch the calibration square in slot {{slot}} to determine its exact position.",
"complete_calibration": "Complete calibration",
"continue": "Continue",
@@ -17,7 +16,6 @@
"gripper_calibration": "Gripper Calibration",
"gripper_recalibration": "Gripper Recalibration",
"gripper_successfully_attached": "Gripper successfully attached",
"hex_screwdriver": "2.5 mm Hex Screwdriver",
"hold_gripper_and_loosen_screws": "Hold the gripper in place and loosen the top gripper screw first. After that move onto the bottom screw. (The screws are captive and will not come apart from the gripper.) Then carefully remove the gripper.",
"insert_pin_into_front_jaw": "Insert calibration pin in front jaw",
"insert_pin_into_rear_jaw": "Insert calibration pin in rear jaw",
1 change: 1 addition & 0 deletions app/src/assets/localization/en/pipette_wizard_flows.json
Original file line number Diff line number Diff line change
@@ -67,6 +67,7 @@
"pipette_heavy": "The 96-Channel Pipette is heavy ({{weight}}). Ask a labmate for help, if needed.",
"please_install_correct_pip": "Install {{pipetteName}} instead",
"progress_will_be_lost": "{{flow}} progress will be lost",
"provided_with_robot": "Provided with the robot. Using another size can strip the instruments’s screws.",
"reattach_carriage": "reattach z-axis carriage",
"recalibrate_pipette": "recalibrate {{mount}} pipette",
"remove_cal_probe": "remove calibration probe",
5 changes: 5 additions & 0 deletions app/src/assets/localization/en/protocol_command_text.json
Original file line number Diff line number Diff line change
@@ -6,11 +6,13 @@
"adapter_in_mod_in_slot": "{{adapter}} on {{module}} in Slot {{slot}}",
"adapter_in_slot": "{{adapter}} in Slot {{slot}}",
"air_gap_in_place": "Air gapping {{volume}} µL",
"all_nozzles": "all nozzles",
"aspirate": "Aspirating {{volume}} µL from well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec",
"aspirate_in_place": "Aspirating {{volume}} µL in place at {{flow_rate}} µL/sec ",
"blowout": "Blowing out at well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec",
"blowout_in_place": "Blowing out in place at {{flow_rate}} µL/sec",
"closing_tc_lid": "Closing Thermocycler lid",
"column_layout": "column layout",
"comment": "Comment",
"configure_for_volume": "Configure {{pipette}} to aspirate {{volume}} µL",
"configure_nozzle_layout": "Configure {{pipette}} to use {{layout}}",
@@ -59,18 +61,21 @@
"opening_tc_lid": "Opening Thermocycler lid",
"pause": "Pause",
"pause_on": "Pause on {{robot_name}}",
"partial_layout": "partial layout",
"pickup_tip": "Picking up tip(s) from {{well_range}} of {{labware}} in {{labware_location}}",
"prepare_to_aspirate": "Preparing {{pipette}} to aspirate",
"reloading_labware": "Reloading {{labware}}",
"return_tip": "Returning tip to {{well_name}} of {{labware}} in {{labware_location}}",
"right": "Right",
"row_layout": "row layout",
"save_position": "Saving position",
"set_and_await_hs_shake": "Setting Heater-Shaker to shake at {{rpm}} rpm and waiting until reached",
"setting_hs_temp": "Setting Target Temperature of Heater-Shaker to {{temp}}",
"setting_temperature_module_temp": "Setting Temperature Module to {{temp}} (rounded to nearest integer)",
"setting_thermocycler_block_temp": "Setting Thermocycler block temperature to {{temp}} with hold time of {{hold_time_seconds}} seconds after target reached",
"setting_thermocycler_lid_temp": "Setting Thermocycler lid temperature to {{temp}}",
"single": "single",
"single_nozzle_layout": "single nozzle layout",
"slot": "Slot {{slot_name}}",
"target_temperature": "target temperature",
"tc_awaiting_for_duration": "Waiting for Thermocycler profile to complete",
6 changes: 6 additions & 0 deletions app/src/assets/localization/en/top_navigation.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"app_settings": "App Settings",
"attached_pipettes_do_not_match": "Attached pipettes do not match pipettes specified in loaded protocol",
"calibrate_deck_to_proceed": "Calibrate your deck to proceed",
"calibration_dashboard": "Calibration Dashboard",
"deck_setup": "Deck Setup",
"device": "Device",
"devices": "Devices",
"instruments": "Instruments",
"labware": "Labware",
@@ -10,10 +13,13 @@
"pipettes": "pipettes",
"please_connect_to_a_robot": "Please connect to a robot to proceed",
"please_load_a_protocol": "Please load a protocol to proceed",
"protocol_details": "Protocol Details",
"protocol_runs": "Protocol Runs",
"protocol_timeline": "Protocol Timeline",
"protocols": "Protocols",
"quick_transfer": "Quick Transfer",
"robot_settings": "Robot Settings",
"run": "run",
"run_details": "Run Details",
"settings": "Settings"
}
Original file line number Diff line number Diff line change
@@ -13,13 +13,12 @@ export function getConfigureNozzleLayoutCommandText({
pip => pip.id === pipetteId
)?.pipetteName

// TODO(cb, 2024-09-10): confirm these strings for copy consistency and add them to i18n
const ConfigAmount = {
SINGLE: 'single nozzle layout',
COLUMN: 'column layout',
ROW: 'row layout',
QUADRANT: 'partial layout',
ALL: 'all nozzles',
SINGLE: t('single_nozzle_layout'),
COLUMN: t('column_layout'),
ROW: t('row_layout'),
QUADRANT: t('partial_layout'),
ALL: t('all_nozzles'),
}

return t('configure_nozzle_layout', {
27 changes: 9 additions & 18 deletions app/src/organisms/Desktop/Alerts/U2EDriverOutdatedAlert.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Link as InternalLink } from 'react-router-dom'
import styled from 'styled-components'
import { useTranslation } from 'react-i18next'

import {
AlertModal,
@@ -12,20 +13,9 @@ import {
ANALYTICS_U2E_DRIVE_ALERT_DISMISSED,
ANALYTICS_U2E_DRIVE_LINK_CLICKED,
} from '/app/redux/analytics'
import {
U2E_DRIVER_UPDATE_URL,
U2E_DRIVER_OUTDATED_MESSAGE,
U2E_DRIVER_DESCRIPTION,
U2E_DRIVER_OUTDATED_CTA,
} from '/app/redux/system-info'
import { U2E_DRIVER_UPDATE_URL } from '/app/redux/system-info'
import type { AlertProps } from './types'

// TODO(mc, 2020-05-07): i18n
const DRIVER_OUT_OF_DATE = 'Realtek USB-to-Ethernet Driver Update Available'
const VIEW_ADAPTER_INFO = 'view adapter info'
const GET_UPDATE = 'get update'
const DONT_REMIND_ME_AGAIN = "Don't remind me again"

const ADAPTER_INFO_URL = '/more/network-and-system'

const LinkButton = styled(Link)`
@@ -42,19 +32,20 @@ const IgnoreCheckbox = styled(DeprecatedCheckboxField)`

export function U2EDriverOutdatedAlert(props: AlertProps): JSX.Element {
const trackEvent = useTrackEvent()
const { t } = useTranslation('app_settings')
const [rememberDismiss, toggleRememberDismiss] = useToggle()
const { dismissAlert } = props

return (
<AlertModal
alertOverlay
heading={DRIVER_OUT_OF_DATE}
heading={t('driver_out_of_date')}
buttons={[
{
Component: LinkButton,
as: InternalLink,
to: ADAPTER_INFO_URL,
children: VIEW_ADAPTER_INFO,
children: t('view_adapter_info'),
onClick: () => {
dismissAlert(rememberDismiss)
trackEvent({
@@ -67,7 +58,7 @@ export function U2EDriverOutdatedAlert(props: AlertProps): JSX.Element {
Component: LinkButton,
href: U2E_DRIVER_UPDATE_URL,
external: true,
children: GET_UPDATE,
children: t('get_update'),
onClick: () => {
dismissAlert(rememberDismiss)
trackEvent({
@@ -79,11 +70,11 @@ export function U2EDriverOutdatedAlert(props: AlertProps): JSX.Element {
]}
>
<p>
{U2E_DRIVER_OUTDATED_MESSAGE} {U2E_DRIVER_DESCRIPTION}
{t('u2e_driver_outdated_message')} {t('u2e_driver_description')}
</p>
<p>{U2E_DRIVER_OUTDATED_CTA}</p>
<p>{t('please_update_driver')}</p>
<IgnoreCheckbox
label={DONT_REMIND_ME_AGAIN}
label={t('dont_remind_me')}
value={rememberDismiss}
onChange={toggleRememberDismiss}
/>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -106,7 +106,7 @@ export function UpdateRobotSoftware({
</TertiaryButton>
{updateFromFileDisabledReason != null && (
<Tooltip tooltipProps={updateButtonTooltipProps}>
{updateFromFileDisabledReason}
{t(updateFromFileDisabledReason)}
</Tooltip>
)}
</Flex>
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { Controller } from 'react-hook-form'
import styled, { css } from 'styled-components'

import { useTranslation } from 'react-i18next'
import {
FONT_SIZE_BODY_1,
BUTTON_TYPE_SUBMIT,
Flex,
} from '@opentrons/components'
import { SECURITY_WPA_PSK, SECURITY_WPA_EAP } from '/app/redux/networking'
import { ScrollableAlertModal } from '/app/molecules/modals'
import { TextField } from './TextField'
import { KeyFileField } from './KeyFileField'
import { SecurityField } from './SecurityField'
import { FIELD_TYPE_KEY_FILE, FIELD_TYPE_SECURITY } from '../constants'
import * as Copy from '../i18n'

import type { Control } from 'react-hook-form'
import type { ConnectFormField, ConnectFormValues, WifiNetwork } from '../types'
@@ -53,16 +53,23 @@ export interface FormModalProps {

export const FormModal = (props: FormModalProps): JSX.Element => {
const { id, network, fields, isValid, onCancel, control } = props
const { t } = useTranslation(['device_settings', 'shared'])

const heading =
network !== null
? Copy.CONNECT_TO_SSID(network.ssid)
: Copy.FIND_AND_JOIN_A_NETWORK
? t('connect_to_ssid', { ssid: network.ssid })
: t('find_and_join_network')

const body =
network !== null
? Copy.NETWORK_REQUIRES_SECURITY(network)
: Copy.ENTER_NAME_AND_SECURITY_TYPE
let bodyText = t('enter_name_security_type')
if (network != null) {
if (network.securityType === SECURITY_WPA_PSK) {
bodyText = t('network_requires_wpa_password', { ssid: network.ssid })
} else if (network.securityType === SECURITY_WPA_EAP) {
bodyText = t('network_requires_auth', { ssid: network.ssid })
} else {
bodyText = t('network_is_unsecured', { ssid: network.ssid })
}
}

return (
<ScrollableAlertModal
@@ -71,16 +78,16 @@ export const FormModal = (props: FormModalProps): JSX.Element => {
iconName="wifi"
onCloseClick={onCancel}
buttons={[
{ children: Copy.CANCEL, onClick: props.onCancel },
{ children: t('shared:cancel'), onClick: props.onCancel },
{
children: Copy.CONNECT,
children: t('connect'),
type: BUTTON_TYPE_SUBMIT,
form: id,
disabled: !isValid,
},
]}
>
<StyledCopy>{body}</StyledCopy>
<StyledCopy>{bodyText}</StyledCopy>
<StyledFlex id={id}>
{fields.map(fieldProps => {
const { name } = fieldProps
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useRef } from 'react'
import { useTranslation } from 'react-i18next'

import { SelectField } from '@opentrons/components'
import { FormRow } from './FormRow'
import { UploadKeyInput } from './UploadKeyInput'
import { LABEL_ADD_NEW_KEY } from '../i18n'
import { useConnectFormField } from './form-state'

import type { WifiKey } from '../types'
@@ -27,10 +27,6 @@ export interface KeyFileFieldProps {

const ADD_NEW_KEY_VALUE = '__addNewKey__'

const ADD_NEW_KEY_OPTION_GROUP = {
options: [{ value: ADD_NEW_KEY_VALUE, label: LABEL_ADD_NEW_KEY }],
}

const makeKeyOptions = (
keys: WifiKey[]
): { options: Array<{ value: string; label: string }> } => ({
@@ -48,6 +44,11 @@ export const KeyFileField = (props: KeyFileFieldProps): JSX.Element => {
field,
fieldState,
} = props
const { t } = useTranslation('device_settings')
const ADD_NEW_KEY_OPTION_GROUP = {
options: [{ value: ADD_NEW_KEY_VALUE, label: t('add_new') }],
}

const { value, error, setValue, setTouched } = useConnectFormField(
field,
fieldState
@@ -81,7 +82,7 @@ export const KeyFileField = (props: KeyFileFieldProps): JSX.Element => {
</FormRow>
<UploadKeyInput
ref={uploadKeyRef}
label={LABEL_ADD_NEW_KEY}
label={t('add_new')}
robotName={robotName}
onUpload={setValue}
/>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useTranslation } from 'react-i18next'
import { SelectField } from '@opentrons/components'

import { SECURITY_NONE, SECURITY_WPA_PSK } from '../constants'
import { LABEL_SECURITY_NONE, LABEL_SECURITY_PSK } from '../i18n'
import { useConnectFormField } from './form-state'
import { FormRow } from './FormRow'

@@ -25,8 +25,8 @@ export interface SecurityFieldProps {
}

const ALL_SECURITY_OPTIONS = [
{ options: [{ value: SECURITY_NONE, label: LABEL_SECURITY_NONE }] },
{ options: [{ value: SECURITY_WPA_PSK, label: LABEL_SECURITY_PSK }] },
{ options: [{ value: SECURITY_NONE, label: 'shared:none' }] },
{ options: [{ value: SECURITY_WPA_PSK, label: 'wpa2_personal' }] },
]

const makeEapOptionsGroup = (
@@ -39,6 +39,7 @@ const makeEapOptionsGroup = (
})

export const SecurityField = (props: SecurityFieldProps): JSX.Element => {
const { t } = useTranslation(['device_settings', 'shared'])
const {
id,
name,
@@ -62,7 +63,7 @@ export const SecurityField = (props: SecurityFieldProps): JSX.Element => {
]

return (
<FormRow label={label} labelFor={id}>
<FormRow label={t(label)} labelFor={id}>
<SelectField
{...{
id,
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useReducer } from 'react'
import { useTranslation } from 'react-i18next'

import {
LegacyInputField,
@@ -9,7 +10,6 @@ import {

import { FormRow } from './FormRow'
import { useConnectFormField } from './form-state'
import { LABEL_SHOW_PASSWORD } from '../i18n'
import type {
ControllerFieldState,
ControllerRenderProps,
@@ -27,6 +27,7 @@ export interface TextFieldProps {
}

export const TextField = (props: TextFieldProps): JSX.Element => {
const { t } = useTranslation('device_settings')
const { id, name, label, isPassword, className, field, fieldState } = props
const { value, error, onChange, onBlur } = useConnectFormField(
field,
@@ -42,7 +43,7 @@ export const TextField = (props: TextFieldProps): JSX.Element => {
/>
{isPassword && (
<DeprecatedCheckboxField
label={LABEL_SHOW_PASSWORD}
label={t('show_password')}
value={showPw}
onChange={toggleShowPw}
/>
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import get from 'lodash/get'

import * as Constants from '../constants'
import * as Copy from '../i18n'

import type { FieldError } from 'react-hook-form'
import type { TFunction } from 'i18next'
import type {
WifiNetwork,
WifiKey,
@@ -24,28 +24,29 @@ type Errors = Record<string, FieldError>
export const renderLabel = (label: string, required: boolean): string =>
`${required ? '* ' : ''}${label}`

const FIELD_SSID: ConnectFormTextField = {
const makeFieldSsid = (t: TFunction): ConnectFormTextField => ({
type: Constants.FIELD_TYPE_TEXT,
name: Constants.CONFIGURE_FIELD_SSID,
label: renderLabel(Copy.LABEL_SSID, true),
label: renderLabel(t('network_name'), true),
isPassword: false,
}
})

const FIELD_PSK: ConnectFormTextField = {
const makeFieldPsk = (t: TFunction): ConnectFormTextField => ({
type: Constants.FIELD_TYPE_TEXT,
name: Constants.CONFIGURE_FIELD_PSK,
label: renderLabel(Copy.LABEL_PSK, true),
label: renderLabel(t('password'), true),
isPassword: true,
}
})

const makeSecurityField = (
eapOptions: EapOption[],
showAllOptions: boolean
showAllOptions: boolean,
t: TFunction
): ConnectFormSecurityField => ({
type: Constants.FIELD_TYPE_SECURITY,
name: Constants.CONFIGURE_FIELD_SECURITY_TYPE,
label: renderLabel(Copy.LABEL_SECURITY, true),
placeholder: Copy.SELECT_AUTHENTICATION_METHOD,
label: renderLabel(t('authentication'), true),
placeholder: t('select_auth_method_short'),
eapOptions,
showAllOptions,
})
@@ -77,21 +78,22 @@ export function getConnectFormFields(
robotName: string,
eapOptions: EapOption[],
wifiKeys: WifiKey[],
values: ConnectFormValues
values: ConnectFormValues,
t: TFunction
): ConnectFormField[] {
const { securityType: formSecurityType } = values
const fields = []

// if the network is unknown, display a field to enter the SSID
if (network === null) {
fields.push(FIELD_SSID)
fields.push(makeFieldSsid(t))
}

// if the network is unknown or the known network is EAP, display a
// security dropdown; security dropdown will handle which options to
// display based on known or unknown network
if (!network || network.securityType === Constants.SECURITY_WPA_EAP) {
fields.push(makeSecurityField(eapOptions, !network))
fields.push(makeSecurityField(eapOptions, !network, t))
}

// if known network is PSK or network is unknown and user has selected PSK
@@ -100,7 +102,7 @@ export function getConnectFormFields(
network?.securityType === Constants.SECURITY_WPA_PSK ||
formSecurityType === Constants.SECURITY_WPA_PSK
) {
fields.push(FIELD_PSK)
fields.push(makeFieldPsk(t))
}

// if known network is EAP or user selected EAP, map eap options to fields
@@ -121,7 +123,7 @@ export function getConnectFormFields(
label,
robotName,
wifiKeys,
placeholder: Copy.SELECT_FILE,
placeholder: t('select_file'),
}
}

@@ -142,7 +144,8 @@ export function validateConnectFormFields(
network: WifiNetwork | null,
eapOptions: EapOption[],
values: ConnectFormValues,
errors: Errors
errors: Errors,
t: TFunction
): Errors {
const {
ssid: formSsid,
@@ -152,7 +155,7 @@ export function validateConnectFormFields(
let errorMessage: string | undefined

if (network === null && (formSsid == null || formSsid.length === 0)) {
errorMessage = Copy.FIELD_IS_REQUIRED(Copy.LABEL_SSID)
errorMessage = t('field_is_required', { field: t('network_name') })
return errorMessage != null
? {
...errors,
@@ -168,7 +171,7 @@ export function validateConnectFormFields(
(network === null || network.securityType === Constants.SECURITY_WPA_EAP) &&
!formSecurityType
) {
errorMessage = Copy.FIELD_IS_REQUIRED(Copy.LABEL_SECURITY)
errorMessage = t('field_is_required', { field: t('authentication') })
return errorMessage != null
? {
...errors,
@@ -185,10 +188,9 @@ export function validateConnectFormFields(
formSecurityType === Constants.SECURITY_WPA_PSK) &&
(!formPsk || formPsk.length < Constants.CONFIGURE_PSK_MIN_LENGTH)
) {
errorMessage = Copy.FIELD_NOT_LONG_ENOUGH(
Copy.LABEL_PSK,
Constants.CONFIGURE_PSK_MIN_LENGTH
)
errorMessage = t('password_not_long_enough', {
minLength: Constants.CONFIGURE_PSK_MIN_LENGTH,
})
return errorMessage != null
? {
...errors,
@@ -215,7 +217,9 @@ export function validateConnectFormFields(
) => {
const fieldName = getEapFieldName(name)
const errorMessage =
displayName != null ? Copy.FIELD_IS_REQUIRED(displayName) : ''
displayName != null
? t('field_is_required', { field: displayName })
: ''

if (errorMessage != null) {
acc[fieldName] = {
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useForm } from 'react-hook-form'
import { useTranslation } from 'react-i18next'

import { useResetFormOnSecurityChange } from './form-state'
import {
@@ -10,6 +11,7 @@ import {
import { FormModal } from './FormModal'

import type { Control, Resolver } from 'react-hook-form'
import type { TFunction } from 'i18next'
import type {
ConnectFormValues,
WifiConfigureRequest,
@@ -35,6 +37,7 @@ interface ConnectModalComponentProps extends ConnectModalProps {
}

export const ConnectModal = (props: ConnectModalProps): JSX.Element => {
const { t } = useTranslation(['device_settings', 'shared'])
const { network, eapOptions, onConnect } = props

const onSubmit = (values: ConnectFormValues): void => {
@@ -45,7 +48,13 @@ export const ConnectModal = (props: ConnectModalProps): JSX.Element => {
const handleValidate: Resolver<ConnectFormValues> = values => {
let errors = {}

errors = validateConnectFormFields(network, eapOptions, values, errors)
errors = validateConnectFormFields(
network,
eapOptions,
values,
errors,
t as TFunction
)
return { values, errors }
}

@@ -78,6 +87,7 @@ export const ConnectModal = (props: ConnectModalProps): JSX.Element => {
export const ConnectModalComponent = (
props: ConnectModalComponentProps
): JSX.Element => {
const { t } = useTranslation(['device_settings', 'shared'])
const {
robotName,
network,
@@ -95,7 +105,8 @@ export const ConnectModalComponent = (
robotName,
eapOptions,
wifiKeys,
values
values,
t as TFunction
)

useResetFormOnSecurityChange()
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next'
import { AlertModal, SpinnerModal } from '@opentrons/components'

import * as Copy from './i18n'
import { ErrorModal } from '/app/molecules/modals'
import { DISCONNECT } from './constants'
import { PENDING, FAILURE } from '/app/redux/robot-api'
@@ -18,29 +18,32 @@ export interface ResultModalProps {

export const ResultModal = (props: ResultModalProps): JSX.Element => {
const { type, ssid, requestStatus, error, onClose } = props
const { t } = useTranslation(['device_settings', 'shared'])
const isDisconnect = type === DISCONNECT

if (requestStatus === PENDING) {
const message = isDisconnect
? Copy.DISCONNECTING_FROM_NETWORK(ssid)
: Copy.CONNECTING_TO_NETWORK(ssid)
? t('disconnecting_from_wifi_network', { ssid: ssid })
: t('connecting_to_wifi_network', { ssid: ssid })

return <SpinnerModal alertOverlay message={message} />
}

if (error || requestStatus === FAILURE) {
const heading = isDisconnect
? Copy.UNABLE_TO_DISCONNECT
: Copy.UNABLE_TO_CONNECT
? t('unable_to_disconnect')
: t('unable_to_connect')

const message = isDisconnect
? Copy.YOUR_ROBOT_WAS_UNABLE_TO_DISCONNECT(ssid)
: Copy.YOUR_ROBOT_WAS_UNABLE_TO_CONNECT(ssid)
? t('disconnect_from_wifi_network_failure', { ssid: ssid })
: t('connect_to_wifi_network_failure', { ssid: ssid })

const retryMessage = !isDisconnect ? ` ${Copy.CHECK_YOUR_CREDENTIALS}.` : ''
const retryMessage = !isDisconnect ? t('please_check_credentials') : ''

const placeholderError = {
message: `Likely incorrect network password. ${Copy.CHECK_YOUR_CREDENTIALS}.`,
message: `${t('likely_incorrect_password')} ${t(
'please_check_credentials'
)}.`,
}

return (
@@ -54,20 +57,20 @@ export const ResultModal = (props: ResultModalProps): JSX.Element => {
}

const heading = isDisconnect
? Copy.SUCCESSFULLY_DISCONNECTED
: Copy.SUCCESSFULLY_CONNECTED
? t('successfully_disconnected')
: t('successfully_connected_to_wifi')

const message = isDisconnect
? Copy.YOUR_ROBOT_HAS_DISCONNECTED(ssid)
: Copy.YOUR_ROBOT_HAS_CONNECTED(ssid)
? t('disconnect_from_wifi_network_success')
: t('successfully_connected_to_ssid', { ssid: ssid })

return (
<AlertModal
alertOverlay
iconName="wifi"
heading={heading}
onCloseClick={props.onClose}
buttons={[{ children: Copy.CLOSE, onClick: onClose }]}
buttons={[{ children: t('shared:close'), onClick: onClose }]}
>
{message}
</AlertModal>
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type * as React from 'react'
import { useTranslation } from 'react-i18next'
import { CONTEXT_MENU } from '@opentrons/components'
import { SelectField } from '/app/atoms/SelectField'
import * as Copy from '../i18n'
import { NetworkOptionLabel, NetworkActionLabel } from './NetworkOptionLabel'

import type { TFunction } from 'i18next'
import type { SelectOptionOrGroup } from '@opentrons/components'

import type { WifiNetwork } from '../types'
@@ -20,11 +21,16 @@ const FIELD_NAME = '__SelectSsid__'

const JOIN_OTHER_VALUE = '__join-other-network__'

const SELECT_JOIN_OTHER_GROUP = {
options: [{ value: JOIN_OTHER_VALUE, label: Copy.LABEL_JOIN_OTHER_NETWORK }],
}
const formatOptions = (
list: WifiNetwork[],
t: TFunction
): SelectOptionOrGroup[] => {
const SELECT_JOIN_OTHER_GROUP = {
options: [
{ value: JOIN_OTHER_VALUE, label: `${t('join_other_network')}...` },
],
}

const formatOptions = (list: WifiNetwork[]): SelectOptionOrGroup[] => {
const ssidOptionsList = {
options: list?.map(({ ssid }) => ({ value: ssid })),
}
@@ -34,6 +40,7 @@ const formatOptions = (list: WifiNetwork[]): SelectOptionOrGroup[] => {
}

export function SelectSsid(props: SelectSsidProps): JSX.Element {
const { t } = useTranslation('device_settings')
const { list, value, onConnect, onJoinOther, isRobotBusy } = props

const handleValueChange = (_: string, value: string): void => {
@@ -69,8 +76,8 @@ export function SelectSsid(props: SelectSsidProps): JSX.Element {
disabled={isRobotBusy}
name={FIELD_NAME}
value={value}
options={formatOptions(list)}
placeholder={Copy.SELECT_NETWORK}
options={formatOptions(list, t as TFunction)}
placeholder={t('choose_a_network')}
onValueChange={handleValueChange}
formatOptionLabel={formatOptionLabel}
width="16rem"

This file was deleted.

Original file line number Diff line number Diff line change
@@ -88,7 +88,7 @@ export function UpdateRobotModal({

let disabledReason: string = ''
if (updateFromFileDisabledReason)
disabledReason = updateFromFileDisabledReason
disabledReason = t(updateFromFileDisabledReason)
else if (isRobotBusy) disabledReason = t('robot_busy_protocol')

useEffect(() => {
6 changes: 4 additions & 2 deletions app/src/organisms/GripperWizardFlows/BeforeBeginning.tsx
Original file line number Diff line number Diff line change
@@ -13,6 +13,8 @@ import {
SCREWDRIVER_LOADNAME,
GRIPPER_LOADNAME,
CAL_PIN_LOADNAME,
CALIBRATION_PIN_DISPLAY_NAME,
HEX_SCREWDRIVER_DISPLAY_NAME,
} from './constants'

import type { UseMutateFunction } from 'react-query'
@@ -105,9 +107,9 @@ export const BeforeBeginning = (
const equipmentInfoByLoadName: {
[loadName: string]: { displayName: string; subtitle?: string }
} = {
calibration_pin: { displayName: t('calibration_pin') },
calibration_pin: { displayName: CALIBRATION_PIN_DISPLAY_NAME },
hex_screwdriver: {
displayName: t('hex_screwdriver'),
displayName: HEX_SCREWDRIVER_DISPLAY_NAME,
subtitle: t('provided_with_robot_use_right_size'),
},
[GRIPPER_LOADNAME]: { displayName: t('branded:gripper') },
4 changes: 4 additions & 0 deletions app/src/organisms/GripperWizardFlows/constants.ts
Original file line number Diff line number Diff line change
@@ -13,6 +13,10 @@ export const GRIPPER_FLOW_TYPES = {
RECALIBRATE: 'RECALIBRATE',
} as const

// note: we will not translate these item titles to be consistent with manuals
export const CALIBRATION_PIN_DISPLAY_NAME = 'Calibration Pin'
export const HEX_SCREWDRIVER_DISPLAY_NAME = '2.5 mm Hex Screwdriver'

// pin movements

export const MOVE_PIN_TO_FRONT_JAW = 'movePinToFrontJaw' as const
Original file line number Diff line number Diff line change
@@ -33,7 +33,6 @@ export function NameQuickTransfer(props: NameQuickTransferProps): JSX.Element {
if (name.length > 60) {
error = t('character_limit_error')
}
// TODO add error handling for quick transfer name replication

return createPortal(
<Flex position={POSITION_FIXED} backgroundColor={COLORS.white} width="100%">
14 changes: 9 additions & 5 deletions app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx
Original file line number Diff line number Diff line change
@@ -107,6 +107,10 @@ export const BeforeBeginning = (

let equipmentList = [CALIBRATION_PROBE]
const proceedButtonText = t('move_gantry_to_front')
const hexScrewdriverWithSubtitle = {
...HEX_SCREWDRIVER,
subtitle: t('provided_with_robot'),
}
let bodyTranslationKey: string = ''

switch (flowType) {
@@ -124,7 +128,7 @@ export const BeforeBeginning = (
equipmentList = [
{ ...PIPETTE, displayName: displayName ?? PIPETTE.displayName },
CALIBRATION_PROBE,
HEX_SCREWDRIVER,
hexScrewdriverWithSubtitle,
]
} else {
equipmentList = [
@@ -133,7 +137,7 @@ export const BeforeBeginning = (
displayName: displayName ?? NINETY_SIX_CHANNEL_PIPETTE.displayName,
},
CALIBRATION_PROBE,
HEX_SCREWDRIVER,
hexScrewdriverWithSubtitle,
NINETY_SIX_CHANNEL_MOUNTING_PLATE,
]
}
@@ -148,19 +152,19 @@ export const BeforeBeginning = (
equipmentList = [
{ ...NINETY_SIX_CHANNEL_PIPETTE, displayName },
CALIBRATION_PROBE,
HEX_SCREWDRIVER,
hexScrewdriverWithSubtitle,
NINETY_SIX_CHANNEL_MOUNTING_PLATE,
]
} else {
equipmentList = [
{ ...PIPETTE, displayName },
CALIBRATION_PROBE,
HEX_SCREWDRIVER,
hexScrewdriverWithSubtitle,
]
}
} else {
bodyTranslationKey = 'get_started_detach'
equipmentList = [HEX_SCREWDRIVER]
equipmentList = [hexScrewdriverWithSubtitle]
}
break
}
5 changes: 2 additions & 3 deletions app/src/organisms/PipetteWizardFlows/constants.ts
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@ export const FLOWS = {
DETACH: 'DETACH',
CALIBRATE: 'CALIBRATE',
}

// note: we will not be translating these item titles to be consistent with manuals
export const CALIBRATION_PROBE_DISPLAY_NAME = 'Calibration Probe'
export const HEX_SCREWDRIVER_DISPLAY_NAME = '2.5 mm Hex Screwdriver'
export const PIPETTE_DISPLAY_NAME = '1- or 8-Channel Pipette'
@@ -33,9 +35,6 @@ export const CALIBRATION_PROBE = {
export const HEX_SCREWDRIVER = {
loadName: 'hex_screwdriver',
displayName: HEX_SCREWDRIVER_DISPLAY_NAME,
// TODO(jr, 4/3/23): add this subtitle to i18n
subtitle:
'Provided with the robot. Using another size can strip the instruments’s screws.',
}
export const PIPETTE = {
loadName: 'flex_pipette',
1 change: 1 addition & 0 deletions app/src/pages/Desktop/Labware/index.tsx
Original file line number Diff line number Diff line change
@@ -63,6 +63,7 @@ const labwareDisplayCategoryFilters: LabwareFilter[] = [
'wellPlate',
]

// note: we've decided not to translate these categories
const FILTER_OPTIONS: DropdownOption[] = labwareDisplayCategoryFilters.map(
category => ({
name: startCase(category),
22 changes: 7 additions & 15 deletions app/src/redux/robot-update/selectors.ts
Original file line number Diff line number Diff line change
@@ -19,15 +19,6 @@ import type {
RobotUpdateTarget,
} from './types'

// TODO(mc, 2020-08-02): i18n
const UPDATE_SERVER_UNAVAILABLE =
"Unable to update because your robot's update server is not responding."
const OTHER_ROBOT_UPDATING =
'Unable to update because the app is currently updating a different robot.'
const NO_UPDATE_FILES =
'Unable to retrieve update for this robot. Ensure your computer is connected to the internet and try again later.'
const UNAVAILABLE = 'Update unavailable'

export const getRobotUpdateTarget: (
state: State,
robotName: string
@@ -198,6 +189,7 @@ export function getRobotUpdateAvailable(
: getRobotUpdateType(currentVersion, updateVersion)
}

// this util returns i18n keys in device_settings
export const getRobotUpdateDisplayInfo: (
state: State,
robotName: string
@@ -212,21 +204,21 @@ export const getRobotUpdateDisplayInfo: (
(robot, currentUpdatingRobot, updateVersion) => {
const robotVersion = robot ? getRobotApiVersion(robot) : null
const autoUpdateType = getRobotUpdateType(robotVersion, updateVersion)
const autoUpdateAction = autoUpdateType ?? UNAVAILABLE
const autoUpdateAction = autoUpdateType ?? 'update_unavailable'
let autoUpdateDisabledReason = null
let updateFromFileDisabledReason = null

if (robot?.serverHealthStatus !== HEALTH_STATUS_OK) {
autoUpdateDisabledReason = UPDATE_SERVER_UNAVAILABLE
updateFromFileDisabledReason = UPDATE_SERVER_UNAVAILABLE
autoUpdateDisabledReason = 'update_server_unavailable'
updateFromFileDisabledReason = 'update_server_unavailable'
} else if (
currentUpdatingRobot !== null &&
currentUpdatingRobot.name !== robot?.name
) {
autoUpdateDisabledReason = OTHER_ROBOT_UPDATING
updateFromFileDisabledReason = OTHER_ROBOT_UPDATING
autoUpdateDisabledReason = 'other_robot_updating'
updateFromFileDisabledReason = 'other_robot_updating'
} else if (autoUpdateType === null) {
autoUpdateDisabledReason = NO_UPDATE_FILES
autoUpdateDisabledReason = 'no_update_files'
}

return {
9 changes: 0 additions & 9 deletions app/src/redux/system-info/constants.ts
Original file line number Diff line number Diff line change
@@ -22,12 +22,3 @@ export const USB_DEVICE_REMOVED: 'systemInfo:USB_DEVICE_REMOVED' =

export const NETWORK_INTERFACES_CHANGED: 'systemInfo:NETWORK_INTERFACES_CHANGED' =
'systemInfo:NETWORK_INTERFACES_CHANGED'

// copy
// TODO(mc, 2020-05-11): i18n
export const U2E_DRIVER_OUTDATED_MESSAGE =
'There is an updated Realtek USB-to-Ethernet adapter driver available for your computer.'
export const U2E_DRIVER_DESCRIPTION =
'The OT-2 uses this adapter for its USB connection to the Opentrons App.'
export const U2E_DRIVER_OUTDATED_CTA =
"Please update your computer's driver to ensure a reliable connection to your OT-2."
2 changes: 1 addition & 1 deletion shared-data/js/fixtures.ts
Original file line number Diff line number Diff line change
@@ -238,7 +238,7 @@ export function getAddressableAreaNamesFromLoadedModule(
return [...acc, ...providedAddressableAreas]
}, [])
}

// note: we've decided not to translate these strings
export function getFixtureDisplayName(
cutoutFixtureId: CutoutFixtureId | null,
usbPortNumber?: number

Unchanged files with check annotations Beta

LABEL_PSK,
SELECT_AUTHENTICATION_METHOD,
SELECT_FILE,
} from '../../i18n'

Check failure on line 25 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Cannot find module '../../i18n' or its corresponding type declarations.

Check failure on line 25 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Cannot find module '../../i18n' or its corresponding type declarations.
import {
getConnectFormFields,
describe('getConnectFormFields', () => {
it('should add a string field for SSID if network is unknown', () => {
const fields = getConnectFormFields(null, 'robot-name', [], [], {})

Check failure on line 35 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.

Check failure on line 35 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.
expect(fields).toContainEqual({
type: FIELD_TYPE_TEXT,
it('should add a security dropdown field if network is unknown', () => {
const eapOptions = [Fixtures.mockEapOption]
const fields = getConnectFormFields(null, 'robot-name', eapOptions, [], {})

Check failure on line 47 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.

Check failure on line 47 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.
expect(fields).toContainEqual({
type: FIELD_TYPE_SECURITY,
...Fixtures.mockWifiNetwork,
securityType: SECURITY_WPA_EAP,
}
const fields = getConnectFormFields(

Check failure on line 65 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.

Check failure on line 65 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.
network,
'robot-name',
eapOptions,
...Fixtures.mockWifiNetwork,
securityType: SECURITY_WPA_PSK,
}
const fields = getConnectFormFields(network, 'robot-name', [], [], {})

Check failure on line 88 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.

Check failure on line 88 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.
expect(fields).toContainEqual({
type: FIELD_TYPE_TEXT,
})
it('should add a password field for PSK if unknown network and user selects PSK', () => {
const fields = getConnectFormFields(null, 'robot-name', [], [], {

Check failure on line 99 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.

Check failure on line 99 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.
securityType: SECURITY_WPA_PSK,
})
{ ...Fixtures.mockEapOption, name: 'someOtherEapType' },
]
const wifiKeys = [Fixtures.mockWifiKey]
const fields = getConnectFormFields(

Check failure on line 117 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.

Check failure on line 117 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.
null,
'robot-name',
eapOptions,
{ ...Fixtures.mockEapOption, name: 'someOtherEapType', options: [] },
]
const wifiKeys = [Fixtures.mockWifiKey]
const fields = getConnectFormFields(

Check failure on line 163 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.

Check failure on line 163 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 6 arguments, but got 5.
network,
'robot-name',
eapOptions,
describe('validateConnectFormFields', () => {
it('should error if network is hidden and ssid is blank', () => {
const errors = validateConnectFormFields(

Check failure on line 200 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 5 arguments, but got 4.

Check failure on line 200 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 5 arguments, but got 4.
null,
[],
{
})
it('should error if network is hidden and securityType is blank', () => {
const errors = validateConnectFormFields(null, [], { ssid: 'foobar' }, {})

Check failure on line 216 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 5 arguments, but got 4.

Check failure on line 216 in app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/__tests__/form-fields.test.ts

GitHub Actions / js checks

Expected 5 arguments, but got 4.
expect(errors).toEqual({
securityType: {
units?: string
type?: string
}
interface PipetteQuirksField {

Check warning on line 62 in api-client/src/pipettes/types.ts

GitHub Actions / js checks

A record is preferred over an index signature

Check warning on line 62 in api-client/src/pipettes/types.ts

GitHub Actions / js checks

A record is preferred over an index signature
[quirkId: string]: boolean
}
interface QuirksField {
quirks?: PipetteQuirksField
}
export type PipetteSettingsFieldsMap = QuirksField & {

Check warning on line 69 in api-client/src/pipettes/types.ts

GitHub Actions / js checks

A record is preferred over an index signature

Check warning on line 69 in api-client/src/pipettes/types.ts

GitHub Actions / js checks

A record is preferred over an index signature
[fieldId: string]: PipetteSettingsField
}
export interface IndividualPipetteSettings {
fields: PipetteSettingsFieldsMap
}
type PipetteSettingsById = Partial<{ [id: string]: IndividualPipetteSettings }>

Check warning on line 77 in api-client/src/pipettes/types.ts

GitHub Actions / js checks

A record is preferred over an index signature

Check warning on line 77 in api-client/src/pipettes/types.ts

GitHub Actions / js checks

A record is preferred over an index signature
export type PipetteSettings = PipetteSettingsById
export interface PipetteSettingsUpdateFieldsMap {

Check warning on line 81 in api-client/src/pipettes/types.ts

GitHub Actions / js checks

A record is preferred over an index signature

Check warning on line 81 in api-client/src/pipettes/types.ts

GitHub Actions / js checks

A record is preferred over an index signature
[fieldId: string]: PipetteSettingsUpdateField
}
} | null
export interface UpdatePipetteSettingsData {
fields: { [fieldId: string]: PipetteSettingsUpdateField }

Check warning on line 90 in api-client/src/pipettes/types.ts

GitHub Actions / js checks

A record is preferred over an index signature

Check warning on line 90 in api-client/src/pipettes/types.ts

GitHub Actions / js checks

A record is preferred over an index signature
}
export interface ResourceLink {
href: string
meta?: Partial<{ [key: string]: string | null | undefined }>

Check warning on line 14 in api-client/src/types.ts

GitHub Actions / js checks

A record is preferred over an index signature

Check warning on line 14 in api-client/src/types.ts

GitHub Actions / js checks

A record is preferred over an index signature
}
export type ResourceLinks = Record<
export const appRestart = (message: string): AppRestartAction => ({
type: APP_RESTART,
payload: {
message: message,

Check warning on line 360 in app-shell-odd/src/actions.ts

GitHub Actions / js checks

Expected property shorthand

Check warning on line 360 in app-shell-odd/src/actions.ts

GitHub Actions / js checks

Expected property shorthand
},
meta: { shell: true },
})
export const reloadUi = (message: string): ReloadUiAction => ({
type: RELOAD_UI,
payload: {
message: message,

Check warning on line 368 in app-shell-odd/src/actions.ts

GitHub Actions / js checks

Expected property shorthand

Check warning on line 368 in app-shell-odd/src/actions.ts

GitHub Actions / js checks

Expected property shorthand
},
meta: { shell: true },
})
export const sendLog = (message: string): SendLogAction => ({
type: SEND_LOG,
payload: {
message: message,

Check warning on line 376 in app-shell-odd/src/actions.ts

GitHub Actions / js checks

Expected property shorthand

Check warning on line 376 in app-shell-odd/src/actions.ts

GitHub Actions / js checks

Expected property shorthand
},
meta: { shell: true },
})
export const updateBrightness = (message: string): UpdateBrightnessAction => ({
type: UPDATE_BRIGHTNESS,
payload: {
message: message,

Check warning on line 384 in app-shell-odd/src/actions.ts

GitHub Actions / js checks

Expected property shorthand

Check warning on line 384 in app-shell-odd/src/actions.ts

GitHub Actions / js checks

Expected property shorthand
},
meta: { shell: true },
})