Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,16 @@ interface IProps {
Selected: TrendSearch.IMarker,
SetSelected: (marker: TrendSearch.IMarker) => void,
Height: number,
IsGlobal: boolean
IsGlobal: boolean,
XAxisType?: 'time' | 'value'
}

const TrendMarkerTable = (props: IProps) => {
const [trendMarkers, setTrendMarkers] = React.useState<TrendSearch.IMarker[]>([]);
const [sortField, setSortField] = React.useState<string>('MeterName');
const [ascending, setAscending] = React.useState<boolean>(true);
const momentFormat = "DD HH:mm:ss.SSS";

React.useEffect(() => {
setTrendMarkers(_.orderBy(props.Markers, sortField, (ascending ? 'asc' : 'desc')));
const trendMarkers: TrendSearch.IMarker[] = React.useMemo(() => {
return _.orderBy(props.Markers, sortField, (ascending ? 'asc' : 'desc'));
}, [props.Markers, sortField, ascending]);

const removeButton = React.useCallback(
Expand Down Expand Up @@ -117,9 +116,9 @@ const TrendMarkerTable = (props: IProps) => {
} else {
switch (row.item.type) {
case "VeHo":
return (row.item["isHori"] ?? true) ? row.item["value"].toFixed(2) : moment.utc(row.item["value"]).format(momentFormat);
return (row.item["isHori"] ?? true) ? row.item["value"].toFixed(2) : formatXValue(row.item["value"], props.XAxisType);
case "Symb":
return `${moment.utc(row.item["xPos"]).format(momentFormat)} | ${row.item["yPos"].toFixed(2)}`;
return `${formatXValue(row.item["xPos"], props.XAxisType)} | ${row.item["yPos"].toFixed(2)}`;
default:
return "All Events";
}
Expand All @@ -142,4 +141,7 @@ const TrendMarkerTable = (props: IProps) => {
);
}

const momentFormat = "DD HH:mm:ss.SSS";
const formatXValue = (value: number, xAxisType?: 'time' | 'value') => xAxisType === 'value' ? value.toFixed(2) : moment.utc(value).format(momentFormat);

export default TrendMarkerTable;

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//******************************************************************************************************
// HistogramPlotSettingsTab.tsx - Gbtc
//
// Copyright © 2026, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
// file except in compliance with the License. You may obtain a copy of the License at:
//
// http://opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 08/03/26 - Preston Crawford
// Generated original version of source code.
//
//******************************************************************************************************
import React from 'react';
import { IPlotSettingsProps, PlotSettingsTab } from './PlotSettingsTab';

const HistogramPlotSettingsTab = React.memo((props: IPlotSettingsProps) => (
<PlotSettingsTab {...props} ShowEvents={false} ShowAxisLimits={false} />
));

export { HistogramPlotSettingsTab };
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export interface IMarkerSettingsProps {
EventSettings: TrendSearch.EventMarkerSettings,
SetEventSettings: (setting: TrendSearch.EventMarkerSettings) => void,
DisplayEventSettings: boolean,
IsGlobalSettings: boolean
IsGlobalSettings: boolean,
XAxisType?: 'time' | 'value'
}
const EventOptions = [{ Label: "Vertical Lines", Value: "Event-Vert" }, { Label: "Custom Symbols", Value: "Event-Symb" }];
// Loading all SVGIcons into the options menue
Expand Down Expand Up @@ -125,10 +126,11 @@ const MarkerTab = React.memo((props: IMarkerSettingsProps) => {
<Input<TrendSearch.ISymbolic> Record={currentMarker as TrendSearch.ISymbolic} Label={'Infobox Opacity'} Field={'opacity'} Setter={state => applyToMarker(state, editFromArray)} Feedback={"Opacity must be between 0 and 1"} Valid={() => {
return (currentMarker['opacity'] <= 1 && currentMarker['opacity'] >= 0);
}} />
<Input<TrendSearch.ISymbolic> Record={currentMarker as TrendSearch.ISymbolic} Label={'Timestamp Format'} Field={'format'} Setter={state => applyToMarker(state, editFromArray)} Feedback={"Must be a valid timestamp format"} Valid={() => {
// TODO: This must be a valid string, something to check this should be added to helper functions in gemstone soon
return true;
}} />
{props.XAxisType === 'value' ? null :
<Input<TrendSearch.ISymbolic> Record={currentMarker as TrendSearch.ISymbolic} Label={'Timestamp Format'} Field={'format'} Setter={state => applyToMarker(state, editFromArray)} Feedback={"Must be a valid timestamp format"} Valid={() => {
// TODO: This must be a valid string, something to check this should be added to helper functions in gemstone soon
return true;
}} />}
<Input<TrendSearch.ISymbolic> Record={currentMarker as TrendSearch.ISymbolic} Label={'Note Text Size (em)'} Field={'fontSize'} Setter={state => applyToMarker(state, editFromArray)} Feedback={"Font size must be a positive number"} Valid={() => {
return currentMarker['fontSize'] > 0;
}} />
Expand Down Expand Up @@ -208,7 +210,7 @@ const MarkerTab = React.memo((props: IMarkerSettingsProps) => {
</> :
<></>
}
<TrendMarkerTable Height={markersHeight} Markers={allMarkers} IsGlobal={props.IsGlobalSettings}
<TrendMarkerTable Height={markersHeight} Markers={allMarkers} IsGlobal={props.IsGlobalSettings} XAxisType={props.XAxisType}
RemoveMarker={(marker) => applyToMarker(marker, removeFromArray)}
Selected={currentMarker} SetSelected={setCurrentMarker} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ export interface IPlotSettingsProps {
Plot: TrendSearch.ITrendPlot,
SetPlot: (record: TrendSearch.ITrendPlot) => void,
SetConfirmDisabled: (record: boolean) => void,
IsGlobalSettings: boolean
IsGlobalSettings: boolean,
ShowEvents?: boolean,
ShowAxisLimits?: boolean
}

interface AxisLimits { LeftUpper: number, LeftLower: number, RightUpper: number, RightLower: number }
Expand Down Expand Up @@ -118,7 +120,8 @@ const PlotSettingsTab = React.memo((props: IPlotSettingsProps) => {
}

function isValid(): boolean {
return validateTrendPlot('Height') && validateTrendPlot('Width') && validateLimit("LeftUpper") && validateLimit("RightUpper");
const limitsAreValid = !(props.ShowAxisLimits ?? true) || (validateLimit("LeftUpper") && validateLimit("RightUpper"));
return validateTrendPlot('Height') && validateTrendPlot('Width') && limitsAreValid;
}

return (
Expand Down Expand Up @@ -193,46 +196,50 @@ const PlotSettingsTab = React.memo((props: IPlotSettingsProps) => {
<div className="row">
<CheckBox<TrendSearch.ITrendPlot> Record={props.Plot} Label='Use Metric Abbreviation' Field='Metric' Setter={props.SetPlot} />
</div>
<div className="row">
<CheckBox<TrendSearch.ITrendPlot> Record={props.Plot} Label='Display Events' Field='ShowEvents' Setter={props.SetPlot} />
</div>
{(props.ShowEvents ?? true) ?
<div className="row">
<CheckBox<TrendSearch.ITrendPlot> Record={props.Plot} Label='Display Events' Field='ShowEvents' Setter={props.SetPlot} />
</div>
: null}
</div>
</fieldset>
</div>
<div className="col" style={{ width: '50%', height: "100%" }}>
<TimeFilter filter={toGemstoneFilter(props.Plot.TimeFilter)} showQuickSelect={false}
setFilter={(start, end, unit, duration) => props.SetPlot({ ...props.Plot, TimeFilter: fromGemstoneFilter(start, end, unit, duration) })}
dateTimeSetting={dateTimeSetting} timeZone={timeZone} />
<fieldset className="border" style={{ padding: '10px', height: '100%' }}>
<legend className="w-auto" style={{ fontSize: 'large' }}>Axis Limits:</legend>
<div className="row">
<div className="col">
<Select<TrendSearch.ITrendPlot> Record={props.Plot} Setter={props.SetPlot} Field='AxisZoom' Options={axisOptions} Label=''
EmptyOption={false} Help={"Selects range of plot."}
/>
</div>
</div>
<div className="row">
<div className="col" style={{ width: '50%' }}>
<Input<AxisLimits> Record={limits} Setter={setPlotLimits} Valid={validateLimit} Feedback={limitFeedback}
Label='Left Axis Lower' Field='LeftLower' Type='integer' Disabled={props.Plot.AxisZoom !== 'Manual'} />
</div>
<div className="col" style={{ width: '50%' }}>
<Input<AxisLimits> Record={limits} Setter={setPlotLimits} Valid={validateLimit} Feedback={limitFeedback}
Label='Left Axis Upper' Field='LeftUpper' Type='integer' Disabled={props.Plot.AxisZoom !== 'Manual'}/>
{(props.ShowAxisLimits ?? true) ?
<fieldset className="border" style={{ padding: '10px', height: '100%' }}>
<legend className="w-auto" style={{ fontSize: 'large' }}>Axis Limits:</legend>
<div className="row">
<div className="col">
<Select<TrendSearch.ITrendPlot> Record={props.Plot} Setter={props.SetPlot} Field='AxisZoom' Options={axisOptions} Label=''
EmptyOption={false} Help={"Selects range of plot."}
/>
</div>
</div>
</div>
<div className="row">
<div className="col" style={{ width: '50%' }}>
<Input<AxisLimits> Record={limits} Setter={setPlotLimits} Valid={validateLimit} Feedback={limitFeedback}
Label='Right Axis Lower' Field='RightLower' Type='integer' Disabled={props.Plot.AxisZoom !== 'Manual'}/>
<div className="row">
<div className="col" style={{ width: '50%' }}>
<Input<AxisLimits> Record={limits} Setter={setPlotLimits} Valid={validateLimit} Feedback={limitFeedback}
Label='Left Axis Lower' Field='LeftLower' Type='integer' Disabled={props.Plot.AxisZoom !== 'Manual'} />
</div>
<div className="col" style={{ width: '50%' }}>
<Input<AxisLimits> Record={limits} Setter={setPlotLimits} Valid={validateLimit} Feedback={limitFeedback}
Label='Left Axis Upper' Field='LeftUpper' Type='integer' Disabled={props.Plot.AxisZoom !== 'Manual'}/>
</div>
</div>
<div className="col" style={{ width: '50%' }}>
<Input<AxisLimits> Record={limits} Setter={setPlotLimits} Valid={validateLimit} Feedback={limitFeedback}
Label='Right Axis Upper' Field='RightUpper' Type='integer' Disabled={props.Plot.AxisZoom !== 'Manual'}/>
<div className="row">
<div className="col" style={{ width: '50%' }}>
<Input<AxisLimits> Record={limits} Setter={setPlotLimits} Valid={validateLimit} Feedback={limitFeedback}
Label='Right Axis Lower' Field='RightLower' Type='integer' Disabled={props.Plot.AxisZoom !== 'Manual'}/>
</div>
<div className="col" style={{ width: '50%' }}>
<Input<AxisLimits> Record={limits} Setter={setPlotLimits} Valid={validateLimit} Feedback={limitFeedback}
Label='Right Axis Upper' Field='RightUpper' Type='integer' Disabled={props.Plot.AxisZoom !== 'Manual'}/>
</div>
</div>
</div>
</fieldset>
</fieldset>
: null}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ const SettingsModal = React.memo((props: IOverlayProps) => {
SetEventSettings={setEventBuffer}
DisplayEventSettings={plotBuffer?.ShowEvents ?? false}
IsGlobalSettings={false}
XAxisType={plotBuffer?.Type === 'Histogram' ? 'value' : 'time'}
/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion SEBrowser/Scripts/TSX/Components/TrendData/TrendData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import React from 'react';
import _ from 'lodash';
import TrendSearchNavbar from './NavBar/TrendDataNavbar';
import TrendPlot from './TrendPlot/TrendPlot';
import TrendPlot from './TrendPlot/TrendWidgetWrapper';
import { TrendSearch } from '../../global';
import AllSettingsModal from './Settings/AllSettingsModal';
import { SelectTrendDataSettings } from '../../Store/SettingsSlice';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { parseTrendDataResponse, requestTrendData } from '../Utils/TrendDataRequ

const binCount = 10;

const seriesTypes = ['Minimum', 'Average', 'Maximum'] as const;
const seriesTypes = ['Minimum', 'Average', 'Maximum'];

type SeriesType = typeof seriesTypes[number];

Expand Down Expand Up @@ -182,6 +182,7 @@ const Histogram = React.memo((props: ITrendWidgetProps) => {
width={series.Settings.Width}
/>
)}
{props.Overlays}
{props.Controls}
</Plot>
<ToolTip Show={hover} Position="bottom" Target={props.ID}>Selected Channels have no finite data for the selected Time Window.</ToolTip>
Expand Down
Loading