diff --git a/src/client/app/components/RadarChartComponent.tsx b/src/client/app/components/RadarChartComponent.tsx index 35ff6d34e..faa9911f1 100644 --- a/src/client/app/components/RadarChartComponent.tsx +++ b/src/client/app/components/RadarChartComponent.tsx @@ -4,7 +4,6 @@ import { values } from 'lodash'; import * as moment from 'moment'; -import { Layout } from 'plotly.js'; import * as React from 'react'; import Plot from 'react-plotly.js'; import { Icons } from 'plotly.js'; @@ -26,6 +25,7 @@ import getGraphColor from '../utils/getGraphColor'; import { lineUnitLabel } from '../utils/graphics'; import { useTranslate } from '../redux/componentHooks'; import SpinnerComponent from './SpinnerComponent'; +import {setHelpLayout} from '../utils/setLayout'; /** * @returns radar plotly component @@ -189,31 +189,13 @@ export default function RadarChartComponent() { } } - let layout: Partial; + let layout = {}; // TODO See 3D code for functions that can be used for layout and notices. if (datasets.length === 0) { // There are no meters so tell user. // Customize the layout of the plot // See https://community.plotly.com/t/replacing-an-empty-graph-with-a-message/31497 for showing text not plot. - layout = { - 'xaxis': { - 'visible': false - }, - 'yaxis': { - 'visible': false - }, - 'annotations': [ - { - 'text': `${translate('select.meter.group')}`, - 'xref': 'paper', - 'yref': 'paper', - 'showarrow': false, - 'font': { - 'size': 28 - } - } - ] - }; + layout = setHelpLayout(translate('select.meter.group'), 28); } else { // Plotly scatterpolar plots have the unfortunate attribute that if a smaller number of plotting // points is done first then that impacts the labeling of the polar coordinate where you can get @@ -230,25 +212,7 @@ export default function RadarChartComponent() { // There is no data so tell user - likely due to date range outside where readings. // Remove plotting data even though none there is an empty r & theta that gives empty graphic. datasets.splice(0, datasets.length); - layout = { - 'xaxis': { - 'visible': false - }, - 'yaxis': { - 'visible': false - }, - 'annotations': [ - { - 'text': `${translate('radar.no.data')}`, - 'xref': 'paper', - 'yref': 'paper', - 'showarrow': false, - 'font': { - 'size': 28 - } - } - ] - }; + layout = setHelpLayout(translate('radar.no.data'),28); } else { // Check if all the values for the dates are compatible. Plotly does not like having different dates in different // scatterpolar lines. Lots of attempts to get this to work failed so not going to allow since not that common. @@ -265,25 +229,9 @@ export default function RadarChartComponent() { // Remove plotting data. datasets.splice(0, datasets.length); // The lines are not compatible so tell user. - layout = { - 'xaxis': { - 'visible': false - }, - 'yaxis': { - 'visible': false - }, - 'annotations': [ - { - 'text': `${translate('radar.lines.incompatible')}`, - 'xref': 'paper', - 'yref': 'paper', - 'showarrow': false, - 'font': { - 'size': 28 - } - } - ] - }; + //Change layout to use function from utils + //Then look at other chart components and do it similar way + layout = setHelpLayout(translate('radar.lines.incompatible'),28); } else { // Data available and okay so plot. // Maximum number of ticks, represents 12 months. Too many is cluttered so this seems good value. diff --git a/src/client/app/components/ThreeDComponent.tsx b/src/client/app/components/ThreeDComponent.tsx index 2310e8671..5598ef530 100644 --- a/src/client/app/components/ThreeDComponent.tsx +++ b/src/client/app/components/ThreeDComponent.tsx @@ -31,6 +31,7 @@ import Plot from 'react-plotly.js'; import { Icons } from 'plotly.js'; import { selectSelectedLanguage } from '../redux/slices/appStateSlice'; import Locales from '../types/locales'; +import {setHelpLayout} from '../utils/setLayout'; /** * Component used to render 3D graphics @@ -191,7 +192,6 @@ function formatThreeDData( const readingValue = readings === null ? null : readings.toPrecision(6); return `${translate('threeD.date')}: ${date}
${translate('threeD.time')}: ${time}
${unitLabel}: ${readingValue}`; })); - const formattedData = [{ type: 'surface', showlegend: false, @@ -206,39 +206,13 @@ function formatThreeDData( return [formattedData, layout]; } -/** - * Utility to get/ set help text plotlyLayout - * @param helpText 3D data to be formatted - * @param fontSize current application state - * @returns plotly layout object. - */ -function setHelpLayout(helpText: string = 'Help Text Goes Here', fontSize: number = 28) { - return { - 'xaxis': { - 'visible': false - }, - 'yaxis': { - 'visible': false - }, - 'annotations': [ - { - 'text': helpText, - 'xref': 'paper', - 'yref': 'paper', - 'showarrow': false, - 'font': { 'size': fontSize } - } - ] - }; -} - /** * Utility to get / set 3D graphic plotlyLayout * @param zLabelText 3D data to be formatted * @param yDataToRender Data range for yaxis * @returns plotly layout object. */ -function setThreeDLayout(zLabelText: string = 'Resource Usage', yDataToRender: string[]) { +export function setThreeDLayout(zLabelText: string = 'Resource Usage', yDataToRender: string[]) { // Convert date strings to JavaScript Date objects and then get dataRange const dateObjects = yDataToRender.map(dateStr => new Date(dateStr)); const dataMin = Math.min(...dateObjects.map(date => date.getTime())); @@ -296,3 +270,5 @@ function setThreeDLayout(zLabelText: string = 'Resource Usage', yDataToRender: s } as Partial; } + + diff --git a/src/client/app/components/groups/CreateGroupModalComponent.tsx b/src/client/app/components/groups/CreateGroupModalComponent.tsx index 5eddfe35f..fdbaf121a 100644 --- a/src/client/app/components/groups/CreateGroupModalComponent.tsx +++ b/src/client/app/components/groups/CreateGroupModalComponent.tsx @@ -197,7 +197,8 @@ export default function CreateGroupModalComponent() { // If the user input a value then gpsInput should be a string. // null came from the DB and it is okay to just leave it - Not a string. if (typeof gpsInput === 'string') { - if (isValidGPSInput(gpsInput)) { + const { validGps, message } = isValidGPSInput(gpsInput); + if (validGps) { // Clearly gpsInput is a string but TS complains about the split so cast. const gpsValues = (gpsInput as string).split(',').map((value: string) => parseFloat(value)); // It is valid and needs to be in this format for routing. @@ -207,10 +208,7 @@ export default function CreateGroupModalComponent() { }; // gpsInput must be of type string but TS does not think so so cast. } else if ((gpsInput as string).length !== 0) { - // GPS not okay. Only true if some input. - // TODO isValidGPSInput currently pops up an alert so not doing it here, may change - // so leaving code commented out. - // showErrorNotification(translate('input.gps.range') + state.gps + '.'); + showErrorNotification(message); inputOk = false; } } @@ -525,7 +523,7 @@ export default function CreateGroupModalComponent() { }); // Want chosen in sorted order. return selectedMetersUnsorted.sort((meterA, meterB) => meterA.label.toLowerCase()?. - localeCompare(meterB.label.toLowerCase(), String(locale), { sensitivity: 'accent'})); + localeCompare(meterB.label.toLowerCase(), String(locale), { sensitivity: 'accent' })); } /** @@ -545,7 +543,7 @@ export default function CreateGroupModalComponent() { }); // Want chosen in sorted order. return selectedGroupsUnsorted.sort((groupA, groupB) => groupA.label.toLowerCase()?. - localeCompare(groupB.label.toLowerCase(), String(locale), { sensitivity: 'accent'})); + localeCompare(groupB.label.toLowerCase(), String(locale), { sensitivity: 'accent' })); } /** diff --git a/src/client/app/components/groups/EditGroupModalComponent.tsx b/src/client/app/components/groups/EditGroupModalComponent.tsx index 04d9495ce..1a1568892 100644 --- a/src/client/app/components/groups/EditGroupModalComponent.tsx +++ b/src/client/app/components/groups/EditGroupModalComponent.tsx @@ -288,7 +288,8 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr // If the user input a value then gpsInput should be a string // null came from DB and it is okay to just leave it - Not a String. if (typeof gpsInput === 'string') { - if (isValidGPSInput(gpsInput)) { + const { validGps, message } = isValidGPSInput(gpsInput); + if (validGps) { // Clearly gpsInput is a string but TS complains about the split so cast. const gpsValues = (gpsInput as string).split(',').map((value: string) => parseFloat(value)); // It is valid and needs to be in this format for routing @@ -297,10 +298,7 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr latitude: gpsValues[latitudeIndex] }; } else if ((gpsInput as string).length !== 0) { - // GPS not okay and there since non-zero length value. - // TODO isValidGPSInput currently pops up an alert so not doing it here, may change - // so leaving code commented out. - // showErrorNotification(translate('input.gps.range') + groupState.gps + '.'); + showErrorNotification(message); inputOk = false; } } @@ -931,7 +929,7 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr }); // Want chosen in sorted order. return selectedMetersUnsorted.sort((meterA, meterB) => meterA.label.toLowerCase()?. - localeCompare(meterB.label.toLowerCase(), String(locale), { sensitivity: 'accent'})); + localeCompare(meterB.label.toLowerCase(), String(locale), { sensitivity: 'accent' })); } /** @@ -953,7 +951,7 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr }); // Want chosen in sorted order. return selectedGroupsUnsorted.sort((groupA, groupB) => groupA.label.toLowerCase()?. - localeCompare(groupB.label.toLowerCase(), String(locale), { sensitivity: 'accent'})); + localeCompare(groupB.label.toLowerCase(), String(locale), { sensitivity: 'accent' })); } /** @@ -977,7 +975,7 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr } }); // Sort for display. Before were sorted by id so not okay here. - listedMeters.sort((meterA, meterB) => meterA.toLowerCase().localeCompare(meterB.toLowerCase(), locale, { sensitivity : 'accent' })); + listedMeters.sort((meterA, meterB) => meterA.toLowerCase().localeCompare(meterB.toLowerCase(), locale, { sensitivity: 'accent' })); if (hasHidden) { // There are hidden meters so note at bottom of list. listedMeters.push(translate('meter.hidden')); @@ -1009,7 +1007,7 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr }); // Sort for display. Before were sorted by id so not okay here. listedGroups.sort((groupA, groupB) => groupA.toLowerCase().localeCompare( - groupB.toLowerCase(), locale, { sensitivity : 'accent' })); + groupB.toLowerCase(), locale, { sensitivity: 'accent' })); if (hasHidden) { // There are hidden groups so note at bottom of list. listedGroups.push(translate('group.hidden')); @@ -1038,7 +1036,7 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr }); // Sort for display. listedDeepMeters.sort((deepMeterA, deepMeterB) => deepMeterA.toLowerCase().localeCompare( - deepMeterB.toLowerCase(), locale, { sensitivity : 'accent' })); + deepMeterB.toLowerCase(), locale, { sensitivity: 'accent' })); if (hasHidden) { // There are hidden meters so note at bottom of list. // This should never happen to an admin. diff --git a/src/client/app/components/maps/MapCalibrationInfoDisplayComponent.tsx b/src/client/app/components/maps/MapCalibrationInfoDisplayComponent.tsx index 7e27aeede..6f57185b5 100644 --- a/src/client/app/components/maps/MapCalibrationInfoDisplayComponent.tsx +++ b/src/client/app/components/maps/MapCalibrationInfoDisplayComponent.tsx @@ -3,9 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import * as React from 'react'; -import {GPSPoint, isValidGPSInput} from '../../utils/calibration'; -import {ChangeEvent, FormEvent} from 'react'; -import {FormattedMessage} from 'react-intl'; +import { GPSPoint, isValidGPSInput } from '../../utils/calibration'; +import { ChangeEvent, FormEvent } from 'react'; +import { FormattedMessage } from 'react-intl'; interface InfoDisplayProps { showGrid: boolean; @@ -47,15 +47,15 @@ export default class MapCalibrationInfoDisplayComponent extends React.Component<