From 9ce1261e54cb1dee5195523f7982b4948c42f72a Mon Sep 17 00:00:00 2001 From: Kevin Schiffer Date: Wed, 14 Aug 2024 20:15:59 +0200 Subject: [PATCH] console: Add various styling fixes --- pkg/webui/components/form/field/index.js | 11 ++-- pkg/webui/components/form/field/tooltip.js | 39 ++++++++++---- pkg/webui/components/spinner/spinner.styl | 12 +---- .../access-point-list/access-point-list.styl | 6 ++- .../containers/access-point-list/index.js | 12 +++-- .../connections/connections.styl | 18 ++++--- .../connection-settings/connections/index.js | 18 ++++--- .../connections/messages.js | 1 + .../wifi-settings-form-fields.js | 54 ++++++++++--------- .../wifi-settings-form-fields.styl | 45 ++++++++++++++++ .../shared/show-profiles-select.js | 5 +- .../shared/wifi-profiles-form-fields.js | 2 - .../wifi-profiles/overview.js | 23 ++------ pkg/webui/lib/shared-messages.js | 1 + pkg/webui/locales/en.json | 7 ++- pkg/webui/locales/ja.json | 5 ++ pkg/webui/styles/utilities/general.styl | 3 ++ 17 files changed, 173 insertions(+), 89 deletions(-) create mode 100644 pkg/webui/console/containers/gateway-managed-gateway/connection-settings/wifi-settings-form-fields.styl diff --git a/pkg/webui/components/form/field/index.js b/pkg/webui/components/form/field/index.js index 9e2776a02f2..e528a2ecbad 100644 --- a/pkg/webui/components/form/field/index.js +++ b/pkg/webui/components/form/field/index.js @@ -85,6 +85,7 @@ const FormField = props => { required, title, titleChildren, + tooltip, tooltipId, warning, validate, @@ -189,7 +190,7 @@ const FormField = props => { const value = decode(encodedValue) const disabled = inputDisabled || formDisabled - const hasTooltip = Boolean(tooltipId) + const hasTooltip = Boolean(tooltipId) || Boolean(tooltip) const hasTitle = Boolean(title) const showError = touched && @@ -198,7 +199,9 @@ const FormField = props => { const showWarning = !showError && Boolean(warning) const error = showError && errors[0] const showDescription = !showError && !showWarning && Boolean(description) - const tooltipIcon = hasTooltip ? : null + const tooltipIcon = hasTooltip ? ( + + ) : null const describedBy = showError ? `${name}-field-error` : showWarning @@ -305,6 +308,7 @@ FormField.propTypes = { required: PropTypes.bool, title: PropTypes.message, titleChildren: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]), + tooltip: PropTypes.message, tooltipId: PropTypes.string, validate: PropTypes.func, valueSetter: PropTypes.func, @@ -324,7 +328,8 @@ FormField.defaultProps = { required: false, title: undefined, titleChildren: null, - tooltipId: '', + tooltip: undefined, + tooltipId: undefined, validate: undefined, valueSetter: defaultValueSetter, warning: '', diff --git a/pkg/webui/components/form/field/tooltip.js b/pkg/webui/components/form/field/tooltip.js index 91609fe05cd..4222e5c39ea 100644 --- a/pkg/webui/components/form/field/tooltip.js +++ b/pkg/webui/components/form/field/tooltip.js @@ -35,7 +35,7 @@ const m = defineMessages({ }) const Content = props => { - const { tooltipDescription, glossaryTerm, children } = props + const { tooltipDescription, tooltip, glossaryTerm, children } = props const { description, location, absence, glossaryId } = tooltipDescription const hasLocation = Boolean(location) @@ -46,12 +46,22 @@ const Content = props => { return (
- + {description && ( + + )} + {Boolean(tooltip) && ( + + )} {hasLocation && ( <> @@ -94,24 +104,27 @@ const Content = props => { Content.propTypes = { children: PropTypes.node, glossaryTerm: PropTypes.message, + tooltip: PropTypes.node, tooltipDescription: PropTypes.shape({ description: PropTypes.message.isRequired, location: PropTypes.message, absence: PropTypes.message, glossaryId: PropTypes.string, - }).isRequired, + }), } Content.defaultProps = { children: null, glossaryTerm: undefined, + tooltipDescription: {}, + tooltip: null, } const FieldTooltip = React.memo(props => { - const { id, glossaryTerm } = props + const { id, glossaryTerm, tooltip } = props const tooltipDescription = descriptions[id] - if (!tooltipDescription) { + if ((!id || !tooltipDescription) && !tooltip) { return null } @@ -142,6 +155,7 @@ const FieldTooltip = React.memo(props => { content={ @@ -154,11 +168,14 @@ const FieldTooltip = React.memo(props => { FieldTooltip.propTypes = { glossaryTerm: PropTypes.message, - id: PropTypes.string.isRequired, + id: PropTypes.string, + tooltip: PropTypes.node, } FieldTooltip.defaultProps = { glossaryTerm: undefined, + id: undefined, + tooltip: undefined, } export default FieldTooltip diff --git a/pkg/webui/components/spinner/spinner.styl b/pkg/webui/components/spinner/spinner.styl index 410f8bcfe26..a52a2769052 100644 --- a/pkg/webui/components/spinner/spinner.styl +++ b/pkg/webui/components/spinner/spinner.styl @@ -72,23 +72,15 @@ $xs = $cs.m .center &:not(.inline) position: absolute - top: ($l * -1) // To achieve visual centering. + top: 0 left: 0 right: 0 bottom: 0 margin: auto - height: $l + height: fit-content &.inline justify-content: center - &.small - height: $s - top: ($s * -1) // To achieve visual centering. - - &.micro - height: $xs - top: ($xs * -1) // To achieve visual centering. - .small .spinner width: $s height: @width diff --git a/pkg/webui/console/containers/access-point-list/access-point-list.styl b/pkg/webui/console/containers/access-point-list/access-point-list.styl index 29ebc4e6830..225552dcd6e 100644 --- a/pkg/webui/console/containers/access-point-list/access-point-list.styl +++ b/pkg/webui/console/containers/access-point-list/access-point-list.styl @@ -15,9 +15,10 @@ .list border-input() input-width-classes() + position: relative box-sizing: border-box border-radius: $br.s - max-height: $ls.xxl + height: 15rem min-width: 15rem overflow-x: auto .item @@ -25,6 +26,9 @@ &.active background-color: $c-active-blue-active color: white + + span + color: white &:not(.active):hover cursor: pointer background-color: $c-backdrop diff --git a/pkg/webui/console/containers/access-point-list/index.js b/pkg/webui/console/containers/access-point-list/index.js index 0f9e4744302..0f75a1e946d 100644 --- a/pkg/webui/console/containers/access-point-list/index.js +++ b/pkg/webui/console/containers/access-point-list/index.js @@ -50,6 +50,7 @@ const m = defineMessages({ lastRefresh: 'Last refresh', description: 'This list shows WiFi networks as detected by your gateway. You can select an access point or choose "Other..." to enter an SSID of a hidden access point.', + scanningWifi: 'Scanning WiFi networks…', }) const computeDeltaInSeconds = (from, to) => { @@ -158,10 +159,13 @@ const AccessPointList = ({ onChange, value, className, inputWidth, onBlur, ssid
{isLoading ? ( -
- - - +
+
+ + + +
+
) : (
diff --git a/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/connections/connections.styl b/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/connections/connections.styl index 1664789fef9..6ab1c7e910e 100644 --- a/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/connections/connections.styl +++ b/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/connections/connections.styl @@ -13,7 +13,7 @@ // limitations under the License. .root - border-normal() + border-dark() border-radius: $br.l box-sizing: border-box padding: $cs.l @@ -22,7 +22,7 @@ gap: $cs.l .top - border-normal() + border-dark() box-sizing: border-box border-radius: $br.l display: flex @@ -30,21 +30,27 @@ .img-div background-color: $c-backdrop-lighter border-radius: $br.l 0 0 $br.l + border-dark('right') .image + object-fit: contain + box-sizing: border-box + padding: $cs.s height: 6rem - width: auto + width: 10rem + opacity: 0.7 + filter: grayscale(100%) .horizontal-line - background-color: $c-divider + background-color: $c-divider-dark .connections - border-normal() + border-dark() box-sizing: border-box border-radius: $br.l display: flex flex-direction: column gap: $cs.xxs - padding: $cs.m $cs.s + padding: $cs.xs $cs.s .connection padding-inline: $cs.xxs diff --git a/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/connections/index.js b/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/connections/index.js index 32beb35caf3..ace4e79473d 100644 --- a/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/connections/index.js +++ b/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/connections/index.js @@ -16,10 +16,9 @@ import React, { useCallback } from 'react' import { useSelector } from 'react-redux' import classnames from 'classnames' -import managedGatewayImage from '@assets/misc/managed-gateway.png' +import managedGatewayImage from '@assets/misc/gateway.svg' import Icon from '@ttn-lw/components/icon' -import Link from '@ttn-lw/components/link' import DataSheet from '@ttn-lw/components/data-sheet' import Message from '@ttn-lw/lib/components/message' @@ -50,7 +49,7 @@ const ConnectionByType = ({ type, isConnected, details, connectedVia, macAddress
-
+
{ /> {systemStatus?.cpu_temperature && ( -
+
- {systemStatus?.cpu_temperature} °C +
)}
+ {/* TODO: Add link to official once available. + */}

- +
{getConnectionData({ @@ -239,7 +243,7 @@ const ManagedGatewayConnections = ({ connectionsData }) => { })}
-
+
{version}', firmwareVersion: 'Firmware version: {version}', connectedVia: 'Connected via {connectedVia}', + cpuTemperature: 'CPU temperature: {temperature}', }) export default messages diff --git a/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/wifi-settings-form-fields.js b/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/wifi-settings-form-fields.js index 4168a82994d..7149e4e8f96 100644 --- a/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/wifi-settings-form-fields.js +++ b/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/wifi-settings-form-fields.js @@ -17,6 +17,7 @@ import { defineMessages } from 'react-intl' import { useDispatch, useSelector } from 'react-redux' import { isEqual, omit } from 'lodash' import { useParams } from 'react-router-dom' +import classNames from 'classnames' import Form, { useFormContext } from '@ttn-lw/components/form' import Select from '@ttn-lw/components/select' @@ -35,7 +36,6 @@ import { initialWifiProfile, } from '@console/containers/gateway-managed-gateway/shared/utils' -import tooltipIds from '@ttn-lw/lib/constants/tooltip-ids' import attachPromise from '@ttn-lw/lib/store/actions/attach-promise' import PropTypes from '@ttn-lw/lib/prop-types' @@ -43,6 +43,8 @@ import { getConnectionProfilesList } from '@console/store/actions/connection-pro import { selectConnectionProfilesByType } from '@console/store/selectors/connection-profiles' +import style from './wifi-settings-form-fields.styl' + const m = defineMessages({ settingsProfile: 'Settings profile', profileDescription: 'Connection settings profiles can be shared within the same organization', @@ -61,6 +63,8 @@ const m = defineMessages({ overrideProfile: 'Override this profile', editProfile: 'Edit this profile', attemptingToConnect: 'The gateway WiFi is currently attempting to connect using this profile', + settingsProfileTooltip: + 'To set up the gateway connection, you can either use a shared profile, to share the connection settings with other gateways, or set a config for this gateway only.', }) const WifiSettingsFormFields = ({ initialValues, isWifiConnected, saveFormClicked }) => { @@ -92,17 +96,17 @@ const WifiSettingsFormFields = ({ initialValues, isWifiConnected, saveFormClicke const connectionStatus = useMemo(() => { if (!values.wifi_profile.profile_id) return null if (hasChanged) { - return { message: m.saveToConnect, icon: 'save' } + return { message: m.saveToConnect, icon: 'info_outline' } } if (isWifiConnected) { if (values.wifi_profile._override) { return { message: m.connectedCollaborator, icon: 'check_circle_outline', - color: 'c-success', + color: style.connected, } } - return { message: m.connected, icon: 'check_circle_outline', color: 'c-success' } + return { message: m.connected, icon: 'check_circle_outline', color: style.connected } } if (!isWifiConnected) { if (saveFormClicked) { @@ -115,10 +119,10 @@ const WifiSettingsFormFields = ({ initialValues, isWifiConnected, saveFormClicke return { message: m.unableToConnectCollaborator, icon: 'highlight_remove', - color: 'c-error', + color: style.notConnected, } } - return { message: m.unableToConnect, icon: 'highlight_remove', color: 'c-error' } + return { message: m.unableToConnect, icon: 'highlight_remove', color: style.notConnected } } return null @@ -185,7 +189,7 @@ const WifiSettingsFormFields = ({ initialValues, isWifiConnected, saveFormClicke return ( <> - + {!values.wifi_profile._override ? ( <>
@@ -203,7 +207,7 @@ const WifiSettingsFormFields = ({ initialValues, isWifiConnected, saveFormClicke title={m.settingsProfile} component={Select} options={profileOptions} - tooltipId={tooltipIds.GATEWAY_SHOW_PROFILES} + tooltip={m.settingsProfileTooltip} placeholder={m.selectAProfile} onChange={handleProfileIdChange} /> @@ -213,14 +217,14 @@ const WifiSettingsFormFields = ({ initialValues, isWifiConnected, saveFormClicke {values.wifi_profile.profile_id.includes('shared') && ( )} ) : ( - <> +
)} {connectionStatus !== null && ( -
- - +
+
+ + +
+ {Boolean(values.wifi_profile.profile_id) && + !values.wifi_profile._override && + !values.wifi_profile.profile_id.includes('shared') && ( + + + + )}
)} - {Boolean(values.wifi_profile.profile_id) && - !values.wifi_profile._override && - !values.wifi_profile.profile_id.includes('shared') && ( - - - - )} ) } diff --git a/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/wifi-settings-form-fields.styl b/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/wifi-settings-form-fields.styl new file mode 100644 index 00000000000..f54c9cd673f --- /dev/null +++ b/pkg/webui/console/containers/gateway-managed-gateway/connection-settings/wifi-settings-form-fields.styl @@ -0,0 +1,45 @@ +// Copyright © 2024 The Things Network Foundation, The Things Industries B.V. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.connection + display: inline-flex + align-items: center + gap: $cs.xxs + padding: $cs.xxs $cs.s $cs.xxs $cs.xs + font-weight: $fw.bold + // TODO: Change color + background-color: #EEEFF9 + border-radius: $br.m + border-width: 1px + border-style: solid + border-color: $c-input-border + +.connected + border-color: $c-success + background-color: #e6ffe4 + + span + color: $c-success + +.notConnected + border-color: $c-error + background-color: #ffe4e4 + + span + color: $c-error + +.fieldDescription + color: $tc-subtle-gray + margin-bottom: $cs.m + margin-top: - $cs.m diff --git a/pkg/webui/console/containers/gateway-managed-gateway/shared/show-profiles-select.js b/pkg/webui/console/containers/gateway-managed-gateway/shared/show-profiles-select.js index 240a1e3108e..12b767a9e48 100644 --- a/pkg/webui/console/containers/gateway-managed-gateway/shared/show-profiles-select.js +++ b/pkg/webui/console/containers/gateway-managed-gateway/shared/show-profiles-select.js @@ -24,7 +24,6 @@ import RequireRequest from '@ttn-lw/lib/components/require-request' import { getValuesNormalized } from '@console/containers/gateway-managed-gateway/shared/utils' -import tooltipIds from '@ttn-lw/lib/constants/tooltip-ids' import { selectCollaboratorsEntitiesStore } from '@ttn-lw/lib/store/selectors/collaborators' import { getOrganizationId } from '@ttn-lw/lib/selectors/id' @@ -38,6 +37,8 @@ import { selectUserId } from '@account/store/selectors/user' const m = defineMessages({ showProfilesOf: 'Show profiles of', yourself: 'Yourself', + showProfilesOfTooltip: + 'Managed gateways can be setup with WiFi profiles shared within an organization. This dropdown allows you to select the source of the profiles applicable to this gateway. If you are a collaborator of an organization, you can select the organization to view its shared profiles.', }) const ShowProfilesSelect = ({ name, ...rest }) => { @@ -94,7 +95,7 @@ const ShowProfilesSelect = ({ name, ...rest }) => { component={Select} options={profileOptions} disabled={!Object.keys(organizations).length} - tooltipId={tooltipIds.GATEWAY_SHOW_PROFILES} + tooltip={m.showProfilesOfTooltip} {...rest} /> diff --git a/pkg/webui/console/containers/gateway-managed-gateway/shared/wifi-profiles-form-fields.js b/pkg/webui/console/containers/gateway-managed-gateway/shared/wifi-profiles-form-fields.js index 7c660a9d8cf..6d7a74f04ac 100644 --- a/pkg/webui/console/containers/gateway-managed-gateway/shared/wifi-profiles-form-fields.js +++ b/pkg/webui/console/containers/gateway-managed-gateway/shared/wifi-profiles-form-fields.js @@ -25,7 +25,6 @@ import AccessPointList from '@console/containers/access-point-list' import NetworkInterfaceAddressesFormFields from '@console/containers/gateway-managed-gateway/shared/network-interface-addresses-form-fields' import { getValuesNormalized } from '@console/containers/gateway-managed-gateway/shared/utils' -import tooltipIds from '@ttn-lw/lib/constants/tooltip-ids' import sharedMessages from '@ttn-lw/lib/shared-messages' const m = defineMessages({ @@ -113,7 +112,6 @@ const GatewayWifiProfilesFormFields = ({ namePrefix }) => { component={Checkbox} label={m.useDefaultNetworkInterfaceSettings} description={m.uncheckToSetCustomSettings} - tooltipId={tooltipIds.DEFAULT_NETWORK_INTERFACE} /> {!Boolean(valuesNormalized._default_network_interface) && ( diff --git a/pkg/webui/console/containers/gateway-managed-gateway/wifi-profiles/overview.js b/pkg/webui/console/containers/gateway-managed-gateway/wifi-profiles/overview.js index e8f78c1cb9e..c7e7ff91b27 100644 --- a/pkg/webui/console/containers/gateway-managed-gateway/wifi-profiles/overview.js +++ b/pkg/webui/console/containers/gateway-managed-gateway/wifi-profiles/overview.js @@ -18,7 +18,6 @@ import { createSelector } from 'reselect' import { useDispatch, useSelector } from 'react-redux' import { defineMessages } from 'react-intl' -import Link from '@ttn-lw/components/link' import Form from '@ttn-lw/components/form' import Button from '@ttn-lw/components/button' import ButtonGroup from '@ttn-lw/components/button/group' @@ -48,8 +47,9 @@ import { import { selectConnectionProfilesByType } from '@console/store/selectors/connection-profiles' const m = defineMessages({ + // TODO: This message should include a link to a documentation page that explains about managed gateways. information: - 'Connection profiles are setup to allow for multiple gateways to connect via the same settings. You can use this view to manage all your profiles or create new ones, after which you can assign them to your gateway.

Learn more about gateway network connection profiles.', + 'Connection profiles are setup to allow for multiple gateways to connect via the same settings. You can use this view to manage all your profiles or create new ones, after which you can assign them to your gateway.', profileId: 'Profile ID', accessPoint: 'Access point', deleteProfile: 'Delete profile', @@ -125,11 +125,9 @@ const GatewayWifiProfilesOverview = () => { }), render: details => ( -