From 41672850b9191d4fe9323ab0b82dbf1f46c2792d Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 9 Aug 2024 11:37:21 -0400 Subject: [PATCH 01/50] Added LocationDrawing button to AssetConnection page --- .../Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index 3ee655c7e..f5282ee14 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -31,6 +31,7 @@ import { OpenXDA } from '@gpa-gemstone/application-typings'; import { useAppSelector, useAppDispatch } from '../hooks'; import { AssetConnectionTypeSlice } from '../Store/Store'; import { SelectRoles } from '../Store/UserSettings'; +import LocationDrawings from '../Meter/PropertyUI/LocationDrawings' interface AssetConnection { AssetRelationShipTypeID: number, @@ -233,9 +234,12 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number
-
+

Connections:

+
+ +
From e34966d69dbe0bb4e9109f83d366bc8ca3302cdd Mon Sep 17 00:00:00 2001 From: collins-self Date: Tue, 13 Aug 2024 10:21:38 -0400 Subject: [PATCH 02/50] Added to nmw and fixed styling --- .../Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx | 6 +++--- .../TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index f5282ee14..eb3b55553 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -233,12 +233,12 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number return (
-
-
+
+

Connections:

- +
diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 8ecc8622b..4da2e8fb7 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -403,7 +403,9 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { return

Number of Trend Channels: {channels.reduce((p, c) => c.Trend ? (p + 1) : p, 0)}

; - else if (currentStep === assetStep) + else if (currentStep === assetStep + || currentStep === connectionStep + ) return else if (currentStep >= additionalFieldMeterStep) { return ( @@ -507,11 +509,11 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) {
-
+

{header}

-
+
{secondaryHeader}
From 4d658af647e1db8fc0fedfc3baabaa2fa003a7d0 Mon Sep 17 00:00:00 2001 From: collins-self Date: Thu, 15 Aug 2024 14:47:44 -0400 Subject: [PATCH 03/50] Made the locations an array of locations and btndropdown --- .../Meter/PropertyUI/LocationDrawings.tsx | 103 +++++++++++++----- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index 2b5752ec3..dc5cb01c1 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -1,7 +1,7 @@ //****************************************************************************************************** // LocationDrawings.tsx - Gbtc // -// Copyright © 2023, Grid Protection Alliance. All Rights Reserved. +// Copyright � 2023, 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. @@ -25,13 +25,14 @@ import * as React from 'react'; import { SystemCenter } from '@gpa-gemstone/application-typings' import { LocationDrawingSlice } from '../../Store/Store'; -import { Modal, ToolTip } from '@gpa-gemstone/react-interactive'; -import { Table, Column } from '@gpa-gemstone/react-table'; +import { BtnDropdown, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; +import { ReactTable } from '@gpa-gemstone/react-table'; import { useAppDispatch, useAppSelector } from '../../hooks'; import { CreateGuid } from '@gpa-gemstone/helper-functions'; interface IProps { - LocationID: number | null + LocationID: number[]; + LocationLabels?: string[]; } const LocationDrawings = (props: IProps) => { @@ -44,29 +45,80 @@ const LocationDrawings = (props: IProps) => { const drawingSortKey = useAppSelector(LocationDrawingSlice.SortField); const drawingAscending = useAppSelector(LocationDrawingSlice.Ascending); + const [selectedLocation, setSelectedLocation] = React.useState(); const [showDrawings, setShowDrawings] = React.useState(false); const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); React.useEffect(() => { - if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != props.LocationID) - dispatch(LocationDrawingSlice.Fetch(props.LocationID)); + if (props.LocationID != null) + setSelectedLocation(null); + if (props.LocationID.length == 1) + setSelectedLocation(props.LocationID[0]); + }, [props.LocationID]) + + React.useEffect(() => { + if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation ) + dispatch(LocationDrawingSlice.Fetch(selectedLocation)); }, [drawingStatus, drawingParentID, props.LocationID]); + function disableDropdownOption() { + return false; + } + + function dropdownOptions(): {Label: string; Callback: () => void; Disabled: boolean;}[] { + if (props.LocationLabels != null) { + const options: { + Label: string; + Callback: () => void; + Disabled: boolean; }[] = []; + for (const label of props.LocationLabels) { + options.push({ + Label: label, + Disabled: disableDropdownOption(), + Callback: () => { + if (selectedLocation != 0 && drawingData.length != 0) setShowDrawings(true) + } + }); + } + return options; + } + return [{Label: 'No labels given for options', Callback: () => {}, Disabled: false}]; + } + return (
- + +

No drawings associated with this substation.

+
+ + : { + if (selectedLocation != 0 && drawingData.length != 0) setShowDrawings(true); - }}>Open Drawing(s) + } + } + Options={dropdownOptions()} + /> + } setShowDrawings(false)} ShowCancel={false} ConfirmText={'Done'}>
- + TableClass="table table-hover" Data={drawingData} SortKey={drawingSortKey} @@ -81,47 +133,42 @@ const LocationDrawings = (props: IProps) => { Selected={(item) => false} KeySelector={(item) => item.ID} > - + Key={'Name'} AllowSort={true} Field={'Name'} HeaderStyle={{ width: 'auto' }} RowStyle={{ width: 'auto' }} > Name - - + + Key={'Description'} AllowSort={true} Field={'Description'} HeaderStyle={{ width: 'auto' }} RowStyle={{ width: 'auto' }} > Description - - + + Key={'Number'} AllowSort={true} Field={'Number'} HeaderStyle={{ width: '15%' }} RowStyle={{ width: '15%' }} > Number - - + + Key={'Category'} AllowSort={true} Field={'Category'} HeaderStyle={{ width: '15%' }} RowStyle={{ width: '15%' }} > Category - - + +
- - -

No drawings associated with this substation.

-
) } From 22a0e1b1fe89a6a96edc5e8864366066c8cae3b7 Mon Sep 17 00:00:00 2001 From: collins-self Date: Thu, 15 Aug 2024 14:49:33 -0400 Subject: [PATCH 04/50] Added getLocations() --- .../SystemCenter/Asset/AssetConnection.tsx | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index eb3b55553..4b3757c38 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -52,6 +52,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number const [selectedAssetID, setSelectedAssetID] = React.useState(0); const [selectedTypeID, setSelectedtypeID] = React.useState(0); const [localAssets, setLocalAssets] = React.useState>([]); + const [locations, setLocations] = React.useState([]); const [sortKey, setSortKey] = React.useState('AssetKey'); const [ascending, setAscending] = React.useState(true); @@ -64,11 +65,6 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number const [hover, setHover] = React.useState<('Update' | 'Reset' | 'None')>('None'); const roles = useAppSelector(SelectRoles); - React.useEffect(() => { - let handle = getAssetConnections(); - return () => { if (handle != null || handle.abort != null) handle.abort();} - }, [props.ID, trigger]) - React.useEffect(() => { if (props.ID > 0) { let sqlString = `(SELECT AssetRelationshipTypeID FROM AssetRelationshipTypeAssetType LEFT JOIN Asset ON ` @@ -107,7 +103,27 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number if (index == -1 && localAssets.length > 0) setSelectedAssetID(localAssets[0].ID) }, [localAssets]) - + + React.useEffect(() => { + let handle = getAssetConnections(); + return () => { if (handle != null || handle.abort != null) handle.abort();} + }, [props.ID, trigger]) + + React.useEffect(() => { + getLocations(); + }, [assetConnections]) + + function getLocations(): void { + $.ajax({ + type: "GET", + url: `${homePath}api/OpenXDA/Asset/${props.ID}/Locations`, + contentType: "application/json; charset=utf-8", + dataType: 'json', + cache: true, + async: true + }).done(data => setLocations(data)); + } + function getAssetConnections(): JQuery.jqXHR { setStatus('loading'); return $.ajax({ @@ -182,7 +198,6 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number }); } - function handleSelect(item) { history.push({ pathname: homePath + 'index.cshtml', search: '?name=Asset&AssetID=' + item.row.AssetID}) } @@ -238,7 +253,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number

Connections:

- +
@@ -360,7 +375,6 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number
}
- ); } From a3e19740f33f88108276ceff79ae6a50ee55d128 Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 4 Oct 2024 12:04:19 -0400 Subject: [PATCH 05/50] Updated LocationDrawing functionality, does not work still --- .../SystemCenter/Asset/AssetConnection.tsx | 31 +- .../Meter/PropertyUI/LocationDrawings.tsx | 109 ++-- .../PropertyUI/MeterLocationProperties.tsx | 26 +- .../SystemCenter/NewMeterWizard/AssetPage.tsx | 505 +++++++++--------- .../NewMeterWizard/NewMeterWizard.tsx | 89 ++- 5 files changed, 364 insertions(+), 396 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index 4b3757c38..d8ce5b299 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -41,8 +41,7 @@ interface AssetConnection { AssetName: string } -function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number}): JSX.Element{ - +function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number }): JSX.Element { let history = useHistory(); let dispatch = useAppDispatch(); @@ -52,7 +51,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number const [selectedAssetID, setSelectedAssetID] = React.useState(0); const [selectedTypeID, setSelectedtypeID] = React.useState(0); const [localAssets, setLocalAssets] = React.useState>([]); - const [locations, setLocations] = React.useState([]); + const [locations, setLocations] = React.useState([]); const [sortKey, setSortKey] = React.useState('AssetKey'); const [ascending, setAscending] = React.useState(true); @@ -68,19 +67,19 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number React.useEffect(() => { if (props.ID > 0) { let sqlString = `(SELECT AssetRelationshipTypeID FROM AssetRelationshipTypeAssetType LEFT JOIN Asset ON ` - sqlString = sqlString + `Asset.AssetTypeID <> ${props.TypeID} AND Asset.AssetTypeID = AssetRelationshipTypeAssetType.assetTypeID AND ` - sqlString = sqlString + `Asset.ID IN (SELECT AssetID FROM AssetLocation WHERE LocationID IN (Select LocationID FROM AssetLocation WHERE AssetID = ${props.ID})) ` - sqlString = sqlString + `GROUP BY AssetRelationshipTypeAssetType.AssetTypeID, AssetRelationshipTypeAssetType.AssetRelationshipTypeID ` - sqlString = sqlString + `HAVING COUNT(Asset.ID) > 0)` + sqlString = sqlString + `Asset.AssetTypeID <> ${props.TypeID} AND Asset.AssetTypeID = AssetRelationshipTypeAssetType.assetTypeID AND ` + sqlString = sqlString + `Asset.ID IN (SELECT AssetID FROM AssetLocation WHERE LocationID IN (Select LocationID FROM AssetLocation WHERE AssetID = ${props.ID})) ` + sqlString = sqlString + `GROUP BY AssetRelationshipTypeAssetType.AssetTypeID, AssetRelationshipTypeAssetType.AssetRelationshipTypeID ` + sqlString = sqlString + `HAVING COUNT(Asset.ID) > 0)` const filter: Search.IFilter[] = [ { FieldName: 'ID', SearchText: `(SELECT AssetRelationshipTypeID FROM AssetRelationshipTypeAssetType WHERE AssetTypeID = ${props.TypeID})`, Operator: 'IN', Type: 'query', IsPivotColumn: false }, { FieldName: 'ID', SearchText: sqlString, Operator: 'IN', Type: 'query', IsPivotColumn: false } - ] + ] dispatch(AssetConnectionTypeSlice.DBSearch({ filter: filter })) } - }, [props.TypeID]) + }, [props.TypeID]) React.useEffect(() => { if (selectedTypeID == 0) { @@ -94,7 +93,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number React.useEffect(() => { let index = assetConnectionTypes.findIndex(t => t.ID == selectedTypeID); - if (index == -1 && assetConnectionTypes.length> 0) + if (index == -1 && assetConnectionTypes.length > 0) setSelectedtypeID(assetConnectionTypes[0].ID) }, [assetConnectionTypes]) @@ -106,7 +105,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number React.useEffect(() => { let handle = getAssetConnections(); - return () => { if (handle != null || handle.abort != null) handle.abort();} + return () => { if (handle != null || handle.abort != null) handle.abort(); } }, [props.ID, trigger]) React.useEffect(() => { @@ -188,7 +187,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number url: `${homePath}api/OpenXDA/AssetConnection/Add`, contentType: "application/json; charset=utf-8", dataType: 'json', - data: JSON.stringify({ ID: 0, AssetRelationshipTypeID: selectedTypeID, ParentID: props.ID, ChildID: selectedAssetID}), + data: JSON.stringify({ ID: 0, AssetRelationshipTypeID: selectedTypeID, ParentID: props.ID, ChildID: selectedAssetID }), cache: false, async: true }).done(() => { @@ -199,7 +198,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number } function handleSelect(item) { - history.push({ pathname: homePath + 'index.cshtml', search: '?name=Asset&AssetID=' + item.row.AssetID}) + history.push({ pathname: homePath + 'index.cshtml', search: '?name=Asset&AssetID=' + item.row.AssetID }) } function hasPermissions(): boolean { @@ -226,7 +225,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number
- if (status == 'loading' || actStatus == 'loading' ) + if (status == 'loading' || actStatus == 'loading') return
@@ -253,7 +252,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number

Connections:

- +
@@ -323,7 +322,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number e.stopPropagation(); if (hasPermissions()) deleteAssetConnection(item); }}>{TrashCan} - } + } >

diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index dc5cb01c1..aaa71a957 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -23,7 +23,7 @@ import * as React from 'react'; -import { SystemCenter } from '@gpa-gemstone/application-typings' +import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings' import { LocationDrawingSlice } from '../../Store/Store'; import { BtnDropdown, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; import { ReactTable } from '@gpa-gemstone/react-table'; @@ -31,9 +31,9 @@ import { useAppDispatch, useAppSelector } from '../../hooks'; import { CreateGuid } from '@gpa-gemstone/helper-functions'; interface IProps { - LocationID: number[]; - LocationLabels?: string[]; + Locations: OpenXDA.Types.Location[]; } +type dropdownOption = { Label: string; Callback: () => void; Disabled: boolean; } const LocationDrawings = (props: IProps) => { const dispatch = useAppDispatch(); @@ -50,68 +50,65 @@ const LocationDrawings = (props: IProps) => { const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); React.useEffect(() => { - if (props.LocationID != null) + if (props.Locations != null) setSelectedLocation(null); - if (props.LocationID.length == 1) - setSelectedLocation(props.LocationID[0]); - }, [props.LocationID]) + if (props.Locations.length == 1) + setSelectedLocation(props.Locations[0].ID); + else { + setSelectedLocation(); + } + }, [props.Locations]) - React.useEffect(() => { - if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation ) + React.useEffect(() => { // Does this properly grab the drawingData to show? + if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) dispatch(LocationDrawingSlice.Fetch(selectedLocation)); - }, [drawingStatus, drawingParentID, props.LocationID]); + }, [drawingStatus, drawingParentID, props.Locations]); - function disableDropdownOption() { - return false; - } - - function dropdownOptions(): {Label: string; Callback: () => void; Disabled: boolean;}[] { - if (props.LocationLabels != null) { - const options: { - Label: string; - Callback: () => void; - Disabled: boolean; }[] = []; - for (const label of props.LocationLabels) { - options.push({ - Label: label, - Disabled: disableDropdownOption(), - Callback: () => { - if (selectedLocation != 0 && drawingData.length != 0) setShowDrawings(true) - } - }); - } - return options; + function dropdownOptions(): dropdownOption[] { + const options: dropdownOption[] = []; + const labels: string[] = props.Locations.map(loc => loc.Name); + for (const label of labels) { + options.push({ + Label: label, + Disabled: false, + Callback: () => { + if (selectedLocation != 0 && drawingData.length != 0) + setShowDrawings(true) + } + }); } - return [{Label: 'No labels given for options', Callback: () => {}, Disabled: false}]; + return options; } return (
- {props.LocationID != null && props.LocationID.length <= 1 ? - <> - - -

No drawings associated with this substation.

-
- - : { - if (selectedLocation != 0 && drawingData.length != 0) - setShowDrawings(true); - } - } - Options={dropdownOptions()} + {props.Locations.length <= 1 ? // There is one Location or zero, show button to drawing or disabled + <> + + +

No drawings associated with this substation.

+
+ + : { }} + Options={dropdownOptions()} /> } diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx index c331cfa1d..501353b83 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx @@ -145,11 +145,11 @@ const MeterLocationProperties = (props: IProps) => {

Your role does not have permission. Please contact your Administrator if you believe this to be in error.

- - Record={props.Location} Field={'LocationKey'} + + Record={props.Location} Field={'LocationKey'} Label={'Key'} Feedback={'A unique key of less than 50 characters is required.'} - Valid={valid} + Valid={valid} Setter={(loc) => props.SetLocation(loc)} Disabled={!hasPermissions() || props.DisableLocation} /> Record={props.Location} Field={'Name'} @@ -165,25 +165,25 @@ const MeterLocationProperties = (props: IProps) => {
- +
- Record={props.Location} - Field={'Alias'} Label={'Alias'} Feedback={'Alias must be less than 200 characters.'} + Record={props.Location} + Field={'Alias'} Label={'Alias'} Feedback={'Alias must be less than 200 characters.'} Valid={valid} Setter={(loc) => props.SetLocation(loc)} Disabled={!hasPermissions() || props.DisableLocation} /> - Record={props.Location} - Field={'Latitude'} Label={'Latitude'} - Feedback={'A numeric Latitude value between -180 and 180 is required.'} + Record={props.Location} + Field={'Latitude'} Label={'Latitude'} + Feedback={'A numeric Latitude value between -180 and 180 is required.'} Valid={valid} Setter={(loc) => props.SetLocation(loc)} Disabled={!hasPermissions() || props.DisableLocation} /> - Record={props.Location} Field={'Longitude'} Label={'Longitude'} - Feedback={'A numeric Longitude value between -180 and 180 is required.'} + Record={props.Location} Field={'Longitude'} Label={'Longitude'} + Feedback={'A numeric Longitude value between -180 and 180 is required.'} Valid={valid} Setter={(loc) => props.SetLocation(loc)} Disabled={!hasPermissions() || props.DisableLocation} /> - Rows={3} Record={props.Location} Field={'Description'} Label={'Description'} + Rows={3} Record={props.Location} Field={'Description'} Label={'Description'} Valid={valid} Setter={(loc) => props.SetLocation(loc)} Disabled={!hasPermissions() || props.DisableLocation} />
- { diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index 874f68247..91c0752dd 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -42,7 +42,7 @@ import { ReactIcons } from '@gpa-gemstone/gpa-symbols'; import { getAssetWithAdditionalFields } from '../../../TS/Services/Asset'; import LocationDrawings from '../Meter/PropertyUI/LocationDrawings'; import { GetNodeSize } from '@gpa-gemstone/helper-functions'; -import { Table, Column } from '@gpa-gemstone/react-table'; +import { ReactTable } from '@gpa-gemstone/react-table'; import GenerationAttributes from '../AssetAttribute/Generation'; import StationAuxAttributes from '../AssetAttribute/StationAux'; import StationBatteryAttributes from '../AssetAttribute/StationBattery'; @@ -76,6 +76,7 @@ export default function AssetPage(props: IProps) { const byAssetStatus = useAppSelector(ByAssetSlice.Status); const detailedAssets = useAppSelector(ByAssetSlice.Data); + const [newEditAsset, setNewEditAsset] = React.useState(AssetAttributes.getNewAsset('Line')); const [editAssetKey, setEditAssetKey] = React.useState(''); const [newEdit, setNewEdit] = React.useState<'New' | 'Edit'>('New'); @@ -109,7 +110,7 @@ export default function AssetPage(props: IProps) { const assetData = React.useMemo(() => { const u = _.cloneDeep(props.Assets); if (sortKey === 'Channels') - u.sort((a, b) => (asc? 1 : -1)* (a.Channels.length > b.Channels.length ? 1 : -1)); + u.sort((a, b) => (asc ? 1 : -1) * (a.Channels.length > b.Channels.length ? 1 : -1)); else return _.orderBy(u, [sortKey], [asc ? 'asc' : 'desc']); return u; @@ -208,7 +209,7 @@ export default function AssetPage(props: IProps) { } } - else if (newEditAsset.AssetType == 'Line'){ + else if (newEditAsset.AssetType == 'Line') { let handle = getLineSegment(newEditAsset.ID); handle.done((lineSegment: OpenXDA.Types.LineDetail) => { let record = _.cloneDeep(newEditAsset as OpenXDA.Types.Line); @@ -222,12 +223,12 @@ export default function AssetPage(props: IProps) { setNewEditAsset(record); }); - return () => { - if (handle.abort !== undefined) handle.abort(); - } - + return () => { + if (handle.abort !== undefined) handle.abort(); } + } + }, [newEditAsset.AssetType]); @@ -256,7 +257,7 @@ export default function AssetPage(props: IProps) { assetConnections.splice(index, 1); index = assetConnections.findIndex(assetConnection => assetConnection.Parent == record[0].AssetKey || assetConnection.Child == record[0].AssetKey); } - + props.UpdateAssets(list); props.UpdateChannels(channels); props.UpdateAssetConnections(assetConnections); @@ -264,7 +265,7 @@ export default function AssetPage(props: IProps) { } function getDifferentAsset(assetID: number): void { - let assetTypeID = assets.find(a => a.ID == assetID)['AssetTypeID']; + let assetTypeID = assets.find(a => a.ID == assetID)['AssetTypeID']; let assetType = assetTypes.find(at => at.ID == assetTypeID) $.ajax({ type: "GET", @@ -304,19 +305,19 @@ export default function AssetPage(props: IProps) { function showAttributes(): JSX.Element { if (newEditAsset.AssetType == 'Breaker') - return 0}/>; + return 0} />; else if (newEditAsset.AssetType == 'Bus') - return ; + return ; else if (newEditAsset.AssetType == 'CapacitorBank') - return 0}/>; + return 0} />; else if (newEditAsset.AssetType == 'CapacitorBankRelay') - return 0}/>; + return 0} />; else if (newEditAsset.AssetType == 'Line') - return 0}/>; + return 0} />; else if (newEditAsset.AssetType == 'Transformer') - return 0}/>; + return 0} />; else if (newEditAsset.AssetType == 'DER') - return 0}/>; + return 0} />; else if (newEditAsset.AssetType == 'Generation') return ; else if (newEditAsset.AssetType == 'StationAux') @@ -325,266 +326,238 @@ export default function AssetPage(props: IProps) { return ; } - return ( -
-
-
-
    -
    -
    - setShowSeries(s => !s)} - value={showSeries ? 'on' : 'off'} - checked={showSeries} - /> - -
    -
    - { - props.Channels.map((channel) => -
  • 0 ? 'line-through' : null) }} key={channel.ID}> - { - channel.Name + - (channel.Name !== channel.Description ? ` - ${channel.Description}` : '') + - ((showSeries && channel.Series.length > 0 && channel.Series[0].SourceIndexes !== '' ) ? ` (${channel.Series[0].SourceIndexes})` : '') - } -
  • - ) - } -
-
-
-
-
-
-
- - -
+ return ( +
+
+
+
    + { + props.Channels.map((channel) =>
  • 0 ? 'line-through' : null) }} key={channel.ID}>{channel.Name + ' - ' + channel.Description}
  • ) + } +
+
+
+
+
+
+
+ +
-
-
- - TableClass="table table-hover" - Data={assetData} - SortKey={sortKey} - Ascending={asc} - OnSort={(d) => { - if (d.colKey == 'Buttons') - return; - if (d.colKey === sortKey) - setAsc((x) => !x); - else - setAsc(false); - setSortKey(d.colKey); - }} - TableStyle={{ padding: 0, width: 'calc(100%)', tableLayout: 'fixed', height: 'calc(100% - 16px)', overflow: 'hidden', display: 'flex', flexDirection: 'column' }} - TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} - TbodyStyle={{ display: 'block', overflowY: 'scroll', flex: 1 }} - RowStyle={{ display: 'table', tableLayout: 'fixed', width: '100%' }} - Selected={(item) => false} - KeySelector={(item) => item.AssetKey} - > - - Key={'Status'} - AllowSort={true} - HeaderStyle={{ width: '10%' }} - RowStyle={{ width: '10%' }} - Content={({ item }) => item.ID == 0 ? 'New' : 'Existing' } - > Status - - - Key={'AssetKey'} - AllowSort={true} - Field={'AssetKey'} - HeaderStyle={{ width: '20%' }} - RowStyle={{ width: '20%' }} - > Key - - - Key={'AssetName'} - AllowSort={true} - Field={'AssetName'} - HeaderStyle={{ width: '30%' }} - RowStyle={{ width: '30%' }} - > Name - - - Key={'AssetType'} - AllowSort={true} - Field={'AssetType'} - HeaderStyle={{ width: '10%' }} - RowStyle={{ width: '10%' }} - > Type - - - Key={'VoltageKV'} - AllowSort={true} - Field={'VoltageKV'} - HeaderStyle={{ width: '10%' }} - RowStyle={{ width: '10%' }} - > kV - - - Key={'Channels'} - AllowSort={true} - Field={'Channels'} - HeaderStyle={{ width: '10%' }} - RowStyle={{ width: '10%' }} - Content={({ item }) => item.Channels.length } - > Channels - - - Key={'Buttons'} - AllowSort={false} - HeaderStyle={{ width: '10%' }} - RowStyle={{ width: '10%' }} - Content={({ index }) => <> - - - } - >

- - -
+
+
+
+ + TableClass="table table-hover" + Data={assetData} + SortKey={sortKey} + Ascending={asc} + OnSort={(d) => { + if (d.colKey == 'Buttons') + return; + if (d.colKey === sortKey) + setAsc((x) => !x); + else + setAsc(false); + setSortKey(d.colKey); + }} + TableStyle={{ padding: 0, width: 'calc(100%)', tableLayout: 'fixed', height: 'calc(100% - 16px)', overflow: 'hidden', display: 'flex', flexDirection: 'column' }} + TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} + TbodyStyle={{ display: 'block', overflowY: 'scroll', flex: 1 }} + RowStyle={{ display: 'table', tableLayout: 'fixed', width: '100%' }} + Selected={(item) => false} + KeySelector={(item) => item.ID} + > + + Key={'Status'} + AllowSort={true} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + Content={({ item }) => item.ID == 0 ? 'New' : 'Existing'} + > Status + + + Key={'AssetKey'} + AllowSort={true} + Field={'AssetKey'} + HeaderStyle={{ width: '20%' }} + RowStyle={{ width: '20%' }} + > Key + + + Key={'AssetName'} + AllowSort={true} + Field={'AssetName'} + HeaderStyle={{ width: '30%' }} + RowStyle={{ width: '30%' }} + > Name + + + Key={'AssetType'} + AllowSort={true} + Field={'AssetType'} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + > Type + + + Key={'VoltageKV'} + AllowSort={true} + Field={'VoltageKV'} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + > kV + + + Key={'Channels'} + AllowSort={true} + Field={'Channels'} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + Content={({ item }) => item.Channels.length} + > Channels + + + Key={'Buttons'} + AllowSort={false} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + Content={({ index }) => <> + + + } + >

+ +
-
+
- { - setShowAssetSelect(false); - if (!confirm) return; - - let list: Array = []; - let channels: Array = _.cloneDeep(props.Channels); - let assetConnections: Array = _.cloneDeep(props.AssetConnections); - - let removedAssets: Array = props.Assets.filter((asset) => asset.ID > 0 && selected.findIndex((selectedAsset) => (asset.ID === selectedAsset.ID)) < 0); - - //Deal with removed assets - $.each(removedAssets, (index, asset) => { - $.each(channels, (index, channel) => { - if (channel.Asset == asset.AssetKey) - channel.Asset = ''; - }); - - var index = assetConnections.findIndex(assetConnection => assetConnection.Parent == asset.AssetKey || assetConnection.Child == asset.AssetKey); - while (index >= 0) { - assetConnections.splice(index, 1); - index = assetConnections.findIndex(assetConnection => assetConnection.Parent == asset.AssetKey || assetConnection.Child == asset.AssetKey); - } - }); - let promises = []; - $.each(selected, async (index, record) => { - const oldRecord = props.Assets.find(asset => asset.ID === record.ID); - let assetRecord = getAssetWithAdditionalFields(record.ID, record.AssetType as OpenXDA.Types.AssetTypeName) - .then(a => ({ ...a, Channels: oldRecord?.Channels ?? []})); - // Push promises into promises - promises.push(assetRecord); - }); - - //Add the new assets that have been created by the user - $.each(props.Assets.filter((asset) => asset.ID <= 0), (index, asset) => { - list.push(asset); +
+ { + setShowAssetSelect(false); + if (!confirm) return; + + let list: Array = []; + let channels: Array = _.clone(props.Channels); + let assetConnections: Array = _.clone(props.AssetConnections); + + let removedAssets: Array = props.Assets.filter((asset) => asset.ID > 0 && selected.findIndex((selectedAsset) => (asset.ID === selectedAsset.ID)) < 0); + + //Deal with removed assets + $.each(removedAssets, (index, asset) => { + $.each(channels, (index, channel) => { + if (channel.Asset == asset.AssetKey) + channel.Asset = ''; }); - //Update selected - setSelectedAssets(selected); - Promise.all(promises).then(d => { props.UpdateAssets(list.concat(d)) }) - - //Update props - props.UpdateChannels(channels); - props.UpdateAssetConnections(assetConnections); - }}> -
  • -
    - Actions: -
    -
    - -
    -
    -
    -
  • -
    - { - if (confirm) { - const record: OpenXDA.Types.Asset = _.cloneDeep(newEditAsset); - const list = _.cloneDeep(props.Assets); - if (newEdit == 'New') { - // We have to do this swap because the key isn't set in stone until now - const channelsWithNewKey = channelsWorking - .map(chan => (chan.Asset === tempKey) ? ({ ...chan, Asset: record.AssetKey }) : chan); - record.Channels = channelsWithNewKey - .filter(chan => chan.Asset === record.AssetKey); ; - list.push(record); - props.UpdateChannels(channelsWithNewKey); - } - else if (newEdit == 'Edit') { - const index = list.findIndex(a => a.AssetKey == editAssetKey); - list[index] = record; - props.UpdateChannels(channelsWorking); - } - props.UpdateAssets(list); + var index = assetConnections.findIndex(assetConnection => assetConnection.Parent == asset.AssetKey || assetConnection.Child == asset.AssetKey); + while (index >= 0) { + assetConnections.splice(index, 1); + index = assetConnections.findIndex(assetConnection => assetConnection.Parent == asset.AssetKey || assetConnection.Child == asset.AssetKey); } - else setChannelsWorking(props.Channels); - - setShowAssetModal(false); + }); + let promises = []; + $.each(selected, async (index, record) => { + let assetRecord = getAssetWithAdditionalFields(record.ID, record.AssetType as OpenXDA.Types.AssetTypeName); + // Push promises into promises + promises.push(assetRecord); + }); + + //Add the new assets that have been created by the user + $.each(props.Assets.filter((asset) => asset.ID <= 0), (index, asset) => { + list.push(asset); + }); + + //Update selected + setSelectedAssets(selected); + Promise.all(promises).then(d => { props.UpdateAssets(list.concat(d)) }) + + //Update props + props.UpdateChannels(channels); + props.UpdateAssetConnections(assetConnections); + }}> +
  • +
    + Actions: +
    +
    + +
    +
    +
    +
  • + + { + setShowAssetModal(false); + + if (!confirm) { setNewEditAsset(AssetAttributes.getNewAsset('Line')); - }} - DisableConfirm={(AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).length > 0) } - ConfirmShowToolTip={AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).length > 0} - ConfirmToolTipContent={ - AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).map((e, i) =>

    {e}

    ) + return; } - > -
    -
    -
    -
    - { - if (record.AssetType == newEditAsset.AssetType) - setNewEditAsset(record); - else { - let newRecord = AssetAttributes.getNewAsset(record.AssetType); - newRecord.AssetKey = record.AssetKey; - newRecord.AssetName = record.AssetName; - newRecord.VoltageKV = record.VoltageKV; - newRecord.Description = record.Description; - newRecord.Channels = record.Channels; - setNewEditAsset(newRecord); - } - }} - GetDifferentAsset={getDifferentAsset} HideAssetType={newEdit == 'Edit'} HideSelectAsset={true} /> -
    -
    - {showAttributes()} -
    + + let record: OpenXDA.Types.Asset = _.clone(newEditAsset); + let list = _.clone(props.Assets); + let channels: Array = _.clone(props.Channels); + + $.each(channels, (index, channel) => { + if (channel.Asset == record.AssetKey) + channel.Asset = '' + + if (record.Channels.findIndex(c => c.ID == channel.ID) >= 0) + channel.Asset = record.AssetKey + }); + + if (newEdit == 'New') + list.push(record); + if (newEdit == 'Edit') { + const index = list.findIndex(a => a.AssetKey == editAssetKey); + list[index] = record; + } + + props.UpdateChannels(channels); + props.UpdateAssets(list); + setNewEditAsset(AssetAttributes.getNewAsset('Line')); + }} + DisableConfirm={(AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).length > 0)} + ConfirmShowToolTip={AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).length > 0} + ConfirmToolTipContent={ + AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).map((e, i) =>

    {CrossMark} {e}

    ) + } + > +
    +
    +
    +
    + { + if (record.AssetType == newEditAsset.AssetType) + setNewEditAsset(record); + else { + let newRecord = AssetAttributes.getNewAsset(record.AssetType); + newRecord.AssetKey = record.AssetKey; + newRecord.AssetName = record.AssetName; + newRecord.VoltageKV = record.VoltageKV; + newRecord.Description = record.Description; + newRecord.Channels = record.Channels; + setNewEditAsset(newRecord); + } + }} + GetDifferentAsset={getDifferentAsset} HideAssetType={newEdit == 'Edit'} HideSelectAsset={true} /> +
    +
    + {showAttributes()} +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 4da2e8fb7..337195c40 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -74,7 +74,7 @@ export interface AssetLists { Transformers: Array } -export default function NewMeterWizard(props: {IsEngineer: boolean}) { +export default function NewMeterWizard(props: { IsEngineer: boolean }) { let history = useHistory(); const dispatch = useAppDispatch(); @@ -209,8 +209,7 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { return []; } - function getAssets(): Array - { + function getAssets(): Array { if (localStorage.hasOwnProperty('NewMeterWizard.Assets')) return JSON.parse(localStorage.getItem('NewMeterWizard.Assets')); else @@ -295,7 +294,7 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { if (isSubmitStep()) setCurrentStep(saveStep + 1); else if (currentStep >= finalStep) - setCurrentStep(finalStep); + setCurrentStep(finalStep); else setCurrentStep(currentStep + 1); @@ -404,9 +403,9 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { Number of Trend Channels: {channels.reduce((p, c) => c.Trend ? (p + 1) : p, 0)}

    ; else if (currentStep === assetStep - || currentStep === connectionStep - ) - return + || currentStep === connectionStep + ) + return else if (currentStep >= additionalFieldMeterStep) { return (
    @@ -420,7 +419,7 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { ); } return null; - }, [currentStep, channels ]); + }, [currentStep, channels]); function getPage() { if (status === 'error') @@ -436,30 +435,30 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { case locationStep: return { setError(e) }} SetWarning={setWarning} /> case eventChannelsStep: - // The uses the same page as the next step for now + // The uses the same page as the next step for now case trendChannelsStep: - return case assetStep: - return case connectionStep: - return asset.AssetType != 'LineSegment')} + return asset.AssetType != 'LineSegment')} GetInnerComponent={(currentAsset) => } /> case additionalFieldMeterStep: return case externalFieldStep: - return + return case lineSegmentStep: - return } /> case additionalFieldAssetStep: - return }/> + return } /> case customerAssetGroupMeterStep: return case customerAssetGroupAssetStep: - return } /> } }; @@ -473,40 +472,40 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { data-tooltip='Next' onMouseEnter={() => setHover('Next')} onMouseLeave={() => setHover('None')} >{isFinalStep() ? 'Finish Editing' : 'Next'}); }; - + function disableNext() { return error.length > 0 }; return (
    -

    New Meter Wizard

    -
    -
    - -
    +

    New Meter Wizard

    +
    +
    + +
    - -
    +
    -
    -
    +
    +
    +
    @@ -519,7 +518,7 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) {
    - {getPage()} + {getPage()}
    {currentStep > 1 && currentStep !== saveStep + 1 ?
    +
    ); } From 3b50146e91dd96f60d6228a59664536a7c70cd85 Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 4 Oct 2024 13:40:40 -0400 Subject: [PATCH 06/50] functional --- .../Meter/PropertyUI/LocationDrawings.tsx | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index aaa71a957..dbbd7c291 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -49,34 +49,26 @@ const LocationDrawings = (props: IProps) => { const [showDrawings, setShowDrawings] = React.useState(false); const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); - React.useEffect(() => { - if (props.Locations != null) - setSelectedLocation(null); - if (props.Locations.length == 1) - setSelectedLocation(props.Locations[0].ID); - else { - setSelectedLocation(); - } - }, [props.Locations]) - React.useEffect(() => { // Does this properly grab the drawingData to show? if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) dispatch(LocationDrawingSlice.Fetch(selectedLocation)); - }, [drawingStatus, drawingParentID, props.Locations]); + }, [drawingStatus, drawingParentID, selectedLocation]); function dropdownOptions(): dropdownOption[] { const options: dropdownOption[] = []; const labels: string[] = props.Locations.map(loc => loc.Name); - for (const label of labels) { + labels.forEach((label, index) => { options.push({ Label: label, Disabled: false, Callback: () => { - if (selectedLocation != 0 && drawingData.length != 0) - setShowDrawings(true) + setSelectedLocation(props.Locations[index].ID); + if (selectedLocation != 0 && drawingData.length != 0) { + setShowDrawings(true); + } } }); - } + }); return options; } @@ -146,6 +138,15 @@ const LocationDrawings = (props: IProps) => { RowStyle={{ width: 'auto' }} > Description + + Key={'Link'} + AllowSort={true} + Field={'Link'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + Content={({ item, key }) => {item[key]}} + > Link + Key={'Number'} AllowSort={true} From 76567ffdcdc413e7b4261bc37a9b13bae80d24c4 Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 4 Oct 2024 15:27:44 -0400 Subject: [PATCH 07/50] Now updates properly w loading and alert --- .../Meter/PropertyUI/LocationDrawings.tsx | 140 +++++++++--------- 1 file changed, 74 insertions(+), 66 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index dbbd7c291..9e5da2c17 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -25,7 +25,7 @@ import * as React from 'react'; import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings' import { LocationDrawingSlice } from '../../Store/Store'; -import { BtnDropdown, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; +import { Alert, BtnDropdown, LoadingIcon, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; import { ReactTable } from '@gpa-gemstone/react-table'; import { useAppDispatch, useAppSelector } from '../../hooks'; import { CreateGuid } from '@gpa-gemstone/helper-functions'; @@ -49,9 +49,10 @@ const LocationDrawings = (props: IProps) => { const [showDrawings, setShowDrawings] = React.useState(false); const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); - React.useEffect(() => { // Does this properly grab the drawingData to show? - if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) + React.useEffect(() => { + if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) { dispatch(LocationDrawingSlice.Fetch(selectedLocation)); + } }, [drawingStatus, drawingParentID, selectedLocation]); function dropdownOptions(): dropdownOption[] { @@ -62,10 +63,8 @@ const LocationDrawings = (props: IProps) => { Label: label, Disabled: false, Callback: () => { - setSelectedLocation(props.Locations[index].ID); - if (selectedLocation != 0 && drawingData.length != 0) { - setShowDrawings(true); - } + setSelectedLocation(props.Locations[index].ID); // then set loading til drawings is set + setShowDrawings(true); } }); }); @@ -98,8 +97,11 @@ const LocationDrawings = (props: IProps) => { : { }} + Label={"Open Drawings " + props.Locations[0].Name} + Callback={() => { + setSelectedLocation(props.Locations[0].ID); + setShowDrawings(true); // does this run after the selected location + }} Options={dropdownOptions()} /> } @@ -107,63 +109,69 @@ const LocationDrawings = (props: IProps) => { setShowDrawings(false)} ShowCancel={false} ConfirmText={'Done'}>
    - - TableClass="table table-hover" - Data={drawingData} - SortKey={drawingSortKey} - Ascending={drawingAscending} - OnSort={(d) => { - dispatch(LocationDrawingSlice.Sort({ SortField: d.colField, Ascending: d.ascending })); - }} - OnClick={(d) => window.open(d.row.Link, '_blank')} - TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} - TbodyStyle={{ display: 'block', overflowY: 'scroll', maxHeight: '400px', width: '100%' }} - RowStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} - Selected={(item) => false} - KeySelector={(item) => item.ID} - > - - Key={'Name'} - AllowSort={true} - Field={'Name'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Name - - - Key={'Description'} - AllowSort={true} - Field={'Description'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Description - - - Key={'Link'} - AllowSort={true} - Field={'Link'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - Content={({ item, key }) => {item[key]}} - > Link - - - Key={'Number'} - AllowSort={true} - Field={'Number'} - HeaderStyle={{ width: '15%' }} - RowStyle={{ width: '15%' }} - > Number - - - Key={'Category'} - AllowSort={true} - Field={'Category'} - HeaderStyle={{ width: '15%' }} - RowStyle={{ width: '15%' }} - > Category - - + + {drawingData.length == 0 ? +
    + No Drawings associated with this location. +
    + : + TableClass="table table-hover" + Data={drawingData} + SortKey={drawingSortKey} + Ascending={drawingAscending} + OnSort={(d) => { + dispatch(LocationDrawingSlice.Sort({ SortField: d.colField, Ascending: d.ascending })); + }} + OnClick={(d) => window.open(d.row.Link, '_blank')} + TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} + TbodyStyle={{ display: 'block', overflowY: 'scroll', maxHeight: '400px', width: '100%' }} + RowStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} + Selected={(item) => false} + KeySelector={(item) => item.ID} + > + + Key={'Name'} + AllowSort={true} + Field={'Name'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + > Name + + + Key={'Description'} + AllowSort={true} + Field={'Description'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + > Description + + + Key={'Link'} + AllowSort={true} + Field={'Link'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + Content={({ item, key }) => {item[key]}} + > Link + + + Key={'Number'} + AllowSort={true} + Field={'Number'} + HeaderStyle={{ width: '15%' }} + RowStyle={{ width: '15%' }} + > Number + + + Key={'Category'} + AllowSort={true} + Field={'Category'} + HeaderStyle={{ width: '15%' }} + RowStyle={{ width: '15%' }} + > Category + + + }
    From e813040eaa14ff682ce9b8e2c61b11aaa6ff6fbf Mon Sep 17 00:00:00 2001 From: collins-self Date: Mon, 7 Oct 2024 13:34:34 -0400 Subject: [PATCH 08/50] Alert and made sure was passing in correct format --- .../Meter/PropertyUI/LocationDrawings.tsx | 11 ++++++----- .../Meter/PropertyUI/MeterLocationProperties.tsx | 2 +- .../NewMeterWizard/ConnectionPage.tsx | 16 ++++++++-------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index 9e5da2c17..60d471ab4 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -39,7 +39,7 @@ const LocationDrawings = (props: IProps) => { const dispatch = useAppDispatch(); const guid = React.useRef(CreateGuid()); - const drawingData = useAppSelector(LocationDrawingSlice.Data); + const drawingData = useAppSelector(LocationDrawingSlice.Data); // For some reason this is full of locations on NMW and MeterLocationProperties const drawingStatus = useAppSelector(LocationDrawingSlice.Status); const drawingParentID = useAppSelector(LocationDrawingSlice.ParentID); const drawingSortKey = useAppSelector(LocationDrawingSlice.SortField); @@ -79,12 +79,13 @@ const LocationDrawings = (props: IProps) => { type="button" className={"btn btn-primary"} disabled={props.Locations.length == 0 - || drawingData.length == 0} + || drawingData.length == 0 + || (props.Locations[0].Name == "" && props.Locations[0].ID == 0)} data-tooltip={guid.current} onMouseEnter={() => setHover('drawings')} onMouseLeave={() => setHover('none')} onClick={() => { - if (drawingData.length != 0) - setShowDrawings(true); + setSelectedLocation(props.Locations[0].ID); + setShowDrawings(true); }} >Open Drawing @@ -111,7 +112,7 @@ const LocationDrawings = (props: IProps) => {
    {drawingData.length == 0 ? -
    +
    No Drawings associated with this location.
    : diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx index 501353b83..129b414fe 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx @@ -165,7 +165,7 @@ const MeterLocationProperties = (props: IProps) => {
    - +
    Record={props.Location} diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/ConnectionPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/ConnectionPage.tsx index 05a370e00..977e9fd9c 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/ConnectionPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/ConnectionPage.tsx @@ -141,9 +141,9 @@ export default function ConnectionPage(props: IProps) { contentType: "application/json; charset=utf-8", dataType: 'json', data: JSON.stringify({ - Searches: filter, - OrderBy: 'ID', - Ascending: true + Searches: filter, + OrderBy: 'ID', + Ascending: true }), cache: true, async: true @@ -208,11 +208,11 @@ export default function ConnectionPage(props: IProps) { if (status === 'error') return
    -
    - -
    +
    + +
    ; - + return <>
    @@ -286,7 +286,7 @@ export default function ConnectionPage(props: IProps) { AllowSort={false} HeaderStyle={{ width: 'auto' }} RowStyle={{ width: 'auto' }} - Content={({item}) => + Content={({ item }) => deleteAssetConnection(item.Connection)} From c60618b4917ab5235978f6bab9af058b28f0587e Mon Sep 17 00:00:00 2001 From: collins-self Date: Mon, 7 Oct 2024 14:13:10 -0400 Subject: [PATCH 09/50] styling --- .../SystemCenter/Asset/AssetConnection.tsx | 2 +- .../Meter/PropertyUI/LocationDrawings.tsx | 49 ++++++++----------- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index d8ce5b299..858ad5858 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -251,7 +251,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number

    Connections:

    -
    +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index 60d471ab4..009474fe8 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -25,7 +25,7 @@ import * as React from 'react'; import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings' import { LocationDrawingSlice } from '../../Store/Store'; -import { Alert, BtnDropdown, LoadingIcon, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; +import { BtnDropdown, LoadingIcon, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; import { ReactTable } from '@gpa-gemstone/react-table'; import { useAppDispatch, useAppSelector } from '../../hooks'; import { CreateGuid } from '@gpa-gemstone/helper-functions'; @@ -39,7 +39,7 @@ const LocationDrawings = (props: IProps) => { const dispatch = useAppDispatch(); const guid = React.useRef(CreateGuid()); - const drawingData = useAppSelector(LocationDrawingSlice.Data); // For some reason this is full of locations on NMW and MeterLocationProperties + const drawingData = useAppSelector(LocationDrawingSlice.Data); const drawingStatus = useAppSelector(LocationDrawingSlice.Status); const drawingParentID = useAppSelector(LocationDrawingSlice.ParentID); const drawingSortKey = useAppSelector(LocationDrawingSlice.SortField); @@ -47,7 +47,7 @@ const LocationDrawings = (props: IProps) => { const [selectedLocation, setSelectedLocation] = React.useState(); const [showDrawings, setShowDrawings] = React.useState(false); - const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); + const [showDropdown, setShowDropdown] = React.useState(); React.useEffect(() => { if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) { @@ -55,6 +55,10 @@ const LocationDrawings = (props: IProps) => { } }, [drawingStatus, drawingParentID, selectedLocation]); + React.useEffect(() => { + setShowDropdown(props.Locations.length > 1); + }, [props.Locations]) + function dropdownOptions(): dropdownOption[] { const options: dropdownOption[] = []; const labels: string[] = props.Locations.map(loc => loc.Name); @@ -63,7 +67,7 @@ const LocationDrawings = (props: IProps) => { Label: label, Disabled: false, Callback: () => { - setSelectedLocation(props.Locations[index].ID); // then set loading til drawings is set + setSelectedLocation(props.Locations[index].ID); setShowDrawings(true); } }); @@ -73,31 +77,8 @@ const LocationDrawings = (props: IProps) => { return (
    - {props.Locations.length <= 1 ? // There is one Location or zero, show button to drawing or disabled - <> - - -

    No drawings associated with this substation.

    -
    - - : { setSelectedLocation(props.Locations[0].ID); @@ -105,6 +86,16 @@ const LocationDrawings = (props: IProps) => { }} Options={dropdownOptions()} /> + : } setShowDrawings(false)} ShowCancel={false} ConfirmText={'Done'}> From b0ef4c4ae260b7fd4041db91c7b64dda6a8bee61 Mon Sep 17 00:00:00 2001 From: Collins Self Date: Tue, 8 Oct 2024 16:00:38 -0400 Subject: [PATCH 10/50] Apply suggestions from code review AssetConnection Co-authored-by: Christoph Lackner <52460212+clackner-gpa@users.noreply.github.com> Signed-off-by: Collins Self --- .../TSX/SystemCenter/Asset/AssetConnection.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index 858ad5858..090670738 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -105,22 +105,25 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number React.useEffect(() => { let handle = getAssetConnections(); - return () => { if (handle != null || handle.abort != null) handle.abort(); } + return () => { if (handle != null && handle.abort != null) handle.abort(); } }, [props.ID, trigger]) React.useEffect(() => { - getLocations(); + const h = getLocations(); + return () => { if (h!= null && h.abort != null) h.abort(); } }, [assetConnections]) - function getLocations(): void { - $.ajax({ + function getLocations() { + const h = $.ajax({ type: "GET", url: `${homePath}api/OpenXDA/Asset/${props.ID}/Locations`, contentType: "application/json; charset=utf-8", dataType: 'json', cache: true, async: true - }).done(data => setLocations(data)); + }); + h.done(data => setLocations(data)); + return h; } function getAssetConnections(): JQuery.jqXHR { From 477cd2e57d141eaee2fd2a79a205a46b3719fb6d Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 9 Oct 2024 14:34:22 -0400 Subject: [PATCH 11/50] removed drowpdown type --- .../SystemCenter/Meter/PropertyUI/LocationDrawings.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index 009474fe8..ef040fbc9 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -33,7 +33,6 @@ import { CreateGuid } from '@gpa-gemstone/helper-functions'; interface IProps { Locations: OpenXDA.Types.Location[]; } -type dropdownOption = { Label: string; Callback: () => void; Disabled: boolean; } const LocationDrawings = (props: IProps) => { const dispatch = useAppDispatch(); @@ -50,17 +49,16 @@ const LocationDrawings = (props: IProps) => { const [showDropdown, setShowDropdown] = React.useState(); React.useEffect(() => { - if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) { + if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) dispatch(LocationDrawingSlice.Fetch(selectedLocation)); - } }, [drawingStatus, drawingParentID, selectedLocation]); React.useEffect(() => { setShowDropdown(props.Locations.length > 1); }, [props.Locations]) - function dropdownOptions(): dropdownOption[] { - const options: dropdownOption[] = []; + function dropdownOptions(): { Label: string; Callback: () => void; Disabled: boolean; }[] { + const options: { Label: string; Callback: () => void; Disabled: boolean; }[] = []; const labels: string[] = props.Locations.map(loc => loc.Name); labels.forEach((label, index) => { options.push({ From d043b55aacb0a7e3f755019f8bb300b48b838464 Mon Sep 17 00:00:00 2001 From: Collins Self Date: Wed, 9 Oct 2024 14:36:40 -0400 Subject: [PATCH 12/50] Apply suggestions from code review Co-authored-by: Christoph Lackner <52460212+clackner-gpa@users.noreply.github.com> Signed-off-by: Collins Self --- .../TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index ef040fbc9..28fa93e53 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -92,7 +92,7 @@ const LocationDrawings = (props: IProps) => { setSelectedLocation(props.Locations[0].ID); setShowDrawings(true); }} - >Open Drawing + >Open Drawing(s) } From bf281f8e73d827795835201af282669422396660 Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 9 Oct 2024 15:33:33 -0400 Subject: [PATCH 13/50] added tooltip back for 0 Locations --- .../Meter/PropertyUI/LocationDrawings.tsx | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index 28fa93e53..c9e35c8f8 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -47,6 +47,22 @@ const LocationDrawings = (props: IProps) => { const [selectedLocation, setSelectedLocation] = React.useState(); const [showDrawings, setShowDrawings] = React.useState(false); const [showDropdown, setShowDropdown] = React.useState(); + const [disableButton, setDisableButton] = React.useState(false); + const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); + + React.useEffect(() => { + if (props.Locations.length == 0 + || (props.Locations[0].Alias == "" // Empty Location is default in NMW + && props.Locations[0].Description == "" + && props.Locations[0].ID == 0 + && props.Locations[0].Latitude == null + && props.Locations[0].LocationKey == "" + && props.Locations[0].Longitude == null + && props.Locations[0].Name == "" + )) + setDisableButton(true); + else setDisableButton(false); + }, [props.Locations]) React.useEffect(() => { if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) @@ -80,27 +96,34 @@ const LocationDrawings = (props: IProps) => { Label={"Open Drawings " + props.Locations[0].Name} Callback={() => { setSelectedLocation(props.Locations[0].ID); - setShowDrawings(true); // does this run after the selected location + setShowDrawings(true); }} Options={dropdownOptions()} /> : } - + +

    No substation.

    +
    setShowDrawings(false)} ShowCancel={false} ConfirmText={'Done'}>
    - {drawingData.length == 0 ? + {drawingData.length == 0 ? // TODO: Replace with a search of all drawings and just disable button
    No Drawings associated with this location.
    From 5551cbdf4579cc74815affb33c8f117a741aaaca Mon Sep 17 00:00:00 2001 From: collins-self Date: Mon, 21 Oct 2024 13:48:14 -0400 Subject: [PATCH 14/50] Tooltip and button disable --- .../Meter/PropertyUI/LocationDrawings.tsx | 165 ++++++++++-------- 1 file changed, 90 insertions(+), 75 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index c9e35c8f8..168543e8b 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -29,6 +29,7 @@ import { BtnDropdown, LoadingIcon, Modal, ToolTip } from '@gpa-gemstone/react-in import { ReactTable } from '@gpa-gemstone/react-table'; import { useAppDispatch, useAppSelector } from '../../hooks'; import { CreateGuid } from '@gpa-gemstone/helper-functions'; +import { CrossMark } from '@gpa-gemstone/gpa-symbols'; interface IProps { Locations: OpenXDA.Types.Location[]; @@ -48,11 +49,19 @@ const LocationDrawings = (props: IProps) => { const [showDrawings, setShowDrawings] = React.useState(false); const [showDropdown, setShowDropdown] = React.useState(); const [disableButton, setDisableButton] = React.useState(false); + const [errors, setErrors] = React.useState([]); const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); React.useEffect(() => { + if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) + dispatch(LocationDrawingSlice.Fetch(selectedLocation)); + }, [props.Locations, drawingStatus, drawingParentID, selectedLocation]); + + React.useEffect(() => { + let e = []; + if (props.Locations.length == 0 - || (props.Locations[0].Alias == "" // Empty Location is default in NMW + || (props.Locations[0].Alias == "" && props.Locations[0].Description == "" && props.Locations[0].ID == 0 && props.Locations[0].Latitude == null @@ -60,20 +69,24 @@ const LocationDrawings = (props: IProps) => { && props.Locations[0].Longitude == null && props.Locations[0].Name == "" )) - setDisableButton(true); - else setDisableButton(false); - }, [props.Locations]) + e.push('No location selected.'); + else if (drawingData.length == 0 + && props.Locations.length != 0) + e.push('No drawings associated with selected location.'); + + setErrors(e); + }, [props.Locations, drawingData]); React.useEffect(() => { - if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) - dispatch(LocationDrawingSlice.Fetch(selectedLocation)); - }, [drawingStatus, drawingParentID, selectedLocation]); + setDisableButton(errors.length > 0); + }, [errors]); React.useEffect(() => { + setSelectedLocation(props.Locations[0].ID); setShowDropdown(props.Locations.length > 1); - }, [props.Locations]) + }, [props.Locations]); - function dropdownOptions(): { Label: string; Callback: () => void; Disabled: boolean; }[] { + function dropdownOptions() { const options: { Label: string; Callback: () => void; Disabled: boolean; }[] = []; const labels: string[] = props.Locations.map(loc => loc.Name); labels.forEach((label, index) => { @@ -112,79 +125,81 @@ const LocationDrawings = (props: IProps) => { setShowDrawings(true); } }} - >Open Drawing(s) + >Open Drawings {props.Locations[0].Name} } - -

    No substation.

    + {errors.map((e, i) =>

    {CrossMark} {e}

    )}
    - setShowDrawings(false)} ShowCancel={false} ConfirmText={'Done'}> + setShowDrawings(false)} + ShowCancel={false} + ConfirmText={'Done'}>
    - {drawingData.length == 0 ? // TODO: Replace with a search of all drawings and just disable button -
    - No Drawings associated with this location. -
    - : - TableClass="table table-hover" - Data={drawingData} - SortKey={drawingSortKey} - Ascending={drawingAscending} - OnSort={(d) => { - dispatch(LocationDrawingSlice.Sort({ SortField: d.colField, Ascending: d.ascending })); - }} - OnClick={(d) => window.open(d.row.Link, '_blank')} - TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} - TbodyStyle={{ display: 'block', overflowY: 'scroll', maxHeight: '400px', width: '100%' }} - RowStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} - Selected={(item) => false} - KeySelector={(item) => item.ID} - > - - Key={'Name'} - AllowSort={true} - Field={'Name'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Name - - - Key={'Description'} - AllowSort={true} - Field={'Description'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Description - - - Key={'Link'} - AllowSort={true} - Field={'Link'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - Content={({ item, key }) => {item[key]}} - > Link - - - Key={'Number'} - AllowSort={true} - Field={'Number'} - HeaderStyle={{ width: '15%' }} - RowStyle={{ width: '15%' }} - > Number - - - Key={'Category'} - AllowSort={true} - Field={'Category'} - HeaderStyle={{ width: '15%' }} - RowStyle={{ width: '15%' }} - > Category - - - } + + TableClass="table table-hover" + Data={drawingData} + SortKey={drawingSortKey} + Ascending={drawingAscending} + OnSort={(d) => { + dispatch(LocationDrawingSlice.Sort({ SortField: d.colField, Ascending: d.ascending })); + }} + OnClick={(d) => window.open(d.row.Link, '_blank')} + TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} + TbodyStyle={{ display: 'block', overflowY: 'scroll', maxHeight: '400px', width: '100%' }} + RowStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} + Selected={(item) => false} + KeySelector={(item) => item.ID} + > + + Key={'Name'} + AllowSort={true} + Field={'Name'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + > Name + + + Key={'Description'} + AllowSort={true} + Field={'Description'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + > Description + + + Key={'Link'} + AllowSort={true} + Field={'Link'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + Content={({ item, key }) => {item[key]}} + > Link + + + Key={'Number'} + AllowSort={true} + Field={'Number'} + HeaderStyle={{ width: '15%' }} + RowStyle={{ width: '15%' }} + > Number + + + Key={'Category'} + AllowSort={true} + Field={'Category'} + HeaderStyle={{ width: '15%' }} + RowStyle={{ width: '15%' }} + > Category + +
    From 746d02b96b851a38ec4583c21643538d556330eb Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 1 Nov 2024 12:19:31 -0400 Subject: [PATCH 15/50] Button wording --- .../TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx index 168543e8b..7055a42f4 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx @@ -125,7 +125,7 @@ const LocationDrawings = (props: IProps) => { setShowDrawings(true); } }} - >Open Drawings {props.Locations[0].Name} + >Open {props.Locations[0].Name} Drawings } Date: Wed, 6 Nov 2024 13:42:18 -0500 Subject: [PATCH 16/50] structural changes to locationdrawings --- .../SystemCenter/Asset/AssetConnection.tsx | 4 +- .../Location/LocationDrawings.tsx | 240 ++---------------- .../LocationDrawingsModal.tsx} | 8 +- .../Location/LocationDrawingsTable.tsx | 226 +++++++++++++++++ .../PropertyUI/MeterLocationProperties.tsx | 4 +- .../SystemCenter/NewMeterWizard/AssetPage.tsx | 4 +- .../NewMeterWizard/NewMeterWizard.tsx | 4 +- 7 files changed, 258 insertions(+), 232 deletions(-) rename Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/{Meter/PropertyUI/LocationDrawings.tsx => Location/LocationDrawingsModal.tsx} (97%) create mode 100644 Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index 090670738..8b78e6b1b 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -31,7 +31,7 @@ import { OpenXDA } from '@gpa-gemstone/application-typings'; import { useAppSelector, useAppDispatch } from '../hooks'; import { AssetConnectionTypeSlice } from '../Store/Store'; import { SelectRoles } from '../Store/UserSettings'; -import LocationDrawings from '../Meter/PropertyUI/LocationDrawings' +import LocationDrawingsModal from '../Location/LocationDrawingsModal' interface AssetConnection { AssetRelationShipTypeID: number, @@ -255,7 +255,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number

    Connections:

    - +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx index 6f2a0e8d7..12612f9f8 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx @@ -22,90 +22,20 @@ // Modified original source code; Incorporated 'Number' and 'Category' fields into // 'Substation Drawings' table. //****************************************************************************************************** - - - - import * as React from 'react'; import * as _ from 'lodash'; -import { Application, OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings'; -import { SystemCenter as SCGlobal } from '../global'; -import { Table, Column, Paging } from '@gpa-gemstone/react-table'; -import { useAppSelector, useAppDispatch } from '../hooks'; -import { Input, Select } from '@gpa-gemstone/react-forms'; -import { Pencil, TrashCan } from '@gpa-gemstone/gpa-symbols'; +import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings'; +import { ToolTip } from '@gpa-gemstone/react-interactive'; +import LocationDrawingsTable from './LocationDrawingsTable'; +import { useAppSelector } from '../hooks'; import { SelectRoles } from '../Store/UserSettings'; -import { ToolTip, GenericController, LoadingScreen, ServerErrorIcon } from '@gpa-gemstone/react-interactive'; -import { current } from '@reduxjs/toolkit'; const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) => { - const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); - const PagingID = 'LocationDrawingPage' - - const [links, setLinks] = React.useState([]); - const [sortKey, setSortKey] = React.useState('Name'); - const [ascending, setAscending] = React.useState(true); + const roles = useAppSelector(SelectRoles); // Deprecated const emptyRecord: SystemCenter.Types.LocationDrawing = { ID: 0, LocationID: 0, Name: '', Link: '', Description: '', Number: '', Category: '' }; const [record, setRecord] = React.useState(emptyRecord); - const [category, setCategory] = React.useState>([]); const [hover, setHover] = React.useState<('Update' | 'Reset' | 'None')>('None'); - const roles = useAppSelector(SelectRoles); - - const [page, setPage] = React.useState(0); - const [pageInfo, setPageInfo] = React.useState<{ RecordsPerPage: number, NumberOfPages: number, TotalRecords: number }>({ RecordsPerPage: 0, NumberOfPages: 0, TotalRecords: 0 }); - const [pageState, setPageState] = React.useState<'error' | 'idle' | 'loading'>('idle'); - - React.useEffect(() => { - const storedInfo = JSON.parse(localStorage.getItem(PagingID) as string); - if (storedInfo != null) setPage(storedInfo); - }, []); - - React.useEffect(() => { - localStorage.setItem(PagingID, JSON.stringify(page)); - }, [page]); - - React.useEffect(() => { - const handle = fetchDrawings(sortKey, ascending, page, props.Location.ID); - return () => { if (handle != null && handle?.abort != null) handle.abort(); } - }, [sortKey, ascending, page, props.Location.ID]); - - const fetchDrawings = (sortKey: keyof SystemCenter.Types.LocationDrawing, ascending: boolean, page: number, locationID: number) => { - setPageState('loading'); - const handle = LocationDrawingController.PagedSearch([], sortKey, ascending, page, locationID) - .done((result) => { - setLinks(JSON.parse(result.Data as unknown as string)); - if (result.NumberOfPages === 0) result.NumberOfPages = 1; - setPageInfo(result); - setPageState('idle'); - }) - .fail(() => setPageState('error')); - return handle; - } - - React.useEffect(() => { - let categoryHandle = getValueList("Category", setCategory); - - return () => { - if (categoryHandle != null && categoryHandle.abort != null) categoryHandle.abort(); - } - }, []) - - function getValueList(listName: string, setter: (value: Array) => void): JQuery.jqXHR> { - let h = $.ajax({ - type: "GET", - url: `${homePath}api/ValueList/Group/${listName}`, - contentType: "application/json; charset=utf-8", - dataType: `json`, - cache: false, - async: true - }); - h.done((dCat: Array) => { - setter(dCat); - - }); - return h; - } function hasPermissions(): boolean { if (roles.indexOf('Administrator') < 0 && roles.indexOf('Engineer') < 0) @@ -113,38 +43,6 @@ const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) => return true; } - function valid(field: keyof (SystemCenter.Types.LocationDrawing)): boolean { - if (field == 'Name') - return record.Name != null && record.Name.length > 0 && record.Name.length <= 200; - else if (field == 'Link') - return record.Link != null && record.Link.length > 0; - else if (field == 'Number') - return record.Number == null || record.Number.length <=50; - return true; - } - - const handleSave = () => { - setPageState('loading'); - LocationDrawingController.DBAction('PATCH', record) - .then(() => { - fetchDrawings(sortKey, ascending, page, props.Location.ID); - }) - .catch(() => { - setPageState('error'); - }); - }; - - const handleDelete = (item: SystemCenter.Types.LocationDrawing) => { - setPageState('loading'); - LocationDrawingController.DBAction('DELETE', item) - .then(() => { - fetchDrawings(sortKey, ascending, page, props.Location.ID); - }) - .catch(() => { - setPageState('error'); - }); - }; - return (
    @@ -155,124 +53,26 @@ const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) =>
    -
    - - TableClass="table table-hover" - Data={links} - SortKey={sortKey} - Ascending={ascending} - OnSort={(d) => { - if (d.colKey === 'EditDelete') - return; - if (d.colKey == sortKey) - setAscending(!ascending); - else { - setAscending(true); - setSortKey(d.colKey as keyof SystemCenter.Types.LocationDrawing); - } - }} - TableStyle={{ padding: 0, width: '100%', tableLayout: 'fixed', display: 'flex', flexDirection: 'column', overflow: 'hidden', flex: 1 }} - TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} - TbodyStyle={{ display: 'block', width: '100%', overflowY: 'auto', flex: 1 }} - RowStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} - Selected={(item) => false} - KeySelector={(item) => item.ID} - > - - Key={'Name'} - AllowSort={true} - Field={'Name'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Name - - - Key={'Link'} - AllowSort={true} - Field={'Link'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - Content={({ item, key }) => {item[key]} } - > Link - - - Key={'Description'} - AllowSort={true} - Field={'Description'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Description - - - Key={'Number'} - AllowSort={true} - Field={'Number'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Number - - - Key={'Category'} - AllowSort={true} - Field={'Category'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Category - - - Key={'EditDelete'} - AllowSort={false} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - Content={({ item }) => - - - - - } - >

    - - - - -
    -
    - setPage(p - 1)} /> -
    -
    -
    +
    - +
    - +

    Your role does not have permission. Please contact your Administrator if you believe this to be in error.

    -
    ); diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsModal.tsx similarity index 97% rename from Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx rename to Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsModal.tsx index 7055a42f4..4a3eeab3b 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsModal.tsx @@ -24,10 +24,10 @@ import * as React from 'react'; import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings' -import { LocationDrawingSlice } from '../../Store/Store'; +import { LocationDrawingSlice } from '../Store/Store'; import { BtnDropdown, LoadingIcon, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; import { ReactTable } from '@gpa-gemstone/react-table'; -import { useAppDispatch, useAppSelector } from '../../hooks'; +import { useAppDispatch, useAppSelector } from '../hooks'; import { CreateGuid } from '@gpa-gemstone/helper-functions'; import { CrossMark } from '@gpa-gemstone/gpa-symbols'; @@ -35,7 +35,7 @@ interface IProps { Locations: OpenXDA.Types.Location[]; } -const LocationDrawings = (props: IProps) => { +const LocationDrawingsModal = (props: IProps) => { const dispatch = useAppDispatch(); const guid = React.useRef(CreateGuid()); @@ -207,4 +207,4 @@ const LocationDrawings = (props: IProps) => { ) } -export default LocationDrawings; +export default LocationDrawingsModal; diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx new file mode 100644 index 000000000..3a50c6759 --- /dev/null +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx @@ -0,0 +1,226 @@ +import { OpenXDA, SystemCenter } from "@gpa-gemstone/application-typings"; +import { Pencil, TrashCan } from "@gpa-gemstone/gpa-symbols"; +import { GenericController, LoadingScreen, ServerErrorIcon } from "@gpa-gemstone/react-interactive"; +import { ReactTable, Paging } from "@gpa-gemstone/react-table"; +import React from "react"; +import { useAppSelector } from "../hooks"; +import { SelectRoles } from "../Store/UserSettings"; +import { Input, Select } from '@gpa-gemstone/react-forms'; + +const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location }) => { + const [links, setLinks] = React.useState([]); + const [sortKey, setSortKey] = React.useState('Name'); + const [ascending, setAscending] = React.useState(true); + const [pageInfo, setPageInfo] = React.useState<{ RecordsPerPage: number, NumberOfPages: number, TotalRecords: number }>({ RecordsPerPage: 0, NumberOfPages: 0, TotalRecords: 0 }); + const [pageState, setPageState] = React.useState<'error' | 'idle' | 'loading'>('idle'); + const [page, setPage] = React.useState(0); + const [category, setCategory] = React.useState>([]); + const emptyRecord: SystemCenter.Types.LocationDrawing = { ID: 0, LocationID: 0, Name: '', Link: '', Description: '', Number: '', Category: '' }; + const [record, setRecord] = React.useState(emptyRecord); + + const roles = useAppSelector(SelectRoles); // Deprecated + const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); + const PagingID = 'LocationDrawingPage' + + function hasPermissions(): boolean { + if (roles.indexOf('Administrator') < 0 && roles.indexOf('Engineer') < 0) + return false; + return true; + } + + const fetchDrawings = (sortKey: keyof SystemCenter.Types.LocationDrawing, ascending: boolean, page: number, locationID: number) => { + setPageState('loading'); + const handle = LocationDrawingController.PagedSearch([], sortKey, ascending, page, locationID) + .done((result) => { + setLinks(JSON.parse(result.Data as unknown as string)); + if (result.NumberOfPages === 0) result.NumberOfPages = 1; + setPageInfo(result); + setPageState('idle'); + }) + .fail(() => setPageState('error')); + return handle; + } + const handleDelete = (item: SystemCenter.Types.LocationDrawing) => { + setPageState('loading'); + LocationDrawingController.DBAction('DELETE', item) + .then(() => { + fetchDrawings(sortKey, ascending, page, props.Location.ID); + }) + .catch(() => { + setPageState('error'); + }); + }; + + const handleSave = () => { + setPageState('loading'); + LocationDrawingController.DBAction('PATCH', record) + .then(() => { + fetchDrawings(sortKey, ascending, page, props.Location.ID); + }) + .catch(() => { + setPageState('error'); + }); + }; + + function getValueList(listName: string, setter: (value: Array) => void): JQuery.jqXHR> { + let h = $.ajax({ + type: "GET", + url: `${homePath}api/ValueList/Group/${listName}`, + contentType: "application/json; charset=utf-8", + dataType: `json`, + cache: false, + async: true + }); + h.done((dCat: Array) => { + setter(dCat); + + }); + return h; + } + + function valid(field: keyof (SystemCenter.Types.LocationDrawing)): boolean { + if (field == 'Name') + return record.Name != null && record.Name.length > 0 && record.Name.length <= 200; + else if (field == 'Link') + return record.Link != null && record.Link.length > 0; + else if (field == 'Number') + return record.Number == null || record.Number.length <= 50; + return true; + } + + React.useEffect(() => { + let categoryHandle = getValueList("Category", setCategory); + + return () => { + if (categoryHandle != null && categoryHandle.abort != null) categoryHandle.abort(); + } + }, []) + + React.useEffect(() => { + const storedInfo = JSON.parse(localStorage.getItem(PagingID) as string); + if (storedInfo != null) setPage(storedInfo); + }, []); + + React.useEffect(() => { + localStorage.setItem(PagingID, JSON.stringify(page)); + }, [page]); + + React.useEffect(() => { + const handle = fetchDrawings(sortKey, ascending, page, props.Location.ID); + return () => { if (handle != null && handle?.abort != null) handle.abort(); } + }, [sortKey, ascending, page, props.Location.ID]); + + return (<> +
    + + TableClass="table table-hover" + Data={links} + SortKey={sortKey} + Ascending={ascending} + OnSort={(d) => { + if (d.colKey === 'EditDelete') + return; + if (d.colKey == sortKey) + setAscending(!ascending); + else { + setAscending(true); + setSortKey(d.colKey as keyof SystemCenter.Types.LocationDrawing); + } + }} + TableStyle={{ padding: 0, width: '100%', tableLayout: 'fixed', display: 'flex', flexDirection: 'column', overflow: 'hidden', flex: 1 }} + TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} + TbodyStyle={{ display: 'block', width: '100%', overflowY: 'auto', flex: 1 }} + RowStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} + Selected={(item) => false} + KeySelector={(item) => item.ID} + > + + Key={'Name'} + AllowSort={true} + Field={'Name'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + > Name + + + Key={'Link'} + AllowSort={true} + Field={'Link'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + Content={({ item, key }) => {item[key]}} + > Link + + + Key={'Description'} + AllowSort={true} + Field={'Description'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + > Description + + + Key={'Number'} + AllowSort={true} + Field={'Number'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + > Number + + + Key={'Category'} + AllowSort={true} + Field={'Category'} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + > Category + + + Key={'EditDelete'} + AllowSort={false} + HeaderStyle={{ width: 'auto' }} + RowStyle={{ width: 'auto' }} + Content={({ item }) => + + + + + } + >

    + + + + +
    +
    + setPage(p - 1)} /> +
    +
    +
    + + ) +} + +export default LocationDrawingsTable; \ No newline at end of file diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx index 129b414fe..511cfb97e 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx @@ -29,7 +29,7 @@ import { Input, TextArea } from '@gpa-gemstone/react-forms'; import { AssetAttributes } from '../../AssetAttribute/Asset'; import { DefaultSelects } from '@gpa-gemstone/common-pages'; import { ByLocationSlice } from '../../Store/Store'; -import LocationDrawings from './LocationDrawings'; +import LocationDrawingsModal from '../../Location/LocationDrawingsModal'; import { useAppSelector } from '../../hooks'; import { SelectRoles } from '../../Store/UserSettings'; import { ToolTip } from '@gpa-gemstone/react-interactive'; @@ -165,7 +165,7 @@ const MeterLocationProperties = (props: IProps) => {
    - +
    Record={props.Location} diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index 91c0752dd..33ee039fc 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -40,7 +40,7 @@ import DERAttributes from '../AssetAttribute/DER'; import AssetSelect from '../Asset/AssetSelect'; import { ReactIcons } from '@gpa-gemstone/gpa-symbols'; import { getAssetWithAdditionalFields } from '../../../TS/Services/Asset'; -import LocationDrawings from '../Meter/PropertyUI/LocationDrawings'; +import LocationDrawingsModal from '../Location/LocationDrawingsModal'; import { GetNodeSize } from '@gpa-gemstone/helper-functions'; import { ReactTable } from '@gpa-gemstone/react-table'; import GenerationAttributes from '../AssetAttribute/Generation'; @@ -484,7 +484,7 @@ export default function AssetPage(props: IProps) { Actions:
    - +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 337195c40..019a6343e 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -41,7 +41,7 @@ import AdditionalFieldsWindow from '../CommonComponents/AdditionalFieldsWindow'; import MultipleAssetsPage from './MultipleAssetsPage'; import CustomerAssetGroupPage from './CustomerAssetGroupPage'; import LineSegmentWindow from '../AssetAttribute/LineSegmentWindow'; -import LocationDrawings from '../Meter/PropertyUI/LocationDrawings'; +import LocationDrawingsModal from '../Location/LocationDrawingsModal'; // Define Step Numbers const generalStep: number = 1; @@ -405,7 +405,7 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { else if (currentStep === assetStep || currentStep === connectionStep ) - return + return else if (currentStep >= additionalFieldMeterStep) { return (
    From cae137cf48d5ac3bdcfb040aea9fc27645e5403b Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 8 Nov 2024 08:49:43 -0500 Subject: [PATCH 17/50] updated imports and fixed 'undefined' error --- .../SystemCenter/Asset/AssetConnection.tsx | 2 +- .../LocationDrawingsModal.tsx | 99 ++++--------------- .../Location/AddEditDrawingsModal.tsx | 90 +++++++++++++++++ .../Location/LocationDrawings.tsx | 4 +- .../Location/LocationDrawingsTable.tsx | 63 +++++++----- .../PropertyUI/MeterLocationProperties.tsx | 2 +- .../SystemCenter/NewMeterWizard/AssetPage.tsx | 2 +- .../NewMeterWizard/NewMeterWizard.tsx | 2 +- 8 files changed, 151 insertions(+), 113 deletions(-) rename Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/{Location => CommonComponents}/LocationDrawingsModal.tsx (56%) create mode 100644 Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index 8b78e6b1b..bfbd4c129 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -31,7 +31,7 @@ import { OpenXDA } from '@gpa-gemstone/application-typings'; import { useAppSelector, useAppDispatch } from '../hooks'; import { AssetConnectionTypeSlice } from '../Store/Store'; import { SelectRoles } from '../Store/UserSettings'; -import LocationDrawingsModal from '../Location/LocationDrawingsModal' +import LocationDrawingsModal from '../CommonComponents/LocationDrawingsModal' interface AssetConnection { AssetRelationShipTypeID: number, diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx similarity index 56% rename from Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsModal.tsx rename to Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 4a3eeab3b..8038705e5 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -16,20 +16,18 @@ // // Code Modification History: // ---------------------------------------------------------------------------------------------------- -// 08/24/2023 - Parker Dinsdale +// 11/06/2024 - Collins Self // Generated original version of source code. // //****************************************************************************************************** - - -import * as React from 'react'; +import React from 'react'; import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings' import { LocationDrawingSlice } from '../Store/Store'; import { BtnDropdown, LoadingIcon, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; -import { ReactTable } from '@gpa-gemstone/react-table'; import { useAppDispatch, useAppSelector } from '../hooks'; import { CreateGuid } from '@gpa-gemstone/helper-functions'; import { CrossMark } from '@gpa-gemstone/gpa-symbols'; +import LocationDrawingsTable from '../Location/LocationDrawingsTable'; interface IProps { Locations: OpenXDA.Types.Location[]; @@ -42,11 +40,9 @@ const LocationDrawingsModal = (props: IProps) => { const drawingData = useAppSelector(LocationDrawingSlice.Data); const drawingStatus = useAppSelector(LocationDrawingSlice.Status); const drawingParentID = useAppSelector(LocationDrawingSlice.ParentID); - const drawingSortKey = useAppSelector(LocationDrawingSlice.SortField); - const drawingAscending = useAppSelector(LocationDrawingSlice.Ascending); const [selectedLocation, setSelectedLocation] = React.useState(); - const [showDrawings, setShowDrawings] = React.useState(false); + const [showModal, setShowModal] = React.useState(false); const [showDropdown, setShowDropdown] = React.useState(); const [disableButton, setDisableButton] = React.useState(false); const [errors, setErrors] = React.useState([]); @@ -69,7 +65,7 @@ const LocationDrawingsModal = (props: IProps) => { && props.Locations[0].Longitude == null && props.Locations[0].Name == "" )) - e.push('No location selected.'); + e.push('No locations have been set.'); else if (drawingData.length == 0 && props.Locations.length != 0) e.push('No drawings associated with selected location.'); @@ -82,11 +78,11 @@ const LocationDrawingsModal = (props: IProps) => { }, [errors]); React.useEffect(() => { - setSelectedLocation(props.Locations[0].ID); + setSelectedLocation(props.Locations[0]?.ID); setShowDropdown(props.Locations.length > 1); }, [props.Locations]); - function dropdownOptions() { + /*function dropdownOptions() { const options: { Label: string; Callback: () => void; Disabled: boolean; }[] = []; const labels: string[] = props.Locations.map(loc => loc.Name); labels.forEach((label, index) => { @@ -95,25 +91,25 @@ const LocationDrawingsModal = (props: IProps) => { Disabled: false, Callback: () => { setSelectedLocation(props.Locations[index].ID); - setShowDrawings(true); + setShowModal(true); } }); }); return options; - } + }*/ return (
    - {showDropdown ? + {/*showDropdown ? { setSelectedLocation(props.Locations[0].ID); - setShowDrawings(true); + setShowModal(true); }} Options={dropdownOptions()} /> - : } { {errors.map((e, i) =>

    {CrossMark} {e}

    )}
    setShowDrawings(false)} + CallBack={() => setShowModal(false)} ShowCancel={false} ConfirmText={'Done'}>
    - - TableClass="table table-hover" - Data={drawingData} - SortKey={drawingSortKey} - Ascending={drawingAscending} - OnSort={(d) => { - dispatch(LocationDrawingSlice.Sort({ SortField: d.colField, Ascending: d.ascending })); - }} - OnClick={(d) => window.open(d.row.Link, '_blank')} - TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} - TbodyStyle={{ display: 'block', overflowY: 'scroll', maxHeight: '400px', width: '100%' }} - RowStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} - Selected={(item) => false} - KeySelector={(item) => item.ID} - > - - Key={'Name'} - AllowSort={true} - Field={'Name'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Name - - - Key={'Description'} - AllowSort={true} - Field={'Description'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Description - - - Key={'Link'} - AllowSort={true} - Field={'Link'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - Content={({ item, key }) => {item[key]}} - > Link - - - Key={'Number'} - AllowSort={true} - Field={'Number'} - HeaderStyle={{ width: '15%' }} - RowStyle={{ width: '15%' }} - > Number - - - Key={'Category'} - AllowSort={true} - Field={'Category'} - HeaderStyle={{ width: '15%' }} - RowStyle={{ width: '15%' }} - > Category - - + loc.ID == selectedLocation)} ShowEdit={false} />
    ) } - -export default LocationDrawingsModal; +export default LocationDrawingsModal; \ No newline at end of file diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx new file mode 100644 index 000000000..4891e6ff4 --- /dev/null +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx @@ -0,0 +1,90 @@ +//****************************************************************************************************** +// LocationDrawings.tsx - Gbtc +// +// Copyright � 2023, 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: +// ---------------------------------------------------------------------------------------------------- +// 11/06/2024 - Collins Self +// Generated original version of source code. +// +//****************************************************************************************************** +import { SystemCenter } from "@gpa-gemstone/application-typings"; +import { Input, Select } from "@gpa-gemstone/react-forms"; +import React from "react"; + +interface IProps { + Record: SystemCenter.Types.LocationDrawing, + Category: { + Value: string | number; + Label: string; + }[], + Setter: (record) => void, + Valid: (field) => boolean, + HandleSave: () => void +} + +const AddEditDrawingsModal = (props: IProps) => { + return <> + + +} +export default AddEditDrawingsModal; \ No newline at end of file diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx index 12612f9f8..66b5c1aab 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx @@ -53,12 +53,12 @@ const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) =>
    - +
    - - ) + {props.ShowEdit ? + { return { Value: item.Value, Label: item.AltValue ?? item.Value } }) }/> + : null} + } export default LocationDrawingsTable; \ No newline at end of file diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx index 511cfb97e..69741b39e 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx @@ -29,7 +29,7 @@ import { Input, TextArea } from '@gpa-gemstone/react-forms'; import { AssetAttributes } from '../../AssetAttribute/Asset'; import { DefaultSelects } from '@gpa-gemstone/common-pages'; import { ByLocationSlice } from '../../Store/Store'; -import LocationDrawingsModal from '../../Location/LocationDrawingsModal'; +import LocationDrawingsModal from '../../CommonComponents/LocationDrawingsModal'; import { useAppSelector } from '../../hooks'; import { SelectRoles } from '../../Store/UserSettings'; import { ToolTip } from '@gpa-gemstone/react-interactive'; diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index 33ee039fc..9ea38cf63 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -40,7 +40,7 @@ import DERAttributes from '../AssetAttribute/DER'; import AssetSelect from '../Asset/AssetSelect'; import { ReactIcons } from '@gpa-gemstone/gpa-symbols'; import { getAssetWithAdditionalFields } from '../../../TS/Services/Asset'; -import LocationDrawingsModal from '../Location/LocationDrawingsModal'; +import LocationDrawingsModal from '../CommonComponents/LocationDrawingsModal'; import { GetNodeSize } from '@gpa-gemstone/helper-functions'; import { ReactTable } from '@gpa-gemstone/react-table'; import GenerationAttributes from '../AssetAttribute/Generation'; diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 019a6343e..43247f886 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -41,7 +41,7 @@ import AdditionalFieldsWindow from '../CommonComponents/AdditionalFieldsWindow'; import MultipleAssetsPage from './MultipleAssetsPage'; import CustomerAssetGroupPage from './CustomerAssetGroupPage'; import LineSegmentWindow from '../AssetAttribute/LineSegmentWindow'; -import LocationDrawingsModal from '../Location/LocationDrawingsModal'; +import LocationDrawingsModal from '../CommonComponents/LocationDrawingsModal'; // Define Step Numbers const generalStep: number = 1; From 38cd223c7c6d7ffde44ab6774a0bf8662decac9a Mon Sep 17 00:00:00 2001 From: collins-self Date: Mon, 11 Nov 2024 13:42:57 -0500 Subject: [PATCH 18/50] simplified functionality, LocationDrawings.tsx wip --- .../SystemCenter/Asset/AssetConnection.tsx | 4 +- .../LocationDrawingsModal.tsx | 107 +++++---------- .../Location/AddEditDrawingsModal.tsx | 126 ++++++++++-------- .../Location/LocationDrawings.tsx | 50 ++++++- .../Location/LocationDrawingsTable.tsx | 46 ++----- .../PropertyUI/MeterLocationProperties.tsx | 2 +- .../SystemCenter/NewMeterWizard/AssetPage.tsx | 2 +- .../NewMeterWizard/NewMeterWizard.tsx | 2 +- 8 files changed, 173 insertions(+), 166 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index bfbd4c129..5a9a34046 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -255,7 +255,9 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number

    Connections:

    - + + +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 8038705e5..2c4e31870 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -21,16 +21,17 @@ // //****************************************************************************************************** import React from 'react'; -import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings' +import { OpenXDA } from '@gpa-gemstone/application-typings' import { LocationDrawingSlice } from '../Store/Store'; -import { BtnDropdown, LoadingIcon, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; +import { LoadingIcon, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; import { useAppDispatch, useAppSelector } from '../hooks'; import { CreateGuid } from '@gpa-gemstone/helper-functions'; import { CrossMark } from '@gpa-gemstone/gpa-symbols'; import LocationDrawingsTable from '../Location/LocationDrawingsTable'; +import AddEditDrawingsModal from '../Location/AddEditDrawingsModal'; interface IProps { - Locations: OpenXDA.Types.Location[]; + Location: OpenXDA.Types.Location; } const LocationDrawingsModal = (props: IProps) => { @@ -41,89 +42,53 @@ const LocationDrawingsModal = (props: IProps) => { const drawingStatus = useAppSelector(LocationDrawingSlice.Status); const drawingParentID = useAppSelector(LocationDrawingSlice.ParentID); - const [selectedLocation, setSelectedLocation] = React.useState(); + const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); + const [errors, setErrors] = React.useState([]); const [showModal, setShowModal] = React.useState(false); - const [showDropdown, setShowDropdown] = React.useState(); const [disableButton, setDisableButton] = React.useState(false); - const [errors, setErrors] = React.useState([]); - const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); React.useEffect(() => { - if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != selectedLocation) - dispatch(LocationDrawingSlice.Fetch(selectedLocation)); - }, [props.Locations, drawingStatus, drawingParentID, selectedLocation]); + setDisableButton(errors.length > 0); + }, [errors]); + + React.useEffect(() => { + if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != props.Location?.ID) + dispatch(LocationDrawingSlice.Fetch(props.Location?.ID)); + }, [props.Location, drawingStatus, drawingParentID]); React.useEffect(() => { let e = []; - if (props.Locations.length == 0 - || (props.Locations[0].Alias == "" - && props.Locations[0].Description == "" - && props.Locations[0].ID == 0 - && props.Locations[0].Latitude == null - && props.Locations[0].LocationKey == "" - && props.Locations[0].Longitude == null - && props.Locations[0].Name == "" - )) + if (props.Location == undefined + || (props.Location.Alias == "" + && props.Location.Description == "" + && props.Location.ID == 0 + && props.Location.Latitude == null + && props.Location.LocationKey == "" + && props.Location.Longitude == null + && props.Location.Name == "")) e.push('No locations have been set.'); - else if (drawingData.length == 0 - && props.Locations.length != 0) + else if (drawingData.length == 0) e.push('No drawings associated with selected location.'); setErrors(e); - }, [props.Locations, drawingData]); - - React.useEffect(() => { - setDisableButton(errors.length > 0); - }, [errors]); - - React.useEffect(() => { - setSelectedLocation(props.Locations[0]?.ID); - setShowDropdown(props.Locations.length > 1); - }, [props.Locations]); - - /*function dropdownOptions() { - const options: { Label: string; Callback: () => void; Disabled: boolean; }[] = []; - const labels: string[] = props.Locations.map(loc => loc.Name); - labels.forEach((label, index) => { - options.push({ - Label: label, - Disabled: false, - Callback: () => { - setSelectedLocation(props.Locations[index].ID); - setShowModal(true); - } - }); - }); - return options; - }*/ + }, [props.Location, drawingData]); return (
    - {/*showDropdown ? - { - setSelectedLocation(props.Locations[0].ID); + - } + } + }} + >Open {props.Location?.Name} Drawings + @@ -139,7 +104,7 @@ const LocationDrawingsModal = (props: IProps) => {
    - loc.ID == selectedLocation)} ShowEdit={false} /> +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx index 4891e6ff4..210d5b954 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx @@ -22,69 +22,87 @@ //****************************************************************************************************** import { SystemCenter } from "@gpa-gemstone/application-typings"; import { Input, Select } from "@gpa-gemstone/react-forms"; +import { Modal } from "@gpa-gemstone/react-interactive"; import React from "react"; interface IProps { Record: SystemCenter.Types.LocationDrawing, - Category: { - Value: string | number; - Label: string; - }[], Setter: (record) => void, Valid: (field) => boolean, - HandleSave: () => void + HandleSave: () => void, + Show: boolean, + SetShow: (show: boolean) => void, } -const AddEditDrawingsModal = (props: IProps) => { +const AddEditDrawingsModal = (props: IProps) => { // Change to modal + const [category, setCategory] = React.useState>([]); + + function getValueList(listName: string, setter: (value: Array) => void): JQuery.jqXHR> { + let h = $.ajax({ + type: "GET", + url: `${homePath}api/ValueList/Group/${listName}`, + contentType: "application/json; charset=utf-8", + dataType: `json`, + cache: false, + async: true + }); + h.done((dCat: Array) => { + setter(dCat); + + }); + return h; + } + + React.useEffect(() => { + let categoryHandle = getValueList("Category", setCategory); + + return () => { + if (categoryHandle != null && categoryHandle.abort != null) categoryHandle.abort(); + } + }, []) + return <> - + { + props.SetShow(false); + if (conf) props.HandleSave(); + }} + ShowCancel={true} + ConfirmText={'Save Changes'}> + + Record={props.Record} + Field={'Name'} + Feedback={'A Name of less than 200 characters is required.'} + Valid={props.Valid} + Setter={(r) => props.Setter(r)} /> + + Record={props.Record} + Field={'Link'} + Feedback={'A Link is required.'} + Valid={props.Valid} + Setter={(r) => props.Setter(r)} /> + + Record={props.Record} + Field={'Description'} + Valid={props.Valid} + Setter={(r) => props.Setter(r)} /> + + Record={props.Record} + Field={'Category'} + Options={category.map(item => { return { Value: item.Value, Label: item.AltValue ?? item.Value } })} + Label={'Category'} + Setter={(r) => props.Setter(r)} /> + + Record={props.Record} + Field={'Number'} + Feedback={'Number must be less than 50 characters.'} + Valid={props.Valid} + AllowNull={true} + Setter={(r) => props.Setter(r)} /> + } export default AddEditDrawingsModal; \ No newline at end of file diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx index 66b5c1aab..70db4bf0f 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx @@ -29,6 +29,7 @@ import { ToolTip } from '@gpa-gemstone/react-interactive'; import LocationDrawingsTable from './LocationDrawingsTable'; import { useAppSelector } from '../hooks'; import { SelectRoles } from '../Store/UserSettings'; +import AddEditDrawingsModal from './AddEditDrawingsModal'; const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) => { @@ -36,6 +37,7 @@ const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) => const emptyRecord: SystemCenter.Types.LocationDrawing = { ID: 0, LocationID: 0, Name: '', Link: '', Description: '', Number: '', Category: '' }; const [record, setRecord] = React.useState(emptyRecord); const [hover, setHover] = React.useState<('Update' | 'Reset' | 'None')>('None'); + const [showModal, setShowModal] = React.useState(false); function hasPermissions(): boolean { if (roles.indexOf('Administrator') < 0 && roles.indexOf('Engineer') < 0) @@ -43,6 +45,40 @@ const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) => return true; } + const fetchDrawings = (sortKey: keyof SystemCenter.Types.LocationDrawing, ascending: boolean, page: number, locationID: number) => { + setPageState('loading'); + const handle = LocationDrawingController.PagedSearch([], sortKey, ascending, page, locationID) + .done((result) => { + setLinks(JSON.parse(result.Data as unknown as string)); + if (result.NumberOfPages === 0) result.NumberOfPages = 1; + setPageInfo(result); + setPageState('idle'); + }) + .fail(() => setPageState('error')); + return handle; + } + + const handleSave = () => { + setPageState('loading'); + LocationDrawingController.DBAction('PATCH', record) + .then(() => { + fetchDrawings(sortKey, ascending, page, props.Location.ID); + }) + .catch(() => { + setPageState('error'); + }); + }; + + function valid(field: keyof (SystemCenter.Types.LocationDrawing)): boolean { + if (field == 'Name') + return record.Name != null && record.Name.length > 0 && record.Name.length <= 200; + else if (field == 'Link') + return record.Link != null && record.Link.length > 0; + else if (field == 'Number') + return record.Number == null || record.Number.length <= 50; + return true; + } + return (
    @@ -53,19 +89,25 @@ const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) =>
    - + { setRecord(record) }} />
    + { +const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, Edit?: (record: SystemCenter.Types.LocationDrawing) => void }) => { const [links, setLinks] = React.useState([]); const [sortKey, setSortKey] = React.useState('Name'); const [ascending, setAscending] = React.useState(true); + const [showModal, setShowModal] = React.useState(true); const [pageInfo, setPageInfo] = React.useState<{ RecordsPerPage: number, NumberOfPages: number, TotalRecords: number }>({ RecordsPerPage: 0, NumberOfPages: 0, TotalRecords: 0 }); const [pageState, setPageState] = React.useState<'error' | 'idle' | 'loading'>('idle'); const [page, setPage] = React.useState(0); - const [category, setCategory] = React.useState>([]); const emptyRecord: SystemCenter.Types.LocationDrawing = { ID: 0, LocationID: 0, Name: '', Link: '', Description: '', Number: '', Category: '' }; const [record, setRecord] = React.useState(emptyRecord); @@ -62,6 +62,7 @@ const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, ShowEd .fail(() => setPageState('error')); return handle; } + const handleDelete = (item: SystemCenter.Types.LocationDrawing) => { setPageState('loading'); LocationDrawingController.DBAction('DELETE', item) @@ -84,22 +85,6 @@ const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, ShowEd }); }; - function getValueList(listName: string, setter: (value: Array) => void): JQuery.jqXHR> { - let h = $.ajax({ - type: "GET", - url: `${homePath}api/ValueList/Group/${listName}`, - contentType: "application/json; charset=utf-8", - dataType: `json`, - cache: false, - async: true - }); - h.done((dCat: Array) => { - setter(dCat); - - }); - return h; - } - function valid(field: keyof (SystemCenter.Types.LocationDrawing)): boolean { if (field == 'Name') return record.Name != null && record.Name.length > 0 && record.Name.length <= 200; @@ -110,14 +95,6 @@ const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, ShowEd return true; } - React.useEffect(() => { - let categoryHandle = getValueList("Category", setCategory); - - return () => { - if (categoryHandle != null && categoryHandle.abort != null) categoryHandle.abort(); - } - }, []) - React.useEffect(() => { const storedInfo = JSON.parse(localStorage.getItem(PagingID) as string); if (storedInfo != null) setPage(storedInfo); @@ -128,7 +105,7 @@ const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, ShowEd }, [page]); React.useEffect(() => { - const handle = fetchDrawings(sortKey, ascending, page, props.Location.ID); + const handle = fetchDrawings(sortKey, ascending, page, props.Location?.ID); return () => { if (handle != null && handle?.abort != null) handle.abort(); } }, [sortKey, ascending, page, props.Location.ID]); @@ -197,7 +174,7 @@ const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, ShowEd RowStyle={{ width: 'auto' }} > Category - {props.ShowEdit ? + {props.Edit ? Key={'EditDelete'} AllowSort={false} @@ -205,8 +182,10 @@ const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, ShowEd RowStyle={{ width: 'auto' }} Content={({ item }) => - - + + } >

    @@ -221,13 +200,14 @@ const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, ShowEd
    - {props.ShowEdit ? + {props.Edit ? { return { Value: item.Value, Label: item.AltValue ?? item.Value } }) }/> + HandleSave={handleSave} /> : null} } diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx index 69741b39e..098b78450 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx @@ -165,7 +165,7 @@ const MeterLocationProperties = (props: IProps) => {
    - +
    Record={props.Location} diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index 9ea38cf63..ad4e2a781 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -484,7 +484,7 @@ export default function AssetPage(props: IProps) { Actions:
    - +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 43247f886..019f9179d 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -405,7 +405,7 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { else if (currentStep === assetStep || currentStep === connectionStep ) - return + return else if (currentStep >= additionalFieldMeterStep) { return (
    From 66e016e9afc0f3532ae3ef466b08d31b9ed3dc19 Mon Sep 17 00:00:00 2001 From: collins-self Date: Tue, 12 Nov 2024 13:48:21 -0500 Subject: [PATCH 19/50] moved some redundant functions --- .../LocationDrawingsModal.tsx | 1 - .../Location/AddEditDrawingsModal.tsx | 29 ++++++--- .../Location/LocationDrawings.tsx | 65 ++++++++----------- .../Location/LocationDrawingsTable.tsx | 50 +++++--------- 4 files changed, 62 insertions(+), 83 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 2c4e31870..33b194767 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -28,7 +28,6 @@ import { useAppDispatch, useAppSelector } from '../hooks'; import { CreateGuid } from '@gpa-gemstone/helper-functions'; import { CrossMark } from '@gpa-gemstone/gpa-symbols'; import LocationDrawingsTable from '../Location/LocationDrawingsTable'; -import AddEditDrawingsModal from '../Location/AddEditDrawingsModal'; interface IProps { Location: OpenXDA.Types.Location; diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx index 210d5b954..d6d8436b9 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx @@ -28,15 +28,24 @@ import React from "react"; interface IProps { Record: SystemCenter.Types.LocationDrawing, Setter: (record) => void, - Valid: (field) => boolean, HandleSave: () => void, Show: boolean, SetShow: (show: boolean) => void, } -const AddEditDrawingsModal = (props: IProps) => { // Change to modal +const AddEditDrawingsModal = (props: IProps) => { const [category, setCategory] = React.useState>([]); + function valid(field: keyof (SystemCenter.Types.LocationDrawing)): boolean { + if (field == 'Name') + return props.Record.Name != null && props.Record.Name.length > 0 && props.Record.Name.length <= 200; + else if (field == 'Link') + return props.Record.Link != null && props.Record.Link.length > 0; + else if (field == 'Number') + return props.Record.Number == null || props.Record.Number.length <= 50; + return true; + } + function getValueList(listName: string, setter: (value: Array) => void): JQuery.jqXHR> { let h = $.ajax({ type: "GET", @@ -65,29 +74,33 @@ const AddEditDrawingsModal = (props: IProps) => { // Change to modal { props.SetShow(false); if (conf) props.HandleSave(); }} ShowCancel={true} - ConfirmText={'Save Changes'}> + DisableConfirm={ + !(valid('Name') && + valid('Link') && + valid('Number'))} + ConfirmText={'Save'}> Record={props.Record} Field={'Name'} Feedback={'A Name of less than 200 characters is required.'} - Valid={props.Valid} + Valid={valid} Setter={(r) => props.Setter(r)} /> Record={props.Record} Field={'Link'} Feedback={'A Link is required.'} - Valid={props.Valid} + Valid={valid} Setter={(r) => props.Setter(r)} /> Record={props.Record} Field={'Description'} - Valid={props.Valid} + Valid={valid} Setter={(r) => props.Setter(r)} /> Record={props.Record} @@ -99,7 +112,7 @@ const AddEditDrawingsModal = (props: IProps) => { // Change to modal Record={props.Record} Field={'Number'} Feedback={'Number must be less than 50 characters.'} - Valid={props.Valid} + Valid={valid} AllowNull={true} Setter={(r) => props.Setter(r)} /> diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx index 70db4bf0f..3a40c413c 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx @@ -25,7 +25,7 @@ import * as React from 'react'; import * as _ from 'lodash'; import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings'; -import { ToolTip } from '@gpa-gemstone/react-interactive'; +import { GenericController, ToolTip } from '@gpa-gemstone/react-interactive'; import LocationDrawingsTable from './LocationDrawingsTable'; import { useAppSelector } from '../hooks'; import { SelectRoles } from '../Store/UserSettings'; @@ -38,6 +38,9 @@ const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) => const [record, setRecord] = React.useState(emptyRecord); const [hover, setHover] = React.useState<('Update' | 'Reset' | 'None')>('None'); const [showModal, setShowModal] = React.useState(false); + const [editMode, setEditMode] = React.useState(false); + const [updateTable, setUpdateTable] = React.useState(0); + const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); function hasPermissions(): boolean { if (roles.indexOf('Administrator') < 0 && roles.indexOf('Engineer') < 0) @@ -45,41 +48,16 @@ const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) => return true; } - const fetchDrawings = (sortKey: keyof SystemCenter.Types.LocationDrawing, ascending: boolean, page: number, locationID: number) => { - setPageState('loading'); - const handle = LocationDrawingController.PagedSearch([], sortKey, ascending, page, locationID) - .done((result) => { - setLinks(JSON.parse(result.Data as unknown as string)); - if (result.NumberOfPages === 0) result.NumberOfPages = 1; - setPageInfo(result); - setPageState('idle'); - }) - .fail(() => setPageState('error')); - return handle; - } - const handleSave = () => { - setPageState('loading'); - LocationDrawingController.DBAction('PATCH', record) - .then(() => { - fetchDrawings(sortKey, ascending, page, props.Location.ID); - }) - .catch(() => { - setPageState('error'); - }); + setShowModal(false); + setRecord(record); + editMode ? LocationDrawingController.DBAction('PATCH', record) + .done(() => {setUpdateTable(updateTable + 1)}) + : LocationDrawingController.DBAction('POST', record) + .done(() => {setUpdateTable(updateTable + 1)}); }; - function valid(field: keyof (SystemCenter.Types.LocationDrawing)): boolean { - if (field == 'Name') - return record.Name != null && record.Name.length > 0 && record.Name.length <= 200; - else if (field == 'Link') - return record.Link != null && record.Link.length > 0; - else if (field == 'Number') - return record.Number == null || record.Number.length <= 50; - return true; - } - - return ( + return (<>
    @@ -89,21 +67,32 @@ const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) =>
    - { setRecord(record) }} /> + { + setRecord(record); + setEditMode(true); + setShowModal(true); + }} + UpdateTable={updateTable} + />

    Your role does not have permission. Please contact your Administrator if you believe this to be in error.

    - - ); - + ); } export default LocationDrawingsWindow; \ No newline at end of file diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx index 0487a5a6e..ba0c4ea64 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx @@ -27,18 +27,23 @@ import { ReactTable, Paging } from "@gpa-gemstone/react-table"; import React from "react"; import { useAppSelector } from "../hooks"; import { SelectRoles } from "../Store/UserSettings"; -import AddEditDrawingsModal from "./AddEditDrawingsModal"; -const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, Edit?: (record: SystemCenter.Types.LocationDrawing) => void }) => { +interface IProps { + Location: OpenXDA.Types.Location, + Edit?: (record: SystemCenter.Types.LocationDrawing) => void, + /** + * @param UpdateTable Counter that triggers a fetchDrawings function + */ + UpdateTable?: number, +} + +const LocationDrawingsTable = (props: IProps) => { const [links, setLinks] = React.useState([]); const [sortKey, setSortKey] = React.useState('Name'); const [ascending, setAscending] = React.useState(true); - const [showModal, setShowModal] = React.useState(true); const [pageInfo, setPageInfo] = React.useState<{ RecordsPerPage: number, NumberOfPages: number, TotalRecords: number }>({ RecordsPerPage: 0, NumberOfPages: 0, TotalRecords: 0 }); const [pageState, setPageState] = React.useState<'error' | 'idle' | 'loading'>('idle'); const [page, setPage] = React.useState(0); - const emptyRecord: SystemCenter.Types.LocationDrawing = { ID: 0, LocationID: 0, Name: '', Link: '', Description: '', Number: '', Category: '' }; - const [record, setRecord] = React.useState(emptyRecord); const roles = useAppSelector(SelectRoles); // Deprecated const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); @@ -74,26 +79,10 @@ const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, Edit?: }); }; - const handleSave = () => { - setPageState('loading'); - LocationDrawingController.DBAction('PATCH', record) - .then(() => { - fetchDrawings(sortKey, ascending, page, props.Location.ID); - }) - .catch(() => { - setPageState('error'); - }); - }; - - function valid(field: keyof (SystemCenter.Types.LocationDrawing)): boolean { - if (field == 'Name') - return record.Name != null && record.Name.length > 0 && record.Name.length <= 200; - else if (field == 'Link') - return record.Link != null && record.Link.length > 0; - else if (field == 'Number') - return record.Number == null || record.Number.length <= 50; - return true; - } + React.useEffect(() => { + if (props.UpdateTable != undefined) + fetchDrawings(sortKey, ascending, page, props.Location.ID); + }, [props.UpdateTable]) React.useEffect(() => { const storedInfo = JSON.parse(localStorage.getItem(PagingID) as string); @@ -183,7 +172,7 @@ const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, Edit?: Content={({ item }) => + onClick={() => { props.Edit(item); }}>{Pencil} @@ -200,15 +189,6 @@ const LocationDrawingsTable = (props: { Location: OpenXDA.Types.Location, Edit?:
    - {props.Edit ? - - : null} } From 11b2ff7194cd9eefbd3c71d2185c887dd73eff97 Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 13 Nov 2024 10:53:10 -0500 Subject: [PATCH 20/50] added the SetRecord functionality --- .../LocationDrawingsModal.tsx | 25 ++++++------------- .../Location/LocationDrawings.tsx | 1 + .../Location/LocationDrawingsTable.tsx | 15 ++++++++--- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 33b194767..424bdc2bb 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -22,9 +22,7 @@ //****************************************************************************************************** import React from 'react'; import { OpenXDA } from '@gpa-gemstone/application-typings' -import { LocationDrawingSlice } from '../Store/Store'; -import { LoadingIcon, Modal, ToolTip } from '@gpa-gemstone/react-interactive'; -import { useAppDispatch, useAppSelector } from '../hooks'; +import { Modal, ToolTip } from '@gpa-gemstone/react-interactive'; import { CreateGuid } from '@gpa-gemstone/helper-functions'; import { CrossMark } from '@gpa-gemstone/gpa-symbols'; import LocationDrawingsTable from '../Location/LocationDrawingsTable'; @@ -34,27 +32,18 @@ interface IProps { } const LocationDrawingsModal = (props: IProps) => { - const dispatch = useAppDispatch(); const guid = React.useRef(CreateGuid()); - const drawingData = useAppSelector(LocationDrawingSlice.Data); - const drawingStatus = useAppSelector(LocationDrawingSlice.Status); - const drawingParentID = useAppSelector(LocationDrawingSlice.ParentID); - const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); const [errors, setErrors] = React.useState([]); const [showModal, setShowModal] = React.useState(false); const [disableButton, setDisableButton] = React.useState(false); + const [totalRecords, setTotalRecords] = React.useState(); React.useEffect(() => { setDisableButton(errors.length > 0); }, [errors]); - React.useEffect(() => { - if (drawingStatus == 'unintiated' || drawingStatus == 'changed' || drawingParentID != props.Location?.ID) - dispatch(LocationDrawingSlice.Fetch(props.Location?.ID)); - }, [props.Location, drawingStatus, drawingParentID]); - React.useEffect(() => { let e = []; @@ -67,11 +56,11 @@ const LocationDrawingsModal = (props: IProps) => { && props.Location.Longitude == null && props.Location.Name == "")) e.push('No locations have been set.'); - else if (drawingData.length == 0) + else if (totalRecords == 0) e.push('No drawings associated with selected location.'); setErrors(e); - }, [props.Location, drawingData]); + }, [props.Location, totalRecords]); return (
    @@ -102,8 +91,10 @@ const LocationDrawingsModal = (props: IProps) => { ConfirmText={'Done'}>
    - - + { setTotalRecords(r) }}/>
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx index 3a40c413c..09511f433 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx @@ -75,6 +75,7 @@ const LocationDrawingsWindow = (props: { Location: OpenXDA.Types.Location }) => setShowModal(true); }} UpdateTable={updateTable} + SetTotalRecords={() => {}} />
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx index ba0c4ea64..bfd8e8ca8 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx @@ -34,7 +34,13 @@ interface IProps { /** * @param UpdateTable Counter that triggers a fetchDrawings function */ - UpdateTable?: number, + UpdateTable: number, + /** + * Used to pass number of drawings up to be used in relevant setters. + * @param n number of records + * @returns + */ + SetTotalRecords: (n: number) => void; } const LocationDrawingsTable = (props: IProps) => { @@ -80,8 +86,11 @@ const LocationDrawingsTable = (props: IProps) => { }; React.useEffect(() => { - if (props.UpdateTable != undefined) - fetchDrawings(sortKey, ascending, page, props.Location.ID); + props.SetTotalRecords(pageInfo.TotalRecords); + }, [pageInfo]) + + React.useEffect(() => { + fetchDrawings(sortKey, ascending, page, props.Location.ID); }, [props.UpdateTable]) React.useEffect(() => { From d96ec5bbe7dce4f6753b886142f3fb95dae060dc Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 13 Nov 2024 12:57:49 -0500 Subject: [PATCH 21/50] Changed to just an ID prop --- .../CommonComponents/LocationDrawingsModal.tsx | 14 +++++++------- .../TSX/SystemCenter/Location/Location.tsx | 2 +- .../SystemCenter/Location/LocationDrawings.tsx | 8 ++++---- .../Location/LocationDrawingsTable.tsx | 17 +++++++++-------- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 424bdc2bb..68b573482 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -37,12 +37,8 @@ const LocationDrawingsModal = (props: IProps) => { const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); const [errors, setErrors] = React.useState([]); const [showModal, setShowModal] = React.useState(false); - const [disableButton, setDisableButton] = React.useState(false); const [totalRecords, setTotalRecords] = React.useState(); - - React.useEffect(() => { - setDisableButton(errors.length > 0); - }, [errors]); + const [disableButton, setDisableButton] = React.useState(false); React.useEffect(() => { let e = []; @@ -57,11 +53,15 @@ const LocationDrawingsModal = (props: IProps) => { && props.Location.Name == "")) e.push('No locations have been set.'); else if (totalRecords == 0) - e.push('No drawings associated with selected location.'); + e.push('No drawings associated with location.'); setErrors(e); }, [props.Location, totalRecords]); + React.useEffect(() => { + setDisableButton(errors.length > 0); + }, [errors]); + return (
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx index e0f208219..5aa2a0c73 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx @@ -86,14 +86,9 @@ const LocationDrawingsTable = (props: IProps) => { }; React.useEffect(() => { - console.log('called') props.SetTotalRecords(pageInfo.TotalRecords); }, [pageInfo.TotalRecords]); - React.useEffect(() => { - fetchDrawings(sortKey, ascending, page, props.LocationID); - }, [props.UpdateTable]); - React.useEffect(() => { const storedInfo = JSON.parse(localStorage.getItem(PagingID) as string); if (storedInfo != null) setPage(storedInfo); @@ -104,9 +99,10 @@ const LocationDrawingsTable = (props: IProps) => { }, [page]); React.useEffect(() => { + fetchDrawings(sortKey, ascending, page, props.LocationID); const handle = fetchDrawings(sortKey, ascending, page, props.LocationID); return () => { if (handle != null && handle?.abort != null) handle.abort(); } - }, [sortKey, ascending, page, props.LocationID]); + }, [sortKey, ascending, page, props.LocationID, props.UpdateTable]); return <>
    From df67bfc5a10f9e91001bdb5362f633314cbd7298 Mon Sep 17 00:00:00 2001 From: collins-self Date: Mon, 25 Nov 2024 16:15:38 -0500 Subject: [PATCH 23/50] functional as single button --- .../LocationDrawingsModal.tsx | 62 +++++++++---------- .../Location/LocationDrawings.tsx | 1 - .../Location/LocationDrawingsTable.tsx | 12 +--- 3 files changed, 32 insertions(+), 43 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 583bcd083..f3c2126e2 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -29,6 +29,11 @@ import LocationDrawingsTable from '../Location/LocationDrawingsTable'; interface IProps { Location: OpenXDA.Types.Location; + /** + * @param Show Shows if equal to location ID + */ + Show: number; + ID: number; } const LocationDrawingsModal = (props: IProps) => { @@ -37,41 +42,35 @@ const LocationDrawingsModal = (props: IProps) => { const [errors, setErrors] = React.useState([]); const [showModal, setShowModal] = React.useState(false); const [pageState, setPageState] = React.useState<"loading" | "error" | "idle">("idle"); - const [totalRecords, setTotalRecords] = React.useState(); const [disableButton, setDisableButton] = React.useState(false); const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); - const fetchDrawings = (sortKey: keyof SystemCenter.Types.LocationDrawing, ascending: boolean, page: number, locationID: number) => { - setPageState('loading'); - LocationDrawingController.PagedSearch([], sortKey, ascending, page, locationID) - .done((result) => { - setTotalRecords(JSON.parse(result.Data as unknown as string).TotalRecords); - setPageState('idle'); - }) - .fail(() => setPageState('error')); - } - - React.useEffect(() => { - fetchDrawings('Name', true, 1, props.Location?.ID); - }, []) - - React.useEffect(() => { + const isValid = (drawingData) => { let e = []; if (props.Location == undefined || (props.Location.Alias == "" - && props.Location.Description == "" - && props.Location.ID == 0 - && props.Location.Latitude == null - && props.Location.LocationKey == "" - && props.Location.Longitude == null - && props.Location.Name == "")) + && props.Location.Description == "" + && props.Location.ID == 0 + && props.Location.Latitude == null + && props.Location.LocationKey == "" + && props.Location.Longitude == null + && props.Location.Name == "")) e.push('No locations have been set.'); - else if (totalRecords == 0) + else if (drawingData.TotalRecords == 0) e.push('No drawings associated with location.'); + return e; + } - setErrors(e); - }, [props.Location, totalRecords]); + React.useEffect(() => { + setPageState('loading'); + LocationDrawingController.PagedSearch([], 'Name', true, 1, props.Location?.ID) + .done((result) => { + setErrors(isValid(result)); + setPageState('idle'); + }) + .fail(() => setPageState('error')); + }, [props.Location]) React.useEffect(() => { setDisableButton(errors.length > 0); @@ -82,7 +81,6 @@ const LocationDrawingsModal = (props: IProps) => { - {errors.map((e, i) =>

    {CrossMark} {e}

    )} + Theme={'dark'} + Position={'top'} + Target={guid.current} + Zindex={9999} + > {errors.map((e, i) =>

    {CrossMark} {e}

    )}
    setShowModal(false)} @@ -111,7 +112,6 @@ const LocationDrawingsModal = (props: IProps) => {
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx index c9b05c070..edec5f1b8 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx @@ -75,7 +75,6 @@ const LocationDrawingsWindow = (props: { LocationID: number }) => { setShowModal(true); }} UpdateTable={updateTable} - SetTotalRecords={() => {}} />
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx index 5aa2a0c73..2b39fe937 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx @@ -34,13 +34,7 @@ interface IProps { /** * @param UpdateTable Counter that triggers a fetchDrawings function */ - UpdateTable: number, - /** - * Used to pass number of drawings up to be used in relevant setters. - * @param n number of records - * @returns - */ - SetTotalRecords: (n: number) => void; + UpdateTable: number } const LocationDrawingsTable = (props: IProps) => { @@ -85,10 +79,6 @@ const LocationDrawingsTable = (props: IProps) => { }); }; - React.useEffect(() => { - props.SetTotalRecords(pageInfo.TotalRecords); - }, [pageInfo.TotalRecords]); - React.useEffect(() => { const storedInfo = JSON.parse(localStorage.getItem(PagingID) as string); if (storedInfo != null) setPage(storedInfo); From a86ed29ac37257d567ea02adec773dd4ae18229b Mon Sep 17 00:00:00 2001 From: collins-self Date: Tue, 26 Nov 2024 16:19:51 -0500 Subject: [PATCH 24/50] removed the button from modal comp --- .../SystemCenter/Asset/AssetConnection.tsx | 36 ++++++++++++++++--- .../LocationDrawingsModal.tsx | 29 +++++---------- .../PropertyUI/MeterLocationProperties.tsx | 16 ++++++++- .../SystemCenter/NewMeterWizard/AssetPage.tsx | 16 ++++++++- .../NewMeterWizard/NewMeterWizard.tsx | 17 ++++++++- 5 files changed, 86 insertions(+), 28 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index 5a9a34046..bd726e0ce 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -25,7 +25,7 @@ import * as React from 'react'; import _ from 'lodash'; import { Table, Column } from '@gpa-gemstone/react-table'; import { useHistory } from "react-router-dom"; -import { LoadingIcon, Modal, Search, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive'; +import { BtnDropdown, LoadingIcon, Modal, Search, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive'; import { TrashCan } from '@gpa-gemstone/gpa-symbols' import { OpenXDA } from '@gpa-gemstone/application-typings'; import { useAppSelector, useAppDispatch } from '../hooks'; @@ -51,7 +51,11 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number const [selectedAssetID, setSelectedAssetID] = React.useState(0); const [selectedTypeID, setSelectedtypeID] = React.useState(0); const [localAssets, setLocalAssets] = React.useState>([]); + const [locations, setLocations] = React.useState([]); + const [showDrawingsModal, setShowDrawingsModal] = React.useState(false); + const [selectedLocation, setSelectedLocation] = React.useState(); + const [disableDrawingButton, setDisableDrawingButton] = React.useState(false); const [sortKey, setSortKey] = React.useState('AssetKey'); const [ascending, setAscending] = React.useState(true); @@ -247,6 +251,10 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number
    const connectionsAvailable = !(assetConnectionTypes == undefined) && (assetConnectionTypes.length > 0); + const handleShowDrawingsModal = (loc: OpenXDA.Types.Location) => { + setSelectedLocation(loc); + setShowDrawingsModal(true); + } return (
    @@ -255,9 +263,29 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number

    Connections:

    - - - + handleShowDrawingsModal(locations[0])} + Disabled={disableDrawingButton} // TODO: get from modal componenet + //ToolTipContent={} // TODO: + ShowToolTip={false} // TODO: hover + BtnClass={disableDrawingButton ? 'btn btn-primary disabled' : 'btn btn-primary'} + Options={locations.slice(1).map((loc, i) => ({ + Label: 'Open ' + loc?.Name + ' Drawings', + Callback: () => handleShowDrawingsModal(loc), + Disabled: disableDrawingButton, // TODO: + //ToolTipContent={}, + ShowToolTip: false, //TODO: + ToolTipLocation: 'left', + Key: i + }))} + /> +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index f3c2126e2..83ff9a5ae 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -32,17 +32,16 @@ interface IProps { /** * @param Show Shows if equal to location ID */ - Show: number; - ID: number; + Show: boolean; + SetShow: (b: boolean) => void; + SetDisabled: (b: boolean) => void; } const LocationDrawingsModal = (props: IProps) => { const guid = React.useRef(CreateGuid()); const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); const [errors, setErrors] = React.useState([]); - const [showModal, setShowModal] = React.useState(false); const [pageState, setPageState] = React.useState<"loading" | "error" | "idle">("idle"); - const [disableButton, setDisableButton] = React.useState(false); const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); const isValid = (drawingData) => { @@ -73,38 +72,26 @@ const LocationDrawingsModal = (props: IProps) => { }, [props.Location]) React.useEffect(() => { - setDisableButton(errors.length > 0); + props.SetDisabled(errors.length > 0); }, [errors]); return (
    - {errors.map((e, i) =>

    {CrossMark} {e}

    )} + > {errors.map((e, i) =>

    {CrossMark} {e}

    )}
    setShowModal(false)} + CallBack={() => props.SetShow(false)} ShowCancel={false} ConfirmText={'Done'}>
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx index 098b78450..6ca98f759 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx @@ -50,6 +50,9 @@ const MeterLocationProperties = (props: IProps) => { const [validKey, setValidKey] = React.useState(true); const [showStationSelector, setShowStationSelector] = React.useState(false); const [hover, setHover] = React.useState<('submit' | 'clear' | 'none')>('none'); + const [showDrawingsModal, setShowDrawingsModal] = React.useState(); + const [disableDrawingButton, setDisableDrawingButton] = React.useState(false); + const roles = useAppSelector(SelectRoles); React.useEffect(() => { @@ -165,7 +168,18 @@ const MeterLocationProperties = (props: IProps) => {
    - + +
    Record={props.Location} diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index ad4e2a781..86b31724a 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -82,6 +82,9 @@ export default function AssetPage(props: IProps) { const [newEdit, setNewEdit] = React.useState<'New' | 'Edit'>('New'); const [showAssetModal, setShowAssetModal] = React.useState(false); + const [showDrawingsModal, setShowDrawingsModal] = React.useState(); + const [disableDrawingButton, setDisableDrawingButton] = React.useState(false); + const [showAssetSelect, setShowAssetSelect] = React.useState(false); const [selectedAssets, setSelectedAssets] = React.useState([]); @@ -484,7 +487,18 @@ export default function AssetPage(props: IProps) { Actions:
    - + +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 019f9179d..58b33598a 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -97,6 +97,8 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { const [hover, setHover] = React.useState<'None' | 'Next' | 'Prev'>('None'); const [showSubmit, setShowSubmit] = React.useState(false); const [status, setStatus] = React.useState('unintiated'); + const [showDrawingsModal, setShowDrawingsModal] = React.useState(); + const [disableDrawingButton, setDisableDrawingButton] = React.useState(false); React.useEffect(() => { if (mStatus === 'unintiated' || mStatus === 'changed') @@ -405,7 +407,20 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { else if (currentStep === assetStep || currentStep === connectionStep ) - return + return (<> + + + ) else if (currentStep >= additionalFieldMeterStep) { return (
    From 93cba9dab2fc00770c5f816f980d2dea80eef4e8 Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 27 Nov 2024 12:20:21 -0500 Subject: [PATCH 25/50] ToolTips and Error --- .../SystemCenter/Asset/AssetConnection.tsx | 18 ++++++++-------- .../LocationDrawingsModal.tsx | 19 +++-------------- .../PropertyUI/MeterLocationProperties.tsx | 21 ++++++++++++++----- .../SystemCenter/NewMeterWizard/AssetPage.tsx | 20 +++++++++++++----- .../NewMeterWizard/NewMeterWizard.tsx | 20 +++++++++++++----- 5 files changed, 58 insertions(+), 40 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index bd726e0ce..e285d8c21 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -26,7 +26,7 @@ import _ from 'lodash'; import { Table, Column } from '@gpa-gemstone/react-table'; import { useHistory } from "react-router-dom"; import { BtnDropdown, LoadingIcon, Modal, Search, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive'; -import { TrashCan } from '@gpa-gemstone/gpa-symbols' +import { CrossMark, TrashCan } from '@gpa-gemstone/gpa-symbols' import { OpenXDA } from '@gpa-gemstone/application-typings'; import { useAppSelector, useAppDispatch } from '../hooks'; import { AssetConnectionTypeSlice } from '../Store/Store'; @@ -55,7 +55,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number const [locations, setLocations] = React.useState([]); const [showDrawingsModal, setShowDrawingsModal] = React.useState(false); const [selectedLocation, setSelectedLocation] = React.useState(); - const [disableDrawingButton, setDisableDrawingButton] = React.useState(false); + const [drawingsModalErrors, setDrawingsModalErrors] = React.useState([]); const [sortKey, setSortKey] = React.useState('AssetKey'); const [ascending, setAscending] = React.useState(true); @@ -65,7 +65,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number const actStatus = useAppSelector(AssetConnectionTypeSlice.SearchStatus); const [trigger, setTrigger] = React.useState(0); - const [hover, setHover] = React.useState<('Update' | 'Reset' | 'None')>('None'); + const [hover, setHover] = React.useState<('Update' | 'Reset' | 'None' | 'Drawings')>('None'); const roles = useAppSelector(SelectRoles); React.useEffect(() => { @@ -266,14 +266,14 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number handleShowDrawingsModal(locations[0])} - Disabled={disableDrawingButton} // TODO: get from modal componenet - //ToolTipContent={} // TODO: - ShowToolTip={false} // TODO: hover - BtnClass={disableDrawingButton ? 'btn btn-primary disabled' : 'btn btn-primary'} + TooltipContent={<>{ + drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    ) + }} + ShowToolTip={drawingsModalErrors.length > 0 && hover === 'Drawings'} + BtnClass={drawingsModalErrors.length > 0 ? 'btn btn-primary disabled' : 'btn btn-primary'} Options={locations.slice(1).map((loc, i) => ({ Label: 'Open ' + loc?.Name + ' Drawings', Callback: () => handleShowDrawingsModal(loc), - Disabled: disableDrawingButton, // TODO: //ToolTipContent={}, ShowToolTip: false, //TODO: ToolTipLocation: 'left', @@ -284,7 +284,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number Location={selectedLocation} Show={showDrawingsModal} SetShow={setShowDrawingsModal} - SetDisabled={setDisableDrawingButton} + Errors={setDrawingsModalErrors} />
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 83ff9a5ae..36dc498e4 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -29,17 +29,12 @@ import LocationDrawingsTable from '../Location/LocationDrawingsTable'; interface IProps { Location: OpenXDA.Types.Location; - /** - * @param Show Shows if equal to location ID - */ Show: boolean; SetShow: (b: boolean) => void; - SetDisabled: (b: boolean) => void; + Errors: (e: string[]) => void; } const LocationDrawingsModal = (props: IProps) => { - const guid = React.useRef(CreateGuid()); - const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); const [errors, setErrors] = React.useState([]); const [pageState, setPageState] = React.useState<"loading" | "error" | "idle">("idle"); const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); @@ -69,24 +64,16 @@ const LocationDrawingsModal = (props: IProps) => { setPageState('idle'); }) .fail(() => setPageState('error')); - }, [props.Location]) + }, [props.Location?.ID]) React.useEffect(() => { - props.SetDisabled(errors.length > 0); + props.Errors(errors); }, [errors]); return (
    - {errors.map((e, i) =>

    {CrossMark} {e}

    )} -
    { const [validKey, setValidKey] = React.useState(true); const [showStationSelector, setShowStationSelector] = React.useState(false); - const [hover, setHover] = React.useState<('submit' | 'clear' | 'none')>('none'); + const [hover, setHover] = React.useState<('submit' | 'clear' | 'none' | 'drawings')>('none'); const [showDrawingsModal, setShowDrawingsModal] = React.useState(); - const [disableDrawingButton, setDisableDrawingButton] = React.useState(false); + const [drawingsModalErrors, setDrawingsModalErrors] = React.useState([]); const roles = useAppSelector(SelectRoles); @@ -169,16 +170,26 @@ const MeterLocationProperties = (props: IProps) => {
    + 0 && hover === 'drawings'} + Theme={'dark'} + Position={'top'} + Target={"DrawingsModal"} + Zindex={9999} + > {drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    )} +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index 86b31724a..c69cf98ee 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -41,7 +41,6 @@ import AssetSelect from '../Asset/AssetSelect'; import { ReactIcons } from '@gpa-gemstone/gpa-symbols'; import { getAssetWithAdditionalFields } from '../../../TS/Services/Asset'; import LocationDrawingsModal from '../CommonComponents/LocationDrawingsModal'; -import { GetNodeSize } from '@gpa-gemstone/helper-functions'; import { ReactTable } from '@gpa-gemstone/react-table'; import GenerationAttributes from '../AssetAttribute/Generation'; import StationAuxAttributes from '../AssetAttribute/StationAux'; @@ -83,7 +82,8 @@ export default function AssetPage(props: IProps) { const [showAssetModal, setShowAssetModal] = React.useState(false); const [showDrawingsModal, setShowDrawingsModal] = React.useState(); - const [disableDrawingButton, setDisableDrawingButton] = React.useState(false); + const [drawingsModalErrors, setDrawingsModalErrors] = React.useState([]); + const [hover, setHover] = React.useState<'none' | 'drawings'>(); const [showAssetSelect, setShowAssetSelect] = React.useState(false); const [selectedAssets, setSelectedAssets] = React.useState([]); @@ -488,16 +488,26 @@ export default function AssetPage(props: IProps) {
    + 0 && hover == 'drawings'} + Theme={'dark'} + Position={'top'} + Zindex={9999} + Target={"DrawingsModal"} + > {drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    )} +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 58b33598a..ee18696ab 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -94,11 +94,11 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { // Wizard Page Control const [error, setError] = React.useState([]); const [warning, setWarning] = React.useState([]); - const [hover, setHover] = React.useState<'None' | 'Next' | 'Prev'>('None'); + const [hover, setHover] = React.useState<'None' | 'Next' | 'Prev' | 'Drawings'>('None'); const [showSubmit, setShowSubmit] = React.useState(false); const [status, setStatus] = React.useState('unintiated'); const [showDrawingsModal, setShowDrawingsModal] = React.useState(); - const [disableDrawingButton, setDisableDrawingButton] = React.useState(false); + const [drawingsModalErrors, setDrawingsModalErrors] = React.useState([]); React.useEffect(() => { if (mStatus === 'unintiated' || mStatus === 'changed') @@ -409,16 +409,26 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { ) return (<> + 0 && hover == 'Drawings'} + Theme={'dark'} + Position={'top'} + Zindex={9999} + Target={"DrawingsModal"} + > {drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    )} +
    ) else if (currentStep >= additionalFieldMeterStep) { From 0244e5fc0f6f5c8d7b9171226209dbb492d40ee8 Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 27 Nov 2024 12:39:03 -0500 Subject: [PATCH 26/50] fixed hover for AssetConnection --- .../TSX/SystemCenter/Asset/AssetConnection.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index e285d8c21..2ca04b6b1 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -269,13 +269,16 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number TooltipContent={<>{ drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    ) }} - ShowToolTip={drawingsModalErrors.length > 0 && hover === 'Drawings'} - BtnClass={drawingsModalErrors.length > 0 ? 'btn btn-primary disabled' : 'btn btn-primary'} + ShowToolTip={drawingsModalErrors.length > 0} + Disabled={drawingsModalErrors.length > 0} + BtnClass={'btn-primary'} Options={locations.slice(1).map((loc, i) => ({ Label: 'Open ' + loc?.Name + ' Drawings', Callback: () => handleShowDrawingsModal(loc), - //ToolTipContent={}, - ShowToolTip: false, //TODO: + ToolTipContent: <>{ + drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    ) + }, + ShowToolTip: drawingsModalErrors.length > 0, ToolTipLocation: 'left', Key: i }))} From f88b3952c556c61cb5818aad0935b9a945d4a700 Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 27 Nov 2024 14:16:56 -0500 Subject: [PATCH 27/50] map --- .../SystemCenter/Asset/AssetConnection.tsx | 29 ++++++++++++++----- .../LocationDrawingsModal.tsx | 16 ++++++++-- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index 2ca04b6b1..882306b27 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -55,7 +55,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number const [locations, setLocations] = React.useState([]); const [showDrawingsModal, setShowDrawingsModal] = React.useState(false); const [selectedLocation, setSelectedLocation] = React.useState(); - const [drawingsModalErrors, setDrawingsModalErrors] = React.useState([]); + const [locationsWithErrors, setLocationsWithErrors] = React.useState>(new Map()) const [sortKey, setSortKey] = React.useState('AssetKey'); const [ascending, setAscending] = React.useState(true); @@ -255,6 +255,16 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number setSelectedLocation(loc); setShowDrawingsModal(true); } + const handleAddLocationError = (locMap: Map) => { + setLocationsWithErrors(prev => new Map([...prev, ...locMap])); + } + const handleRemoveLocationError = (loc: OpenXDA.Types.Location) => { + setLocationsWithErrors(prev => { + const newMap = new Map(prev); + newMap.delete(loc); + return newMap; + }); + } return (
    @@ -267,19 +277,20 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number Label={'Open ' + locations[0]?.Name + ' Drawings'} Callback={() => handleShowDrawingsModal(locations[0])} TooltipContent={<>{ - drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    ) + locationsWithErrors.get(locations[0])?.map((e, i) =>

    {CrossMark} {e}

    ) }} - ShowToolTip={drawingsModalErrors.length > 0} - Disabled={drawingsModalErrors.length > 0} + ShowToolTip={locationsWithErrors.has(locations[0])} + Disabled={locationsWithErrors.has(locations[0])} BtnClass={'btn-primary'} Options={locations.slice(1).map((loc, i) => ({ Label: 'Open ' + loc?.Name + ' Drawings', Callback: () => handleShowDrawingsModal(loc), + Disabled: locationsWithErrors.has(loc), ToolTipContent: <>{ - drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    ) + locationsWithErrors.get(loc)?.map((e, i) =>

    {CrossMark} {e}

    ) }, - ShowToolTip: drawingsModalErrors.length > 0, - ToolTipLocation: 'left', + ShowToolTip: locationsWithErrors.has(loc), + ToolTipLocation: "left", Key: i }))} /> @@ -287,7 +298,9 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number Location={selectedLocation} Show={showDrawingsModal} SetShow={setShowDrawingsModal} - Errors={setDrawingsModalErrors} + Errors={() => {}} + AddLocationWithErrors={handleAddLocationError} + RemoveLocationWithErrors={handleRemoveLocationError} />
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 36dc498e4..e82e3b874 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -22,9 +22,7 @@ //****************************************************************************************************** import React from 'react'; import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings' -import { GenericController, LoadingScreen, Modal, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive'; -import { CreateGuid } from '@gpa-gemstone/helper-functions'; -import { CrossMark } from '@gpa-gemstone/gpa-symbols'; +import { GenericController, LoadingScreen, Modal, ServerErrorIcon } from '@gpa-gemstone/react-interactive'; import LocationDrawingsTable from '../Location/LocationDrawingsTable'; interface IProps { @@ -32,6 +30,11 @@ interface IProps { Show: boolean; SetShow: (b: boolean) => void; Errors: (e: string[]) => void; + /** + * For use with multiple LocationDrawingsModal's + */ + AddLocationWithErrors?: (locationErrorsMap: Map) => void; + RemoveLocationWithErrors?: (l: OpenXDA.Types.Location) => void; } const LocationDrawingsModal = (props: IProps) => { @@ -68,6 +71,13 @@ const LocationDrawingsModal = (props: IProps) => { React.useEffect(() => { props.Errors(errors); + + const locationErrorsMap = new Map(); + locationErrorsMap.set(props.Location, errors); + + if (errors.length > 0 && props.Location != undefined) + props.AddLocationWithErrors?.(locationErrorsMap); + else props.RemoveLocationWithErrors?.(props.Location); }, [errors]); return ( From 574cbd6e9ba1845131fa919e95c3e5651bf18d29 Mon Sep 17 00:00:00 2001 From: collins-self Date: Mon, 2 Dec 2024 14:14:24 -0500 Subject: [PATCH 28/50] modified disable --- .../SystemCenter/CommonComponents/LocationDrawingsModal.tsx | 4 ++-- .../TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index e82e3b874..bd53b4944 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -63,7 +63,8 @@ const LocationDrawingsModal = (props: IProps) => { setPageState('loading'); LocationDrawingController.PagedSearch([], 'Name', true, 1, props.Location?.ID) .done((result) => { - setErrors(isValid(result)); + const validationErrors = isValid(result); + setErrors(validationErrors); setPageState('idle'); }) .fail(() => setPageState('error')); @@ -71,7 +72,6 @@ const LocationDrawingsModal = (props: IProps) => { React.useEffect(() => { props.Errors(errors); - const locationErrorsMap = new Map(); locationErrorsMap.set(props.Location, errors); diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index ee18696ab..698802a92 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -410,7 +410,10 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { return (<>
    const connectionsAvailable = !(assetConnectionTypes == undefined) && (assetConnectionTypes.length > 0); - const handleShowDrawingsModal = (loc: OpenXDA.Types.Location) => { - setSelectedLocation(loc); - setShowDrawingsModal(true); - } - const handleAddLocationError = (locMap: Map) => { - setLocationsWithErrors(prev => new Map([...prev, ...locMap])); - } - const handleRemoveLocationError = (loc: OpenXDA.Types.Location) => { - setLocationsWithErrors(prev => { - const newMap = new Map(prev); - newMap.delete(loc); - return newMap; - }); - } return (
    @@ -273,35 +256,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number

    Connections:

    - handleShowDrawingsModal(locations[0])} - TooltipContent={<>{ - locationsWithErrors.get(locations[0])?.map((e, i) =>

    {CrossMark} {e}

    ) - }} - ShowToolTip={locationsWithErrors.has(locations[0])} - Disabled={locationsWithErrors.has(locations[0])} - BtnClass={'btn-primary'} - Options={locations.slice(1).map((loc, i) => ({ - Label: 'Open ' + loc?.Name + ' Drawings', - Callback: () => handleShowDrawingsModal(loc), - Disabled: locationsWithErrors.has(loc), - ToolTipContent: <>{ - locationsWithErrors.get(loc)?.map((e, i) =>

    {CrossMark} {e}

    ) - }, - ShowToolTip: locationsWithErrors.has(loc), - ToolTipLocation: "left", - Key: i - }))} - /> - {}} - AddLocationWithErrors={handleAddLocationError} - RemoveLocationWithErrors={handleRemoveLocationError} - /> +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx new file mode 100644 index 000000000..7455ae8b1 --- /dev/null +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -0,0 +1,147 @@ +import React from 'react'; +import { BtnDropdown, GenericController, LoadingScreen, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive'; +import LocationDrawingsModal from './LocationDrawingsModal'; +import { OpenXDA } from '@gpa-gemstone/application-typings'; +import { CrossMark } from '@gpa-gemstone/gpa-symbols'; + +interface LocationDrawingsButtonProps { + Locations: OpenXDA.Types.Location[]; +} + +const LocationDrawingsButton: React.FC = (props) => { + const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); + const [pageState, setPageState] = React.useState<"loading" | "error" | "idle">("idle"); + const [selectedLocation, setSelectedLocation] = React.useState(); + const [multipleLocations, setMultipleLocations] = React.useState(false); + const [showDrawingsModal, setShowDrawingsModal] = React.useState(false); + const [locationsWithErrors, setLocationsWithErrors] = React.useState>(new Map()) + const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); + + const isValid = (location, drawingData) => { + let e = []; + + if (location == undefined + || (location.Alias == "" + && location.Description == "" + && location.ID == 0 + && location.Latitude == null + && location.LocationKey == "" + && location.Longitude == null + && location.Name == "")) + e.push('No locations have been set.'); + else if (drawingData.TotalRecords == 0) + e.push('No drawings associated with location.'); + return e; + } + + React.useEffect(() => { // Generates the map of errors for each location + if (props.Locations.length > 1) setMultipleLocations(true); + else setMultipleLocations(false); // TODO: check for undefined location isValid is not doing it + for (const location of props.Locations) { + if (location?.ID) { + setPageState('loading'); + LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) + .done((result) => { + const errors = isValid(location, result); + updateLocationErrors(location, errors); + setPageState('idle') + }) + .fail(() => setPageState('error')); + } + } + }, [props.Locations]); + + const handleAddLocationError = (locMap: Map) => { + setLocationsWithErrors(prev => { + const newMap = new Map(prev); + locMap.forEach((errors, loc) => { + if (newMap.has(loc)) { + const existingErrors = newMap.get(loc); + newMap.set(loc, Array.from(new Set([...existingErrors, ...errors]))); + } else { + newMap.set(loc, errors); + } + }); + return newMap; + }); + } + + const handleRemoveLocationError = (loc: OpenXDA.Types.Location) => { + setLocationsWithErrors(prev => { + const newMap = new Map(prev); + newMap.delete(loc); + return newMap; + }); + } + + const updateLocationErrors = (loc: OpenXDA.Types.Location, errors: string[]) => { + if (errors.length > 0 && loc != undefined) { + const locationErrorsMap = new Map(); + locationErrorsMap.set(loc, errors); + handleAddLocationError(locationErrorsMap); + } else { + handleRemoveLocationError(loc); + } + } + + const handleShowDrawingsModal = (loc) => { + if (loc == undefined) return; + setSelectedLocation(loc); + setShowDrawingsModal(true); + }; + + return ( +
    + + + {!multipleLocations + ? <> + + 0 && hover === 'drawings'} + Theme={'dark'} + Position={'top'} + Target={"DrawingsModal"} + Zindex={9999} + > {locationsWithErrors.get(props.Locations[0])?.map((e, i) =>

    {CrossMark} {e}

    )} +
    + + : handleShowDrawingsModal(props.Locations[0])} + TooltipContent={ + <>{locationsWithErrors.get(props.Locations[0])?.map((e, i) =>

    {CrossMark} {e}

    )} + } + ShowToolTip={locationsWithErrors.has(props.Locations[0])} + Disabled={locationsWithErrors.has(props.Locations[0])} + BtnClass={'btn-primary'} + Options={props.Locations.slice(1).map((loc, i) => ({ + Label: 'Open ' + loc?.Name + ' Drawings', + Callback: () => handleShowDrawingsModal(loc), + Disabled: locationsWithErrors.has(loc), + ToolTipContent: <>{ + locationsWithErrors.get(loc)?.map((e, i) =>

    {CrossMark} {e}

    ) + }, + ShowToolTip: locationsWithErrors.has(loc), + ToolTipLocation: "left", + Key: i + }))} + /> + } + +
    + ); +}; + +export default LocationDrawingsButton; \ No newline at end of file diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 5dacdbca5..756706bde 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -21,86 +21,33 @@ // //****************************************************************************************************** import React from 'react'; -import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings' -import { GenericController, LoadingScreen, Modal, ServerErrorIcon } from '@gpa-gemstone/react-interactive'; +import { Modal } from '@gpa-gemstone/react-interactive'; import LocationDrawingsTable from '../Location/LocationDrawingsTable'; interface IProps { - Location: OpenXDA.Types.Location; + LocationID: number; Show: boolean; SetShow: (b: boolean) => void; - /** For use when keeping track of a single Location's error to display */ - Errors: (e: string[]) => void; - /** For use with multiple locations with multiple LocationDrawingsModal's */ - AddLocationWithErrors?: (locationErrorsMap: Map) => void; - /** For use with multiple locations with multiple LocationDrawingsModal's */ - RemoveLocationWithErrors?: (locationErrorsMap: OpenXDA.Types.Location) => void; } const LocationDrawingsModal = (props: IProps) => { - const [errors, setErrors] = React.useState([]); - const [pageState, setPageState] = React.useState<"loading" | "error" | "idle">("idle"); - const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); - - const isValid = (drawingData) => { - let e = []; - - if (props.Location == undefined - || (props.Location.Alias == "" - && props.Location.Description == "" - && props.Location.ID == 0 - && props.Location.Latitude == null - && props.Location.LocationKey == "" - && props.Location.Longitude == null - && props.Location.Name == "")) - e.push('No locations have been set.'); - else if (drawingData.TotalRecords == 0) - e.push('No drawings associated with location.'); - return e; - } - - React.useEffect(() => { - setPageState('loading'); - LocationDrawingController.PagedSearch([], 'Name', true, 1, props.Location?.ID) - .done((result) => { - const validationErrors = isValid(result); - setErrors(validationErrors); - setPageState('idle'); - }) - .fail(() => setPageState('error')); - }, [props.Location?.ID]) - - React.useEffect(() => { - props.Errors(errors); - const locationErrorsMap = new Map(); - locationErrorsMap.set(props.Location, errors); - - if (errors.length > 0 && props.Location != undefined) - props.AddLocationWithErrors?.(locationErrorsMap); - else props.RemoveLocationWithErrors?.(props.Location); - }, [errors]); - return ( -
    - - - props.SetShow(false)} - ShowCancel={false} - ConfirmText={'Done'}> -
    -
    - -
    + props.SetShow(false)} + ShowCancel={false} + ConfirmText={'Done'}> +
    +
    +
    - -
    +
    +
    ) } export default LocationDrawingsModal; \ No newline at end of file diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx index f11445b32..36aa07c34 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx @@ -29,11 +29,10 @@ import { Input, TextArea } from '@gpa-gemstone/react-forms'; import { AssetAttributes } from '../../AssetAttribute/Asset'; import { DefaultSelects } from '@gpa-gemstone/common-pages'; import { ByLocationSlice } from '../../Store/Store'; -import LocationDrawingsModal from '../../CommonComponents/LocationDrawingsModal'; import { useAppSelector } from '../../hooks'; import { SelectRoles } from '../../Store/UserSettings'; import { ToolTip } from '@gpa-gemstone/react-interactive'; -import { CrossMark } from '@gpa-gemstone/gpa-symbols'; +import LocationDrawingsButton from '../../CommonComponents/LocationDrawingsButton'; import { Column } from '@gpa-gemstone/react-table'; declare var homePath: string; @@ -50,9 +49,7 @@ interface IProps { const MeterLocationProperties = (props: IProps) => { const [validKey, setValidKey] = React.useState(true); const [showStationSelector, setShowStationSelector] = React.useState(false); - const [hover, setHover] = React.useState<('submit' | 'clear' | 'none' | 'drawings')>('none'); - const [showDrawingsModal, setShowDrawingsModal] = React.useState(); - const [drawingsModalErrors, setDrawingsModalErrors] = React.useState([]); + const [hover, setHover] = React.useState<('submit' | 'clear' | 'none')>('none'); const roles = useAppSelector(SelectRoles); @@ -169,27 +166,8 @@ const MeterLocationProperties = (props: IProps) => {
    - - 0 && hover === 'drawings'} - Theme={'dark'} - Position={'top'} - Target={"DrawingsModal"} - Zindex={9999} - > {drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    )} -
    -
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index c69cf98ee..4c6d2fd0f 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -40,12 +40,12 @@ import DERAttributes from '../AssetAttribute/DER'; import AssetSelect from '../Asset/AssetSelect'; import { ReactIcons } from '@gpa-gemstone/gpa-symbols'; import { getAssetWithAdditionalFields } from '../../../TS/Services/Asset'; -import LocationDrawingsModal from '../CommonComponents/LocationDrawingsModal'; import { ReactTable } from '@gpa-gemstone/react-table'; import GenerationAttributes from '../AssetAttribute/Generation'; import StationAuxAttributes from '../AssetAttribute/StationAux'; import StationBatteryAttributes from '../AssetAttribute/StationBattery'; import ChannelSelector from './ChannelSelector'; +import LocationDrawingsButton from '../CommonComponents/LocationDrawingsButton'; declare var homePath: string; @@ -80,11 +80,6 @@ export default function AssetPage(props: IProps) { const [editAssetKey, setEditAssetKey] = React.useState(''); const [newEdit, setNewEdit] = React.useState<'New' | 'Edit'>('New'); const [showAssetModal, setShowAssetModal] = React.useState(false); - - const [showDrawingsModal, setShowDrawingsModal] = React.useState(); - const [drawingsModalErrors, setDrawingsModalErrors] = React.useState([]); - const [hover, setHover] = React.useState<'none' | 'drawings'>(); - const [showAssetSelect, setShowAssetSelect] = React.useState(false); const [selectedAssets, setSelectedAssets] = React.useState([]); @@ -487,27 +482,8 @@ export default function AssetPage(props: IProps) { Actions:
    - - 0 && hover == 'drawings'} - Theme={'dark'} - Position={'top'} - Zindex={9999} - Target={"DrawingsModal"} - > {drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    )} -
    -
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 698802a92..9c952084d 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -41,7 +41,7 @@ import AdditionalFieldsWindow from '../CommonComponents/AdditionalFieldsWindow'; import MultipleAssetsPage from './MultipleAssetsPage'; import CustomerAssetGroupPage from './CustomerAssetGroupPage'; import LineSegmentWindow from '../AssetAttribute/LineSegmentWindow'; -import LocationDrawingsModal from '../CommonComponents/LocationDrawingsModal'; +import LocationDrawingsButton from '../CommonComponents/LocationDrawingsButton'; // Define Step Numbers const generalStep: number = 1; @@ -97,8 +97,6 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { const [hover, setHover] = React.useState<'None' | 'Next' | 'Prev' | 'Drawings'>('None'); const [showSubmit, setShowSubmit] = React.useState(false); const [status, setStatus] = React.useState('unintiated'); - const [showDrawingsModal, setShowDrawingsModal] = React.useState(); - const [drawingsModalErrors, setDrawingsModalErrors] = React.useState([]); React.useEffect(() => { if (mStatus === 'unintiated' || mStatus === 'changed') @@ -408,30 +406,8 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { || currentStep === connectionStep ) return (<> - - 0 && hover == 'Drawings'} - Theme={'dark'} - Position={'top'} - Zindex={9999} - Target={"DrawingsModal"} - > {drawingsModalErrors.map((e, i) =>

    {CrossMark} {e}

    )} -
    - ) else if (currentStep >= additionalFieldMeterStep) { From 6db7f96296f644dbb8496d49dc232d00a098bd07 Mon Sep 17 00:00:00 2001 From: collins-self Date: Tue, 7 Jan 2025 14:26:38 -0500 Subject: [PATCH 31/50] fix: update LocationDrawingsButton to use location IDs for error handling --- .../LocationDrawingsButton.tsx | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index 7455ae8b1..0313437a8 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -14,13 +14,13 @@ const LocationDrawingsButton: React.FC = (props) => const [selectedLocation, setSelectedLocation] = React.useState(); const [multipleLocations, setMultipleLocations] = React.useState(false); const [showDrawingsModal, setShowDrawingsModal] = React.useState(false); - const [locationsWithErrors, setLocationsWithErrors] = React.useState>(new Map()) + const [locationsWithErrors, setLocationsWithErrors] = React.useState>(new Map()) const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); - const isValid = (location, drawingData) => { + const isValid = (location: OpenXDA.Types.Location, drawingData) => { let e = []; - if (location == undefined + if (!location || (location.Alias == "" && location.Description == "" && location.ID == 0 @@ -36,9 +36,9 @@ const LocationDrawingsButton: React.FC = (props) => React.useEffect(() => { // Generates the map of errors for each location if (props.Locations.length > 1) setMultipleLocations(true); - else setMultipleLocations(false); // TODO: check for undefined location isValid is not doing it + else setMultipleLocations(false); for (const location of props.Locations) { - if (location?.ID) { + if (location) { setPageState('loading'); LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) .done((result) => { @@ -49,38 +49,39 @@ const LocationDrawingsButton: React.FC = (props) => .fail(() => setPageState('error')); } } - }, [props.Locations]); + }, [props.Locations]); // ? Calls too frequently - const handleAddLocationError = (locMap: Map) => { + const handleAddLocationError = (locMap: Map) => { setLocationsWithErrors(prev => { const newMap = new Map(prev); - locMap.forEach((errors, loc) => { - if (newMap.has(loc)) { - const existingErrors = newMap.get(loc); - newMap.set(loc, Array.from(new Set([...existingErrors, ...errors]))); - } else { - newMap.set(loc, errors); + locMap.forEach((errors, locID) => { + if (newMap.has(locID)) { // If the location already has errors + const existingErrors = newMap.get(locID); + newMap.set(locID, Array.from(new Set([...existingErrors, ...errors]))); // supresses duplicate values + } else { // otherwise add new + newMap.set(locID, errors); } }); return newMap; }); } - const handleRemoveLocationError = (loc: OpenXDA.Types.Location) => { + const handleRemoveLocationError = (locID: number) => { setLocationsWithErrors(prev => { const newMap = new Map(prev); - newMap.delete(loc); + newMap.delete(locID); return newMap; }); } const updateLocationErrors = (loc: OpenXDA.Types.Location, errors: string[]) => { - if (errors.length > 0 && loc != undefined) { - const locationErrorsMap = new Map(); - locationErrorsMap.set(loc, errors); + if (locationsWithErrors.has(loc?.ID) // Remove if the location has + && locationsWithErrors.get(loc?.ID).length > errors.length) {// fewer errors than before + handleRemoveLocationError(loc.ID); + } else if (errors.length > 0) { + const locationErrorsMap = new Map(); + locationErrorsMap.set(loc?.ID, errors); handleAddLocationError(locationErrorsMap); - } else { - handleRemoveLocationError(loc); } } @@ -97,39 +98,39 @@ const LocationDrawingsButton: React.FC = (props) => {!multipleLocations ? <> 0 && hover === 'drawings'} + Show={locationsWithErrors.has(props.Locations[0]?.ID) && hover === 'drawings'} Theme={'dark'} Position={'top'} Target={"DrawingsModal"} Zindex={9999} - > {locationsWithErrors.get(props.Locations[0])?.map((e, i) =>

    {CrossMark} {e}

    )} + > {locationsWithErrors.get(props.Locations[0]?.ID)?.map((e, i) =>

    {CrossMark} {e}

    )}
    : handleShowDrawingsModal(props.Locations[0])} TooltipContent={ - <>{locationsWithErrors.get(props.Locations[0])?.map((e, i) =>

    {CrossMark} {e}

    )} + <>{locationsWithErrors.get(props.Locations[0]?.ID)?.map((e, i) =>

    {CrossMark} {e}

    )} } - ShowToolTip={locationsWithErrors.has(props.Locations[0])} - Disabled={locationsWithErrors.has(props.Locations[0])} + ShowToolTip={locationsWithErrors.has(props.Locations[0]?.ID)} + Disabled={locationsWithErrors.has(props.Locations[0]?.ID)} BtnClass={'btn-primary'} Options={props.Locations.slice(1).map((loc, i) => ({ Label: 'Open ' + loc?.Name + ' Drawings', Callback: () => handleShowDrawingsModal(loc), - Disabled: locationsWithErrors.has(loc), + Disabled: locationsWithErrors.has(loc?.ID), ToolTipContent: <>{ - locationsWithErrors.get(loc)?.map((e, i) =>

    {CrossMark} {e}

    ) + locationsWithErrors.get(loc?.ID)?.map((e, i) =>

    {CrossMark} {e}

    ) }, - ShowToolTip: locationsWithErrors.has(loc), + ShowToolTip: locationsWithErrors.has(loc?.ID), ToolTipLocation: "left", Key: i }))} From bd0bd10deea5618722ab4de24ae9ebcdb106de75 Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 15 Jan 2025 09:11:09 -0500 Subject: [PATCH 32/50] quick fixes --- .../SystemCenter/Asset/AssetConnection.tsx | 2 +- .../LocationDrawingsButton.tsx | 31 ++++++++++++++++--- .../LocationDrawingsModal.tsx | 13 ++++---- .../Location/AddEditDrawingsModal.tsx | 4 +-- .../Location/LocationDrawings.tsx | 2 +- .../Location/LocationDrawingsTable.tsx | 21 +++++-------- 6 files changed, 46 insertions(+), 27 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index 20d467a9e..e6f8a7913 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -105,7 +105,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number }, [localAssets]) React.useEffect(() => { - let handle = getAssetConnections(); + const handle = getAssetConnections(); return () => { if (handle != null && handle.abort != null) handle.abort(); } }, [props.ID, trigger]) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index 0313437a8..a1f6afa86 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -1,3 +1,25 @@ +//****************************************************************************************************** +// LocationDrawings.tsx - Gbtc +// +// Copyright © 2024, 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: +// ---------------------------------------------------------------------------------------------------- +// 01/06/2024 - Collins Self +// Generated original version of source code. +// +//****************************************************************************************************** import React from 'react'; import { BtnDropdown, GenericController, LoadingScreen, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive'; import LocationDrawingsModal from './LocationDrawingsModal'; @@ -37,18 +59,19 @@ const LocationDrawingsButton: React.FC = (props) => React.useEffect(() => { // Generates the map of errors for each location if (props.Locations.length > 1) setMultipleLocations(true); else setMultipleLocations(false); + + setPageState('loading'); for (const location of props.Locations) { - if (location) { - setPageState('loading'); + if (location != null) { LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) .done((result) => { const errors = isValid(location, result); updateLocationErrors(location, errors); - setPageState('idle') }) .fail(() => setPageState('error')); } } + if (pageState != 'error') setPageState('idle'); }, [props.Locations]); // ? Calls too frequently const handleAddLocationError = (locMap: Map) => { @@ -137,7 +160,7 @@ const LocationDrawingsButton: React.FC = (props) => /> } diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 756706bde..8ad9aaa0f 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -1,7 +1,7 @@ //****************************************************************************************************** // LocationDrawings.tsx - Gbtc // -// Copyright � 2023, Grid Protection Alliance. All Rights Reserved. +// Copyright © 2024, 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. @@ -23,9 +23,10 @@ import React from 'react'; import { Modal } from '@gpa-gemstone/react-interactive'; import LocationDrawingsTable from '../Location/LocationDrawingsTable'; +import { OpenXDA } from '@gpa-gemstone/application-typings'; interface IProps { - LocationID: number; + Location: OpenXDA.Types.Location; Show: boolean; SetShow: (b: boolean) => void; } @@ -34,16 +35,16 @@ const LocationDrawingsModal = (props: IProps) => { return ( props.SetShow(false)} ShowCancel={false} ConfirmText={'Done'}>
    -
    +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx index d6d8436b9..622a6c08e 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx @@ -1,7 +1,7 @@ //****************************************************************************************************** // LocationDrawings.tsx - Gbtc // -// Copyright � 2023, Grid Protection Alliance. All Rights Reserved. +// Copyright © 2024, 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. @@ -63,7 +63,7 @@ const AddEditDrawingsModal = (props: IProps) => { } React.useEffect(() => { - let categoryHandle = getValueList("Category", setCategory); + const categoryHandle = getValueList("Category", setCategory); return () => { if (categoryHandle != null && categoryHandle.abort != null) categoryHandle.abort(); diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx index edec5f1b8..210d30a51 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx @@ -74,7 +74,7 @@ const LocationDrawingsWindow = (props: { LocationID: number }) => { setEditMode(true); setShowModal(true); }} - UpdateTable={updateTable} + RefreshDrawings={updateTable} />
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx index 2b39fe937..b646b5668 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx @@ -1,7 +1,7 @@ //****************************************************************************************************** // LocationDrawings.tsx - Gbtc // -// Copyright � 2023, Grid Protection Alliance. All Rights Reserved. +// Copyright © 2023, 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. @@ -32,9 +32,9 @@ interface IProps { LocationID: number, Edit?: (record: SystemCenter.Types.LocationDrawing) => void, /** - * @param UpdateTable Counter that triggers a fetchDrawings function + * @param RefreshDrawings Counter that triggers a fetchDrawings function */ - UpdateTable: number + RefreshDrawings: number } const LocationDrawingsTable = (props: IProps) => { @@ -45,7 +45,7 @@ const LocationDrawingsTable = (props: IProps) => { const [pageState, setPageState] = React.useState<'error' | 'idle' | 'loading'>('idle'); const [page, setPage] = React.useState(0); - const roles = useAppSelector(SelectRoles); // Deprecated + const roles = useAppSelector(SelectRoles); const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); const PagingID = 'LocationDrawingPage' @@ -71,12 +71,8 @@ const LocationDrawingsTable = (props: IProps) => { const handleDelete = (item: SystemCenter.Types.LocationDrawing) => { setPageState('loading'); LocationDrawingController.DBAction('DELETE', item) - .then(() => { - fetchDrawings(sortKey, ascending, page, props.LocationID); - }) - .catch(() => { - setPageState('error'); - }); + .then(() => fetchDrawings(sortKey, ascending, page, props.LocationID), + () => setPageState('error')) }; React.useEffect(() => { @@ -89,13 +85,12 @@ const LocationDrawingsTable = (props: IProps) => { }, [page]); React.useEffect(() => { - fetchDrawings(sortKey, ascending, page, props.LocationID); const handle = fetchDrawings(sortKey, ascending, page, props.LocationID); return () => { if (handle != null && handle?.abort != null) handle.abort(); } - }, [sortKey, ascending, page, props.LocationID, props.UpdateTable]); + }, [sortKey, ascending, page, props.LocationID, props.RefreshDrawings]); return <> -
    +
    TableClass="table table-hover" Data={links} From 4fc731a049fc3cdcf50bf7567146350776e6d1e3 Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 15 Jan 2025 10:13:53 -0500 Subject: [PATCH 33/50] optimize multipleLocations and error management in LocationDrawingsButton --- .../LocationDrawingsButton.tsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index a1f6afa86..a3538384e 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -34,7 +34,7 @@ const LocationDrawingsButton: React.FC = (props) => const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); const [pageState, setPageState] = React.useState<"loading" | "error" | "idle">("idle"); const [selectedLocation, setSelectedLocation] = React.useState(); - const [multipleLocations, setMultipleLocations] = React.useState(false); + const multipleLocations = React.useMemo(() => props.Locations.length > 1, [props.Locations]); const [showDrawingsModal, setShowDrawingsModal] = React.useState(false); const [locationsWithErrors, setLocationsWithErrors] = React.useState>(new Map()) const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); @@ -57,22 +57,24 @@ const LocationDrawingsButton: React.FC = (props) => } React.useEffect(() => { // Generates the map of errors for each location - if (props.Locations.length > 1) setMultipleLocations(true); - else setMultipleLocations(false); - setPageState('loading'); - for (const location of props.Locations) { + + const handles = props.Locations.map(location=> { if (location != null) { - LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) - .done((result) => { + return LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) + .then((result) => { const errors = isValid(location, result); updateLocationErrors(location, errors); }) - .fail(() => setPageState('error')); + .fail(() => { throw new Error() }); } - } - if (pageState != 'error') setPageState('idle'); - }, [props.Locations]); // ? Calls too frequently + return Promise.resolve(); + }); + + Promise.all(handles) + .then(() => { setPageState('idle')}, + () => { setPageState('error') }); + }, [props.Locations]); const handleAddLocationError = (locMap: Map) => { setLocationsWithErrors(prev => { From f93c3aec9da16b3bf6f52a5e530f07af2661a192 Mon Sep 17 00:00:00 2001 From: collins-self Date: Thu, 16 Jan 2025 10:10:46 -0500 Subject: [PATCH 34/50] improve error handling and cleanup in LocationDrawingsButton --- .../LocationDrawingsButton.tsx | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index a3538384e..829dae364 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -59,21 +59,32 @@ const LocationDrawingsButton: React.FC = (props) => React.useEffect(() => { // Generates the map of errors for each location setPageState('loading'); - const handles = props.Locations.map(location=> { + const handles = props.Locations.map(location => { if (location != null) { - return LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) - .then((result) => { + const handle = LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) + .done((result) => { const errors = isValid(location, result); updateLocationErrors(location, errors); }) .fail(() => { throw new Error() }); + return handle; } - return Promise.resolve(); - }); + return null; // invalid location + }).filter(handle => handle != null); Promise.all(handles) - .then(() => { setPageState('idle')}, - () => { setPageState('error') }); + .then(() => { + setPageState('idle'); + }, + () => { + setPageState('error') + }); + + return () => { + handles.forEach(handle => { + return () => { if (handle != null && handle?.abort != null) handle.abort(); } + }) + }; }, [props.Locations]); const handleAddLocationError = (locMap: Map) => { From 7c45f362c4f464dfb79a6741fb91681077cada5c Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 17 Jan 2025 09:01:35 -0500 Subject: [PATCH 35/50] enhance LocationDrawingsButton with dropdown options and error handling --- .../LocationDrawingsButton.tsx | 94 +++++++------------ 1 file changed, 35 insertions(+), 59 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index 829dae364..cb236831d 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -30,17 +30,27 @@ interface LocationDrawingsButtonProps { Locations: OpenXDA.Types.Location[]; } +type DropDownOption = { + Label: JSX.Element | string, + Callback: () => void, + Disabled: boolean + ToolTipContent: JSX.Element, + ShowToolTip: boolean, + ToolTipLocation: ('top' | 'bottom' | 'left' | 'right'), + Key: string | number +} + const LocationDrawingsButton: React.FC = (props) => { const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); const [pageState, setPageState] = React.useState<"loading" | "error" | "idle">("idle"); const [selectedLocation, setSelectedLocation] = React.useState(); const multipleLocations = React.useMemo(() => props.Locations.length > 1, [props.Locations]); const [showDrawingsModal, setShowDrawingsModal] = React.useState(false); - const [locationsWithErrors, setLocationsWithErrors] = React.useState>(new Map()) + const [locationOptions, setLocationOptions] = React.useState([]); const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); const isValid = (location: OpenXDA.Types.Location, drawingData) => { - let e = []; + let e = ""; if (!location || (location.Alias == "" @@ -50,21 +60,31 @@ const LocationDrawingsButton: React.FC = (props) => && location.LocationKey == "" && location.Longitude == null && location.Name == "")) - e.push('No locations have been set.'); + e = 'No locations have been set.'; else if (drawingData.TotalRecords == 0) - e.push('No drawings associated with location.'); + e = 'No drawings associated with location.'; return e; } React.useEffect(() => { // Generates the map of errors for each location setPageState('loading'); - const handles = props.Locations.map(location => { + const handles = props.Locations.map((location, i) => { + setLocationOptions([]); if (location != null) { const handle = LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) .done((result) => { - const errors = isValid(location, result); - updateLocationErrors(location, errors); + const error = isValid(location, result); + const option: DropDownOption = { + Label: location.Name, + Callback: () => handleShowDrawingsModal(location), + Disabled: error != "", + ToolTipContent:

    {error}

    , + ShowToolTip: error != "", + ToolTipLocation: "left", + Key: i + }; + setLocationOptions(prev => [...prev, option]); }) .fail(() => { throw new Error() }); return handle; @@ -87,40 +107,6 @@ const LocationDrawingsButton: React.FC = (props) => }; }, [props.Locations]); - const handleAddLocationError = (locMap: Map) => { - setLocationsWithErrors(prev => { - const newMap = new Map(prev); - locMap.forEach((errors, locID) => { - if (newMap.has(locID)) { // If the location already has errors - const existingErrors = newMap.get(locID); - newMap.set(locID, Array.from(new Set([...existingErrors, ...errors]))); // supresses duplicate values - } else { // otherwise add new - newMap.set(locID, errors); - } - }); - return newMap; - }); - } - - const handleRemoveLocationError = (locID: number) => { - setLocationsWithErrors(prev => { - const newMap = new Map(prev); - newMap.delete(locID); - return newMap; - }); - } - - const updateLocationErrors = (loc: OpenXDA.Types.Location, errors: string[]) => { - if (locationsWithErrors.has(loc?.ID) // Remove if the location has - && locationsWithErrors.get(loc?.ID).length > errors.length) {// fewer errors than before - handleRemoveLocationError(loc.ID); - } else if (errors.length > 0) { - const locationErrorsMap = new Map(); - locationErrorsMap.set(loc?.ID, errors); - handleAddLocationError(locationErrorsMap); - } - } - const handleShowDrawingsModal = (loc) => { if (loc == undefined) return; setSelectedLocation(loc); @@ -134,42 +120,32 @@ const LocationDrawingsButton: React.FC = (props) => {!multipleLocations ? <> {locationsWithErrors.get(props.Locations[0]?.ID)?.map((e, i) =>

    {CrossMark} {e}

    )} + >

    {CrossMark} {locationOptions[0]?.ToolTipContent}

    : handleShowDrawingsModal(props.Locations[0])} TooltipContent={ - <>{locationsWithErrors.get(props.Locations[0]?.ID)?.map((e, i) =>

    {CrossMark} {e}

    )} +

    {CrossMark} {locationOptions[0]?.Disabled}

    } - ShowToolTip={locationsWithErrors.has(props.Locations[0]?.ID)} - Disabled={locationsWithErrors.has(props.Locations[0]?.ID)} + ShowToolTip={locationOptions[0]?.ShowToolTip} + Disabled={locationOptions[0]?.Disabled} BtnClass={'btn-primary'} - Options={props.Locations.slice(1).map((loc, i) => ({ - Label: 'Open ' + loc?.Name + ' Drawings', - Callback: () => handleShowDrawingsModal(loc), - Disabled: locationsWithErrors.has(loc?.ID), - ToolTipContent: <>{ - locationsWithErrors.get(loc?.ID)?.map((e, i) =>

    {CrossMark} {e}

    ) - }, - ShowToolTip: locationsWithErrors.has(loc?.ID), - ToolTipLocation: "left", - Key: i - }))} + Options={locationOptions.slice(1)} /> } Date: Fri, 17 Jan 2025 09:19:50 -0500 Subject: [PATCH 36/50] update LocationDrawingsModal and LocationDrawingsTable for improved state management --- .../SystemCenter/CommonComponents/LocationDrawingsModal.tsx | 2 +- .../TSX/SystemCenter/Location/LocationDrawingsTable.tsx | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx index 8ad9aaa0f..2e388677d 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx @@ -39,7 +39,7 @@ const LocationDrawingsModal = (props: IProps) => { ShowX={true} Size={'lg'} CallBack={() => props.SetShow(false)} ShowCancel={false} - ConfirmText={'Done'}> + ShowConfirm={false}>
    { .done((result) => { setLinks(JSON.parse(result.Data as unknown as string)); if (result.NumberOfPages === 0) result.NumberOfPages = 1; - setPageInfo(result); + setPageInfo({RecordsPerPage: result.RecordsPerPage, + NumberOfPages: result.NumberOfPages, + TotalRecords: result.TotalRecords}); setPageState('idle'); }) .fail(() => setPageState('error')); From 9a7eae702d3ff73159012171d48a5d9e1564250f Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 17 Jan 2025 09:41:38 -0500 Subject: [PATCH 37/50] Removed unintended (whitespace) changes: ConnectionPage, AssetPage, NMW --- .../SystemCenter/NewMeterWizard/AssetPage.tsx | 430 +++++++++--------- .../NewMeterWizard/ConnectionPage.tsx | 16 +- .../NewMeterWizard/NewMeterWizard.tsx | 83 ++-- 3 files changed, 264 insertions(+), 265 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index 4c6d2fd0f..43a1858bf 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -45,7 +45,7 @@ import GenerationAttributes from '../AssetAttribute/Generation'; import StationAuxAttributes from '../AssetAttribute/StationAux'; import StationBatteryAttributes from '../AssetAttribute/StationBattery'; import ChannelSelector from './ChannelSelector'; -import LocationDrawingsButton from '../CommonComponents/LocationDrawingsButton'; +import LocationDrawings from '../Location/LocationDrawings'; declare var homePath: string; @@ -75,11 +75,11 @@ export default function AssetPage(props: IProps) { const byAssetStatus = useAppSelector(ByAssetSlice.Status); const detailedAssets = useAppSelector(ByAssetSlice.Data); - const [newEditAsset, setNewEditAsset] = React.useState(AssetAttributes.getNewAsset('Line')); const [editAssetKey, setEditAssetKey] = React.useState(''); const [newEdit, setNewEdit] = React.useState<'New' | 'Edit'>('New'); const [showAssetModal, setShowAssetModal] = React.useState(false); + const [showAssetSelect, setShowAssetSelect] = React.useState(false); const [selectedAssets, setSelectedAssets] = React.useState([]); @@ -108,7 +108,7 @@ export default function AssetPage(props: IProps) { const assetData = React.useMemo(() => { const u = _.cloneDeep(props.Assets); if (sortKey === 'Channels') - u.sort((a, b) => (asc ? 1 : -1) * (a.Channels.length > b.Channels.length ? 1 : -1)); + u.sort((a, b) => (asc? 1 : -1)* (a.Channels.length > b.Channels.length ? 1 : -1)); else return _.orderBy(u, [sortKey], [asc ? 'asc' : 'desc']); return u; @@ -207,7 +207,7 @@ export default function AssetPage(props: IProps) { } } - else if (newEditAsset.AssetType == 'Line') { + else if (newEditAsset.AssetType == 'Line'){ let handle = getLineSegment(newEditAsset.ID); handle.done((lineSegment: OpenXDA.Types.LineDetail) => { let record = _.cloneDeep(newEditAsset as OpenXDA.Types.Line); @@ -221,11 +221,11 @@ export default function AssetPage(props: IProps) { setNewEditAsset(record); }); - return () => { - if (handle.abort !== undefined) handle.abort(); - } + return () => { + if (handle.abort !== undefined) handle.abort(); + } - } + } }, [newEditAsset.AssetType]); @@ -255,7 +255,7 @@ export default function AssetPage(props: IProps) { assetConnections.splice(index, 1); index = assetConnections.findIndex(assetConnection => assetConnection.Parent == record[0].AssetKey || assetConnection.Child == record[0].AssetKey); } - + props.UpdateAssets(list); props.UpdateChannels(channels); props.UpdateAssetConnections(assetConnections); @@ -263,7 +263,7 @@ export default function AssetPage(props: IProps) { } function getDifferentAsset(assetID: number): void { - let assetTypeID = assets.find(a => a.ID == assetID)['AssetTypeID']; + let assetTypeID = assets.find(a => a.ID == assetID)['AssetTypeID']; let assetType = assetTypes.find(at => at.ID == assetTypeID) $.ajax({ type: "GET", @@ -303,19 +303,19 @@ export default function AssetPage(props: IProps) { function showAttributes(): JSX.Element { if (newEditAsset.AssetType == 'Breaker') - return 0} />; + return 0}/>; else if (newEditAsset.AssetType == 'Bus') - return ; + return ; else if (newEditAsset.AssetType == 'CapacitorBank') - return 0} />; + return 0}/>; else if (newEditAsset.AssetType == 'CapacitorBankRelay') - return 0} />; + return 0}/>; else if (newEditAsset.AssetType == 'Line') - return 0} />; + return 0}/>; else if (newEditAsset.AssetType == 'Transformer') - return 0} />; + return 0}/>; else if (newEditAsset.AssetType == 'DER') - return 0} />; + return 0}/>; else if (newEditAsset.AssetType == 'Generation') return ; else if (newEditAsset.AssetType == 'StationAux') @@ -324,219 +324,217 @@ export default function AssetPage(props: IProps) { return ; } - return ( -
    -
    -
    -
      - { - props.Channels.map((channel) =>
    • 0 ? 'line-through' : null) }} key={channel.ID}>{channel.Name + ' - ' + channel.Description}
    • ) - } -
    -
    -
    -
    -
    -
    -
    - - + return ( +
    +
    +
    +
      + { + props.Channels.map((channel) =>
    • 0 ? 'line-through' : null)}} key={channel.ID}>{channel.Name + ' - ' + channel.Description}
    • ) + } +
    +
    +
    +
    +
    +
    +
    + + +
    -
    -
    -
    - - TableClass="table table-hover" - Data={assetData} - SortKey={sortKey} - Ascending={asc} - OnSort={(d) => { - if (d.colKey == 'Buttons') - return; - if (d.colKey === sortKey) - setAsc((x) => !x); - else - setAsc(false); - setSortKey(d.colKey); - }} - TableStyle={{ padding: 0, width: 'calc(100%)', tableLayout: 'fixed', height: 'calc(100% - 16px)', overflow: 'hidden', display: 'flex', flexDirection: 'column' }} - TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} - TbodyStyle={{ display: 'block', overflowY: 'scroll', flex: 1 }} - RowStyle={{ display: 'table', tableLayout: 'fixed', width: '100%' }} - Selected={(item) => false} - KeySelector={(item) => item.ID} - > - - Key={'Status'} - AllowSort={true} - HeaderStyle={{ width: '10%' }} - RowStyle={{ width: '10%' }} - Content={({ item }) => item.ID == 0 ? 'New' : 'Existing'} - > Status - - - Key={'AssetKey'} - AllowSort={true} - Field={'AssetKey'} - HeaderStyle={{ width: '20%' }} - RowStyle={{ width: '20%' }} - > Key - - - Key={'AssetName'} - AllowSort={true} - Field={'AssetName'} - HeaderStyle={{ width: '30%' }} - RowStyle={{ width: '30%' }} - > Name - - - Key={'AssetType'} - AllowSort={true} - Field={'AssetType'} - HeaderStyle={{ width: '10%' }} - RowStyle={{ width: '10%' }} - > Type - - - Key={'VoltageKV'} - AllowSort={true} - Field={'VoltageKV'} - HeaderStyle={{ width: '10%' }} - RowStyle={{ width: '10%' }} - > kV - - - Key={'Channels'} - AllowSort={true} - Field={'Channels'} - HeaderStyle={{ width: '10%' }} - RowStyle={{ width: '10%' }} - Content={({ item }) => item.Channels.length} - > Channels - - - Key={'Buttons'} - AllowSort={false} - HeaderStyle={{ width: '10%' }} - RowStyle={{ width: '10%' }} - Content={({ index }) => <> - - - } - >

    - - +
    +
    + + TableClass="table table-hover" + Data={assetData} + SortKey={sortKey} + Ascending={asc} + OnSort={(d) => { + if (d.colKey == 'Buttons') + return; + if (d.colKey === sortKey) + setAsc((x) => !x); + else + setAsc(false); + setSortKey(d.colKey); + }} + TableStyle={{ padding: 0, width: 'calc(100%)', tableLayout: 'fixed', height: 'calc(100% - 16px)', overflow: 'hidden', display: 'flex', flexDirection: 'column' }} + TheadStyle={{ fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }} + TbodyStyle={{ display: 'block', overflowY: 'scroll', flex: 1 }} + RowStyle={{ display: 'table', tableLayout: 'fixed', width: '100%' }} + Selected={(item) => false} + KeySelector={(item) => item.ID} + > + + Key={'Status'} + AllowSort={true} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + Content={({ item }) => item.ID == 0 ? 'New' : 'Existing' } + > Status + + + Key={'AssetKey'} + AllowSort={true} + Field={'AssetKey'} + HeaderStyle={{ width: '20%' }} + RowStyle={{ width: '20%' }} + > Key + + + Key={'AssetName'} + AllowSort={true} + Field={'AssetName'} + HeaderStyle={{ width: '30%' }} + RowStyle={{ width: '30%' }} + > Name + + + Key={'AssetType'} + AllowSort={true} + Field={'AssetType'} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + > Type + + + Key={'VoltageKV'} + AllowSort={true} + Field={'VoltageKV'} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + > kV + + + Key={'Channels'} + AllowSort={true} + Field={'Channels'} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + Content={({ item }) => item.Channels.length } + > Channels + + + Key={'Buttons'} + AllowSort={false} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + Content={({ index }) => <> + + + } + >

    + + +
    -
    +
    -
    - { - setShowAssetSelect(false); - if (!confirm) return; - - let list: Array = []; - let channels: Array = _.clone(props.Channels); - let assetConnections: Array = _.clone(props.AssetConnections); - - let removedAssets: Array = props.Assets.filter((asset) => asset.ID > 0 && selected.findIndex((selectedAsset) => (asset.ID === selectedAsset.ID)) < 0); + { + setShowAssetSelect(false); + if (!confirm) return; + + let list: Array = []; + let channels: Array = _.clone(props.Channels); + let assetConnections: Array = _.clone(props.AssetConnections); + + let removedAssets: Array = props.Assets.filter((asset) => asset.ID > 0 && selected.findIndex((selectedAsset) => (asset.ID === selectedAsset.ID)) < 0); + + //Deal with removed assets + $.each(removedAssets, (index, asset) => { + $.each(channels, (index, channel) => { + if (channel.Asset == asset.AssetKey) + channel.Asset = ''; + }); + + var index = assetConnections.findIndex(assetConnection => assetConnection.Parent == asset.AssetKey || assetConnection.Child == asset.AssetKey); + while (index >= 0) { + assetConnections.splice(index, 1); + index = assetConnections.findIndex(assetConnection => assetConnection.Parent == asset.AssetKey || assetConnection.Child == asset.AssetKey); + } + }); + let promises = []; + $.each(selected, async (index, record) => { + let assetRecord = getAssetWithAdditionalFields(record.ID, record.AssetType as OpenXDA.Types.AssetTypeName); + // Push promises into promises + promises.push(assetRecord); + }); - //Deal with removed assets - $.each(removedAssets, (index, asset) => { - $.each(channels, (index, channel) => { - if (channel.Asset == asset.AssetKey) - channel.Asset = ''; + //Add the new assets that have been created by the user + $.each(props.Assets.filter((asset) => asset.ID <= 0), (index, asset) => { + list.push(asset); }); - var index = assetConnections.findIndex(assetConnection => assetConnection.Parent == asset.AssetKey || assetConnection.Child == asset.AssetKey); - while (index >= 0) { - assetConnections.splice(index, 1); - index = assetConnections.findIndex(assetConnection => assetConnection.Parent == asset.AssetKey || assetConnection.Child == asset.AssetKey); + //Update selected + setSelectedAssets(selected); + Promise.all(promises).then(d => { props.UpdateAssets(list.concat(d)) }) + + //Update props + props.UpdateChannels(channels); + props.UpdateAssetConnections(assetConnections); + }}> +
  • +
    + Actions: +
    +
    + +
    +
    +
    +
  • +
    + { + setShowAssetModal(false); + + if (!confirm) { + setNewEditAsset(AssetAttributes.getNewAsset('Line')); + return; } - }); - let promises = []; - $.each(selected, async (index, record) => { - let assetRecord = getAssetWithAdditionalFields(record.ID, record.AssetType as OpenXDA.Types.AssetTypeName); - // Push promises into promises - promises.push(assetRecord); - }); - - //Add the new assets that have been created by the user - $.each(props.Assets.filter((asset) => asset.ID <= 0), (index, asset) => { - list.push(asset); - }); - - //Update selected - setSelectedAssets(selected); - Promise.all(promises).then(d => { props.UpdateAssets(list.concat(d)) }) - - //Update props - props.UpdateChannels(channels); - props.UpdateAssetConnections(assetConnections); - }}> -
  • -
    - Actions: -
    -
    - -
    -
    -
    -
  • -
    - { - setShowAssetModal(false); - - if (!confirm) { - setNewEditAsset(AssetAttributes.getNewAsset('Line')); - return; - } - let record: OpenXDA.Types.Asset = _.clone(newEditAsset); - let list = _.clone(props.Assets); - let channels: Array = _.clone(props.Channels); + let record: OpenXDA.Types.Asset = _.clone(newEditAsset); + let list = _.clone(props.Assets); + let channels: Array = _.clone(props.Channels); - $.each(channels, (index, channel) => { - if (channel.Asset == record.AssetKey) - channel.Asset = '' + $.each(channels, (index, channel) => { + if (channel.Asset == record.AssetKey) + channel.Asset = '' - if (record.Channels.findIndex(c => c.ID == channel.ID) >= 0) - channel.Asset = record.AssetKey - }); + if (record.Channels.findIndex(c => c.ID == channel.ID) >= 0) + channel.Asset = record.AssetKey + }); - if (newEdit == 'New') - list.push(record); - if (newEdit == 'Edit') { - const index = list.findIndex(a => a.AssetKey == editAssetKey); - list[index] = record; - } + if (newEdit == 'New') + list.push(record); + if (newEdit == 'Edit') { + const index = list.findIndex(a => a.AssetKey == editAssetKey); + list[index] = record; + } - props.UpdateChannels(channels); - props.UpdateAssets(list); - setNewEditAsset(AssetAttributes.getNewAsset('Line')); - }} - DisableConfirm={(AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).length > 0)} - ConfirmShowToolTip={AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).length > 0} - ConfirmToolTipContent={ - AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).map((e, i) =>

    {CrossMark} {e}

    ) - } - > -
    -
    -
    + props.UpdateChannels(channels); + props.UpdateAssets(list); + setNewEditAsset(AssetAttributes.getNewAsset('Line')); + }} + DisableConfirm={(AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).length > 0) } + ConfirmShowToolTip={AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).length > 0} + ConfirmToolTipContent={ + AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).map((e, i) =>

    {CrossMark} {e}

    ) + } + > +
    +
    +
    -
    - -
    +
    + +
    ; - + return <>
    @@ -286,7 +286,7 @@ export default function ConnectionPage(props: IProps) { AllowSort={false} HeaderStyle={{ width: 'auto' }} RowStyle={{ width: 'auto' }} - Content={({ item }) => + Content={({item}) => deleteAssetConnection(item.Connection)} diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 9c952084d..ac597ae80 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -74,7 +74,7 @@ export interface AssetLists { Transformers: Array } -export default function NewMeterWizard(props: { IsEngineer: boolean }) { +export default function NewMeterWizard(props: {IsEngineer: boolean}) { let history = useHistory(); const dispatch = useAppDispatch(); @@ -209,7 +209,8 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { return []; } - function getAssets(): Array { + function getAssets(): Array + { if (localStorage.hasOwnProperty('NewMeterWizard.Assets')) return JSON.parse(localStorage.getItem('NewMeterWizard.Assets')); else @@ -294,7 +295,7 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { if (isSubmitStep()) setCurrentStep(saveStep + 1); else if (currentStep >= finalStep) - setCurrentStep(finalStep); + setCurrentStep(finalStep); else setCurrentStep(currentStep + 1); @@ -423,7 +424,7 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { ); } return null; - }, [currentStep, channels]); + }, [currentStep, channels ]); function getPage() { if (status === 'error') @@ -439,30 +440,30 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { case locationStep: return { setError(e) }} SetWarning={setWarning} /> case eventChannelsStep: - // The uses the same page as the next step for now + // The uses the same page as the next step for now case trendChannelsStep: - return case assetStep: - return case connectionStep: - return asset.AssetType != 'LineSegment')} + return asset.AssetType != 'LineSegment')} GetInnerComponent={(currentAsset) => } /> case additionalFieldMeterStep: return case externalFieldStep: - return + return case lineSegmentStep: - return } /> case additionalFieldAssetStep: - return } /> + return }/> case customerAssetGroupMeterStep: return case customerAssetGroupAssetStep: - return } /> } }; @@ -476,40 +477,40 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) { data-tooltip='Next' onMouseEnter={() => setHover('Next')} onMouseLeave={() => setHover('None')} >{isFinalStep() ? 'Finish Editing' : 'Next'}); }; - + function disableNext() { return error.length > 0 }; return (
    -

    New Meter Wizard

    -
    -
    - -
    +

    New Meter Wizard

    +
    +
    + +
    - + +
    -
    -
    -
    +
    +
    @@ -522,7 +523,7 @@ export default function NewMeterWizard(props: { IsEngineer: boolean }) {
    - {getPage()} + {getPage()}
    {currentStep > 1 && currentStep !== saveStep + 1 ?
    -
    ); } From 7d97c4fd55772ee992ddf7622db6e48e5599ceb6 Mon Sep 17 00:00:00 2001 From: collins-self Date: Tue, 21 Jan 2025 10:23:30 -0500 Subject: [PATCH 38/50] update LocationDrawingsButton and related components for loading state management --- .../SystemCenter/Asset/AssetConnection.tsx | 11 +- .../LocationDrawingsButton.tsx | 113 +++++++++--------- .../LocationDrawingsModal.tsx | 54 --------- .../Location/AddEditDrawingsModal.tsx | 2 +- .../Location/LocationDrawings.tsx | 2 +- .../TSX/SystemCenter/Meter/MeterLocation.tsx | 6 +- .../PropertyUI/MeterLocationProperties.tsx | 2 + .../NewMeterWizard/LocationPage.tsx | 11 +- .../NewMeterWizard/NewMeterWizard.tsx | 8 +- 9 files changed, 87 insertions(+), 122 deletions(-) delete mode 100644 Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index e6f8a7913..2a7a26722 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -1,4 +1,4 @@ -//****************************************************************************************************** +//****************************************************************************************************** // LocationMeter.tsx - Gbtc // // Copyright © 2020, Grid Protection Alliance. All Rights Reserved. @@ -53,6 +53,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number const [localAssets, setLocalAssets] = React.useState>([]); const [locations, setLocations] = React.useState([]); + const [isLoadingLocations, setIsLoadingLocations] = React.useState(false); const [sortKey, setSortKey] = React.useState('AssetKey'); const [ascending, setAscending] = React.useState(true); @@ -115,6 +116,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number }, [assetConnections]) function getLocations() { + setIsLoadingLocations(true); const h = $.ajax({ type: "GET", url: `${homePath}api/OpenXDA/Asset/${props.ID}/Locations`, @@ -123,7 +125,7 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number cache: true, async: true }); - h.done(data => setLocations(data)); + h.done(data => { setLocations(data); setIsLoadingLocations(false); }); return h; } @@ -256,7 +258,10 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number

    Connections:

    - +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index cb236831d..727222907 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -21,13 +21,14 @@ // //****************************************************************************************************** import React from 'react'; -import { BtnDropdown, GenericController, LoadingScreen, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive'; -import LocationDrawingsModal from './LocationDrawingsModal'; +import { BtnDropdown, GenericController, LoadingScreen, Modal, ServerErrorIcon, ToolTip } from '@gpa-gemstone/react-interactive'; import { OpenXDA } from '@gpa-gemstone/application-typings'; import { CrossMark } from '@gpa-gemstone/gpa-symbols'; +import LocationDrawingsTable from '../Location/LocationDrawingsTable'; interface LocationDrawingsButtonProps { Locations: OpenXDA.Types.Location[]; + IsLoadingLocations: boolean; } type DropDownOption = { @@ -40,6 +41,23 @@ type DropDownOption = { Key: string | number } +const isValid = (location: OpenXDA.Types.Location, drawingData) => { + let e = ""; + + if (location == null + || (location.Alias === "" + && location.Description === "" + && location.ID === 0 + && location.Latitude == null + && location.LocationKey === "" + && location.Longitude == null + && location.Name === "")) + e = 'No location(s) have been set.'; + else if (drawingData.TotalRecords == 0) + e = 'No drawing(s) associated with location.'; + return e; +} + const LocationDrawingsButton: React.FC = (props) => { const [hover, setHover] = React.useState<'none' | 'drawings'>('none'); const [pageState, setPageState] = React.useState<"loading" | "error" | "idle">("idle"); @@ -49,62 +67,36 @@ const LocationDrawingsButton: React.FC = (props) => const [locationOptions, setLocationOptions] = React.useState([]); const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); - const isValid = (location: OpenXDA.Types.Location, drawingData) => { - let e = ""; - - if (!location - || (location.Alias == "" - && location.Description == "" - && location.ID == 0 - && location.Latitude == null - && location.LocationKey == "" - && location.Longitude == null - && location.Name == "")) - e = 'No locations have been set.'; - else if (drawingData.TotalRecords == 0) - e = 'No drawings associated with location.'; - return e; - } - React.useEffect(() => { // Generates the map of errors for each location setPageState('loading'); + setLocationOptions([]); const handles = props.Locations.map((location, i) => { - setLocationOptions([]); - if (location != null) { - const handle = LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) - .done((result) => { - const error = isValid(location, result); - const option: DropDownOption = { - Label: location.Name, - Callback: () => handleShowDrawingsModal(location), - Disabled: error != "", - ToolTipContent:

    {error}

    , - ShowToolTip: error != "", - ToolTipLocation: "left", - Key: i - }; - setLocationOptions(prev => [...prev, option]); - }) - .fail(() => { throw new Error() }); - return handle; - } - return null; // invalid location + if (location == null) + return null; + const handle = LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) + .done((result) => { + const error = isValid(location, result); + const option: DropDownOption = { + Label: location.Name, + Callback: () => handleShowDrawingsModal(location), + Disabled: error != "", + ToolTipContent:

    {error}

    , + ShowToolTip: error != "", + ToolTipLocation: "left", + Key: i + }; + setLocationOptions(prev => [...prev, option]); + }) + .fail(() => { throw new Error() }); + return handle; }).filter(handle => handle != null); Promise.all(handles) - .then(() => { - setPageState('idle'); - }, - () => { - setPageState('error') - }); + .then(() => setPageState('idle'), + () => setPageState('error')); - return () => { - handles.forEach(handle => { - return () => { if (handle != null && handle?.abort != null) handle.abort(); } - }) - }; + return () => handles.forEach(handle => () => { if (handle != null && handle?.abort != null) handle.abort() }); }, [props.Locations]); const handleShowDrawingsModal = (loc) => { @@ -115,7 +107,7 @@ const LocationDrawingsButton: React.FC = (props) => return (
    - + {!multipleLocations ? <> @@ -148,11 +140,22 @@ const LocationDrawingsButton: React.FC = (props) => Options={locationOptions.slice(1)} /> } - + Title={'Drawings for ' + selectedLocation?.Name} + ShowX={true} Size={'lg'} + CallBack={() => setShowDrawingsModal(false)} + ShowCancel={false} + ShowConfirm={false}> +
    +
    + +
    +
    +
    ); }; diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx deleted file mode 100644 index 2e388677d..000000000 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsModal.tsx +++ /dev/null @@ -1,54 +0,0 @@ -//****************************************************************************************************** -// LocationDrawings.tsx - Gbtc -// -// Copyright © 2024, 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: -// ---------------------------------------------------------------------------------------------------- -// 11/06/2024 - Collins Self -// Generated original version of source code. -// -//****************************************************************************************************** -import React from 'react'; -import { Modal } from '@gpa-gemstone/react-interactive'; -import LocationDrawingsTable from '../Location/LocationDrawingsTable'; -import { OpenXDA } from '@gpa-gemstone/application-typings'; - -interface IProps { - Location: OpenXDA.Types.Location; - Show: boolean; - SetShow: (b: boolean) => void; -} - -const LocationDrawingsModal = (props: IProps) => { - return ( - props.SetShow(false)} - ShowCancel={false} - ShowConfirm={false}> -
    -
    - -
    -
    -
    - ) -} -export default LocationDrawingsModal; \ No newline at end of file diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx index 622a6c08e..2889bd513 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/AddEditDrawingsModal.tsx @@ -79,7 +79,7 @@ const AddEditDrawingsModal = (props: IProps) => { props.SetShow(false); if (conf) props.HandleSave(); }} - ShowCancel={true} + ShowCancel={false} DisableConfirm={ !(valid('Name') && valid('Link') && diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx index 210d30a51..87807368c 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawings.tsx @@ -33,7 +33,7 @@ import AddEditDrawingsModal from './AddEditDrawingsModal'; const LocationDrawingsWindow = (props: { LocationID: number }) => { - const roles = useAppSelector(SelectRoles); // Deprecated + const roles = useAppSelector(SelectRoles); const emptyRecord: SystemCenter.Types.LocationDrawing = { ID: 0, LocationID: 0, Name: '', Link: '', Description: '', Number: '', Category: '' }; const [record, setRecord] = React.useState(emptyRecord); const [hover, setHover] = React.useState<('Update' | 'Reset' | 'None')>('None'); diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/MeterLocation.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/MeterLocation.tsx index 6298b5456..f02e2b446 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/MeterLocation.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/MeterLocation.tsx @@ -168,13 +168,17 @@ const LocationWindow = (props: IProps) => {
    - { setLocation(loc); setHasChanged(true); }} UpdateMeter={(m) => { setHasChanged(props.Meter.LocationID != (m.LocationID != null ? parseInt(m.LocationID.toString()) : 0)); setMeter({ ...m, LocationID: (m.LocationID != null ? parseInt(m.LocationID.toString()) : 0) }); }} DisableLocation={location.ID > 0} + LocationStatus={locationStatus} />
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx index 36aa07c34..feb58a6f2 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx @@ -43,6 +43,7 @@ interface IProps { Locationlist: OpenXDA.Types.Location[], Location: OpenXDA.Types.Location, SetLocation: (loc: OpenXDA.Types.Location) => void, + LocationStatus: string, DisableLocation: boolean } @@ -168,6 +169,7 @@ const MeterLocationProperties = (props: IProps) => {
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/LocationPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/LocationPage.tsx index f2764fe6a..79e71020b 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/LocationPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/LocationPage.tsx @@ -80,7 +80,10 @@ export default function LocationPage(props: IProps) { return ( - { if (m.LocationID != 0 && m.LocationID != null) getDifferentMeterLocation(m.LocationID) @@ -96,8 +99,10 @@ export default function LocationPage(props: IProps) { Description: '', }); }} - Locationlist={locations != null ? locations : []} DisableLocation={props.LocationInfo.ID != 0} /> - + Locationlist={locations != null ? locations : []} + DisableLocation={props.LocationInfo.ID != 0} + LocationStatus={lStatus} + /> ); } diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index ac597ae80..8cd7ed394 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -404,13 +404,13 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { Number of Trend Channels: {channels.reduce((p, c) => c.Trend ? (p + 1) : p, 0)}

    ; else if (currentStep === assetStep - || currentStep === connectionStep - ) - return (<> + || currentStep === connectionStep) + return ( - ) + ) else if (currentStep >= additionalFieldMeterStep) { return (
    From ab95603ad7ba03a03ab58686d8f2ad3e660ac710 Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 22 Jan 2025 10:27:46 -0500 Subject: [PATCH 39/50] Made prop optional --- .../SystemCenter/CommonComponents/LocationDrawingsButton.tsx | 2 +- .../Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index 727222907..54a74360f 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -28,7 +28,7 @@ import LocationDrawingsTable from '../Location/LocationDrawingsTable'; interface LocationDrawingsButtonProps { Locations: OpenXDA.Types.Location[]; - IsLoadingLocations: boolean; + IsLoadingLocations?: boolean; } type DropDownOption = { diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 8cd7ed394..5f8fb7841 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -24,7 +24,7 @@ import * as React from 'react'; import * as _ from 'lodash'; import { Application, OpenXDA } from '@gpa-gemstone/application-typings'; -import { LoadingScreen, ServerErrorIcon, ToolTip, Warning, Modal, ProgressBar } from '@gpa-gemstone/react-interactive'; +import { LoadingScreen, ServerErrorIcon, ToolTip, Warning, Modal, ProgressBar, GenericController } from '@gpa-gemstone/react-interactive'; import { useAppDispatch, useAppSelector } from '../hooks'; import { CrossMark, Warning as WarningSymbol } from '@gpa-gemstone/gpa-symbols'; import { SelectMeterStatus, FetchMeter } from '../Store/MeterSlice'; @@ -408,7 +408,6 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { return ( ) else if (currentStep >= additionalFieldMeterStep) { From c537b3174af5d21c2ed34568bbdc92ddf0354c92 Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 24 Jan 2025 10:30:22 -0500 Subject: [PATCH 40/50] updated LocationDrawingsButton props with memoized location arrays --- .../SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx | 3 ++- .../TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx index feb58a6f2..9bb51b0f9 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Meter/PropertyUI/MeterLocationProperties.tsx @@ -53,6 +53,7 @@ const MeterLocationProperties = (props: IProps) => { const [hover, setHover] = React.useState<('submit' | 'clear' | 'none')>('none'); const roles = useAppSelector(SelectRoles); + const locationArray = React.useMemo(() => [props.Location], [props.Location]); React.useEffect(() => { const key = props.Location.LocationKey; @@ -168,7 +169,7 @@ const MeterLocationProperties = (props: IProps) => {
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx index 5f8fb7841..49a986ad9 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/NewMeterWizard.tsx @@ -98,6 +98,8 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { const [showSubmit, setShowSubmit] = React.useState(false); const [status, setStatus] = React.useState('unintiated'); + const locationInfoArray = React.useMemo(() => [locationInfo], [locationInfo]); + React.useEffect(() => { if (mStatus === 'unintiated' || mStatus === 'changed') dispatch(FetchMeter()); @@ -407,7 +409,7 @@ export default function NewMeterWizard(props: {IsEngineer: boolean}) { || currentStep === connectionStep) return ( ) else if (currentStep >= additionalFieldMeterStep) { From 2c5c685e27fb9e54864d42beded2e900b9770603 Mon Sep 17 00:00:00 2001 From: collins-self Date: Mon, 27 Jan 2025 08:36:45 -0500 Subject: [PATCH 41/50] fixed error handling and DBSearch, organized AssetConnection changes --- .../TSX/SystemCenter/Asset/AssetConnection.tsx | 14 ++++---------- .../CommonComponents/LocationDrawingsButton.tsx | 6 +++--- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index 2a7a26722..a64adb71f 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -111,23 +111,17 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number }, [props.ID, trigger]) React.useEffect(() => { - const h = getLocations(); - return () => { if (h!= null && h.abort != null) h.abort(); } - }, [assetConnections]) - - function getLocations() { setIsLoadingLocations(true); - const h = $.ajax({ + const h = $.ajax({ type: "GET", url: `${homePath}api/OpenXDA/Asset/${props.ID}/Locations`, contentType: "application/json; charset=utf-8", dataType: 'json', cache: true, async: true - }); - h.done(data => { setLocations(data); setIsLoadingLocations(false); }); - return h; - } + }).done(data => { setLocations(data); setIsLoadingLocations(false); }); + return () => { if (h!= null && h.abort != null) h.abort(); } + }, [assetConnections]) function getAssetConnections(): JQuery.jqXHR { setStatus('loading'); diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index 54a74360f..62d34804d 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -26,6 +26,7 @@ import { OpenXDA } from '@gpa-gemstone/application-typings'; import { CrossMark } from '@gpa-gemstone/gpa-symbols'; import LocationDrawingsTable from '../Location/LocationDrawingsTable'; +const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); interface LocationDrawingsButtonProps { Locations: OpenXDA.Types.Location[]; IsLoadingLocations?: boolean; @@ -53,7 +54,7 @@ const isValid = (location: OpenXDA.Types.Location, drawingData) => { && location.Longitude == null && location.Name === "")) e = 'No location(s) have been set.'; - else if (drawingData.TotalRecords == 0) + else if (drawingData.length == 0) e = 'No drawing(s) associated with location.'; return e; } @@ -65,7 +66,6 @@ const LocationDrawingsButton: React.FC = (props) => const multipleLocations = React.useMemo(() => props.Locations.length > 1, [props.Locations]); const [showDrawingsModal, setShowDrawingsModal] = React.useState(false); const [locationOptions, setLocationOptions] = React.useState([]); - const LocationDrawingController = new GenericController(`${homePath}api/LocationDrawing`, "Name", true); React.useEffect(() => { // Generates the map of errors for each location setPageState('loading'); @@ -74,7 +74,7 @@ const LocationDrawingsButton: React.FC = (props) => const handles = props.Locations.map((location, i) => { if (location == null) return null; - const handle = LocationDrawingController.PagedSearch([], 'Name', true, 1, location.ID) + const handle = LocationDrawingController.DBSearch([], 'Name', true, location.ID) .done((result) => { const error = isValid(location, result); const option: DropDownOption = { From 4c66fcb296117bb17e2ec68279430b48889cf4c4 Mon Sep 17 00:00:00 2001 From: collins-self Date: Tue, 28 Jan 2025 08:14:29 -0500 Subject: [PATCH 42/50] adjust table column styles and csproj --- .../SystemCenter/SystemCenter.csproj | 4 ++- .../LocationDrawingsButton.tsx | 2 +- .../Location/LocationDrawingsTable.tsx | 34 +++++++++---------- .../SystemCenter/NewMeterWizard/AssetPage.tsx | 6 ++-- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Source/Applications/SystemCenter/SystemCenter.csproj b/Source/Applications/SystemCenter/SystemCenter.csproj index 20e9b3b17..b72a1eebe 100644 --- a/Source/Applications/SystemCenter/SystemCenter.csproj +++ b/Source/Applications/SystemCenter/SystemCenter.csproj @@ -578,7 +578,9 @@ - + + + diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index 62d34804d..cc933fea1 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -143,7 +143,7 @@ const LocationDrawingsButton: React.FC = (props) => setShowDrawingsModal(false)} ShowCancel={false} ShowConfirm={false}> diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx index 0db709a6f..28fe813eb 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx @@ -119,49 +119,49 @@ const LocationDrawingsTable = (props: IProps) => { Key={'Name'} AllowSort={true} Field={'Name'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} + HeaderStyle={{ width: '20%' }} + RowStyle={{ width: '20%' }} > Name Key={'Link'} AllowSort={true} Field={'Link'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} + HeaderStyle={{ width: '20%' }} + RowStyle={{ width: '20%' }} Content={({ item, key }) => {item[key]}} > Link - - Key={'Description'} - AllowSort={true} - Field={'Description'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} - > Description - Key={'Number'} AllowSort={true} Field={'Number'} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} > Number Key={'Category'} AllowSort={true} Field={'Category'} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} + > Category + + + Key={'Description'} + AllowSort={true} + Field={'Description'} HeaderStyle={{ width: 'auto' }} RowStyle={{ width: 'auto' }} - > Category + > Description {props.Edit ? Key={'EditDelete'} AllowSort={false} - HeaderStyle={{ width: 'auto' }} - RowStyle={{ width: 'auto' }} + HeaderStyle={{ width: '10%' }} + RowStyle={{ width: '10%' }} Content={({ item }) =>
    -
    + ); }; From 6581c96ea7e853505c40c7907f74695a6d981251 Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 31 Jan 2025 11:33:19 -0500 Subject: [PATCH 45/50] updated props and imports --- .../LocationDrawingsButton.tsx | 1 - .../Location/LocationDrawings.tsx | 1 - .../Location/LocationDrawingsTable.tsx | 30 ++++++++-------- .../SystemCenter/NewMeterWizard/AssetPage.tsx | 34 +++++++++---------- 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index 364f8ec7e..7940fe68a 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -124,7 +124,6 @@ const LocationDrawingsButton: React.FC = (props) => {

    Your role does not have permission. Please contact your Administrator if you believe this to be in error.

    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx index 28fe813eb..35c1a8223 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Location/LocationDrawingsTable.tsx @@ -23,7 +23,7 @@ import { SystemCenter } from "@gpa-gemstone/application-typings"; import { Pencil, TrashCan } from "@gpa-gemstone/gpa-symbols"; import { GenericController, LoadingScreen, ServerErrorIcon } from "@gpa-gemstone/react-interactive"; -import { ReactTable, Paging } from "@gpa-gemstone/react-table"; +import { Column, Table, Paging } from "@gpa-gemstone/react-table"; import React from "react"; import { useAppSelector } from "../hooks"; import { SelectRoles } from "../Store/UserSettings"; @@ -93,7 +93,7 @@ const LocationDrawingsTable = (props: IProps) => { return <>
    - + TableClass="table table-hover" Data={links} SortKey={sortKey} @@ -115,15 +115,15 @@ const LocationDrawingsTable = (props: IProps) => { Selected={(item) => false} KeySelector={(item) => item.ID} > - + Key={'Name'} AllowSort={true} Field={'Name'} HeaderStyle={{ width: '20%' }} RowStyle={{ width: '20%' }} > Name - - + + Key={'Link'} AllowSort={true} Field={'Link'} @@ -131,33 +131,33 @@ const LocationDrawingsTable = (props: IProps) => { RowStyle={{ width: '20%' }} Content={({ item, key }) => {item[key]}} > Link - - + + Key={'Number'} AllowSort={true} Field={'Number'} HeaderStyle={{ width: '10%' }} RowStyle={{ width: '10%' }} > Number - - + + Key={'Category'} AllowSort={true} Field={'Category'} HeaderStyle={{ width: '10%' }} RowStyle={{ width: '10%' }} > Category - - + + Key={'Description'} AllowSort={true} Field={'Description'} HeaderStyle={{ width: 'auto' }} RowStyle={{ width: 'auto' }} > Description - + {props.Edit ? - + Key={'EditDelete'} AllowSort={false} HeaderStyle={{ width: '10%' }} @@ -171,9 +171,9 @@ const LocationDrawingsTable = (props: IProps) => { } >

    - + : null} - +
    diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index 92313cc5a..dd745a82e 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -40,7 +40,7 @@ import DERAttributes from '../AssetAttribute/DER'; import AssetSelect from '../Asset/AssetSelect'; import { ReactIcons } from '@gpa-gemstone/gpa-symbols'; import { getAssetWithAdditionalFields } from '../../../TS/Services/Asset'; -import { ReactTable } from '@gpa-gemstone/react-table'; +import { Table, Column } from '@gpa-gemstone/react-table'; import GenerationAttributes from '../AssetAttribute/Generation'; import StationAuxAttributes from '../AssetAttribute/StationAux'; import StationBatteryAttributes from '../AssetAttribute/StationBattery'; @@ -348,7 +348,7 @@ export default function AssetPage(props: IProps) {
    - + TableClass="table table-hover" Data={assetData} SortKey={sortKey} @@ -369,47 +369,47 @@ export default function AssetPage(props: IProps) { Selected={(item) => false} KeySelector={(item) => item.ID} > - + Key={'Status'} AllowSort={true} HeaderStyle={{ width: '10%' }} RowStyle={{ width: '10%' }} Content={({ item }) => item.ID == 0 ? 'New' : 'Existing' } > Status - - + + Key={'AssetKey'} AllowSort={true} Field={'AssetKey'} HeaderStyle={{ width: '20%' }} RowStyle={{ width: '20%' }} > Key - - + + Key={'AssetName'} AllowSort={true} Field={'AssetName'} HeaderStyle={{ width: '30%' }} RowStyle={{ width: '30%' }} > Name - - + + Key={'AssetType'} AllowSort={true} Field={'AssetType'} HeaderStyle={{ width: '10%' }} RowStyle={{ width: '10%' }} > Type - - + + Key={'VoltageKV'} AllowSort={true} Field={'VoltageKV'} HeaderStyle={{ width: '10%' }} RowStyle={{ width: '10%' }} > kV - - + + Key={'Channels'} AllowSort={true} Field={'Channels'} @@ -417,8 +417,8 @@ export default function AssetPage(props: IProps) { RowStyle={{ width: '10%' }} Content={({ item }) => item.Channels.length } > Channels - - + + Key={'Buttons'} AllowSort={false} HeaderStyle={{ width: '10%' }} @@ -428,8 +428,8 @@ export default function AssetPage(props: IProps) { } >

    - - + +
    From 3b96c34565066f91de48214af62bde45605f2d7c Mon Sep 17 00:00:00 2001 From: collins-self Date: Fri, 31 Jan 2025 11:51:18 -0500 Subject: [PATCH 46/50] removed redundant button fixed tooltip --- .../CommonComponents/LocationDrawingsButton.tsx | 5 +++-- .../Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx | 6 ------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx index 7940fe68a..67b0463f0 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/CommonComponents/LocationDrawingsButton.tsx @@ -118,16 +118,17 @@ const LocationDrawingsButton: React.FC = (props) =>

    {CrossMark} {locationOptions[0]?.ToolTipContent}

    + >

    {locationOptions[0]?.ToolTipContent}

    :
    Actions: -
    -
    - -
    -
    From 09bd2c749f7d660d53dd9808b4a6b3ed0991ead2 Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 5 Feb 2025 11:10:20 -0500 Subject: [PATCH 47/50] added missing imports --- .../Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index 3e4a5912c..0e84b1e5f 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -38,7 +38,7 @@ import { SelectAssetStatus, FetchAsset, SelectAssets } from '../Store/AssetSlice import { Modal, Search, TabSelector } from '@gpa-gemstone/react-interactive'; import DERAttributes from '../AssetAttribute/DER'; import AssetSelect from '../Asset/AssetSelect'; -import { ReactIcons } from '@gpa-gemstone/gpa-symbols'; +import { CrossMark, Pencil, ReactIcons, TrashCan } from '@gpa-gemstone/gpa-symbols'; import { getAssetWithAdditionalFields } from '../../../TS/Services/Asset'; import { Table, Column } from '@gpa-gemstone/react-table'; import GenerationAttributes from '../AssetAttribute/Generation'; From ff331c04cb0fd06c3df48d1719ac8d6c4a1180fc Mon Sep 17 00:00:00 2001 From: collins-self Date: Wed, 12 Feb 2025 09:52:33 -0500 Subject: [PATCH 48/50] cleaned up NMW/AssetPage --- .../SystemCenter/NewMeterWizard/AssetPage.tsx | 147 +++++++++++------- 1 file changed, 87 insertions(+), 60 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index 0e84b1e5f..2d4df4252 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -38,7 +38,7 @@ import { SelectAssetStatus, FetchAsset, SelectAssets } from '../Store/AssetSlice import { Modal, Search, TabSelector } from '@gpa-gemstone/react-interactive'; import DERAttributes from '../AssetAttribute/DER'; import AssetSelect from '../Asset/AssetSelect'; -import { CrossMark, Pencil, ReactIcons, TrashCan } from '@gpa-gemstone/gpa-symbols'; +import { ReactIcons } from '@gpa-gemstone/gpa-symbols'; import { getAssetWithAdditionalFields } from '../../../TS/Services/Asset'; import { Table, Column } from '@gpa-gemstone/react-table'; import GenerationAttributes from '../AssetAttribute/Generation'; @@ -104,7 +104,6 @@ export default function AssetPage(props: IProps) { channelsWorking.filter(ch => (ch.Asset === (newEdit === 'Edit' ? editAssetKey : tempKey)) || (ch.Asset === "")) , [channelsWorking, editAssetKey, newEdit]); - const locations = React.useMemo(() => [props.Location], [props.Location]) const assetData = React.useMemo(() => { const u = _.cloneDeep(props.Assets); @@ -329,9 +328,32 @@ export default function AssetPage(props: IProps) {
    -
      +
        +
        +
        + setShowSeries(s => !s)} + value={showSeries ? 'on' : 'off'} + checked={showSeries} + /> + +
        +
        { - props.Channels.map((channel) =>
      • 0 ? 'line-through' : null)}} key={channel.ID}>{channel.Name + ' - ' + channel.Description}
      • ) + props.Channels.map((channel) => +
      • 0 ? 'line-through' : null) }} key={channel.ID}> + { + channel.Name + + (channel.Name !== channel.Description ? ` - ${channel.Description}` : '') + + ((showSeries && channel.Series.length > 0 && channel.Series[0].SourceIndexes !== '' ) ? ` (${channel.Series[0].SourceIndexes})` : '') + } +
      • + ) }
    @@ -366,7 +388,7 @@ export default function AssetPage(props: IProps) { TbodyStyle={{ display: 'block', overflowY: 'scroll', flex: 1 }} RowStyle={{ display: 'table', tableLayout: 'fixed', width: '100%' }} Selected={(item) => false} - KeySelector={(item) => item.ID} + KeySelector={(item) => item.AssetKey} > Key={'Status'} @@ -423,8 +445,16 @@ export default function AssetPage(props: IProps) { HeaderStyle={{ width: '10%' }} RowStyle={{ width: '10%' }} Content={({ index }) => <> - - + + } >

    @@ -440,8 +470,8 @@ export default function AssetPage(props: IProps) { if (!confirm) return; let list: Array = []; - let channels: Array = _.clone(props.Channels); - let assetConnections: Array = _.clone(props.AssetConnections); + let channels: Array = _.cloneDeep(props.Channels); + let assetConnections: Array = _.cloneDeep(props.AssetConnections); let removedAssets: Array = props.Assets.filter((asset) => asset.ID > 0 && selected.findIndex((selectedAsset) => (asset.ID === selectedAsset.ID)) < 0); @@ -460,7 +490,9 @@ export default function AssetPage(props: IProps) { }); let promises = []; $.each(selected, async (index, record) => { - let assetRecord = getAssetWithAdditionalFields(record.ID, record.AssetType as OpenXDA.Types.AssetTypeName); + const oldRecord = props.Assets.find(asset => asset.ID === record.ID); + let assetRecord = getAssetWithAdditionalFields(record.ID, record.AssetType as OpenXDA.Types.AssetTypeName) + .then(a => ({ ...a, Channels: oldRecord?.Channels ?? []})); // Push promises into promises promises.push(assetRecord); }); @@ -489,69 +521,64 @@ export default function AssetPage(props: IProps) { ConfirmBtnClass={'btn-success'} ConfirmText={newEdit == 'Edit' ? 'Save' : 'Add'} CancelBtnClass={'btn-danger'} - CancelText={'Close'} + ShowCancel={false} + ShowX={true} Size={'xlg'} CallBack={(confirm) => { - setShowAssetModal(false); - - if (!confirm) { - setNewEditAsset(AssetAttributes.getNewAsset('Line')); - return; - } - - let record: OpenXDA.Types.Asset = _.clone(newEditAsset); - let list = _.clone(props.Assets); - let channels: Array = _.clone(props.Channels); - - $.each(channels, (index, channel) => { - if (channel.Asset == record.AssetKey) - channel.Asset = '' - - if (record.Channels.findIndex(c => c.ID == channel.ID) >= 0) - channel.Asset = record.AssetKey - }); - - if (newEdit == 'New') - list.push(record); - if (newEdit == 'Edit') { - const index = list.findIndex(a => a.AssetKey == editAssetKey); - list[index] = record; + if (confirm) { + const record: OpenXDA.Types.Asset = _.cloneDeep(newEditAsset); + const list = _.cloneDeep(props.Assets); + if (newEdit == 'New') { + // We have to do this swap because the key isn't set in stone until now + const channelsWithNewKey = channelsWorking + .map(chan => (chan.Asset === tempKey) ? ({ ...chan, Asset: record.AssetKey }) : chan); + record.Channels = channelsWithNewKey + .filter(chan => chan.Asset === record.AssetKey);; + list.push(record); + props.UpdateChannels(channelsWithNewKey); + } + else if (newEdit == 'Edit') { + const index = list.findIndex(a => a.AssetKey == editAssetKey); + list[index] = record; + props.UpdateChannels(channelsWorking); + } + props.UpdateAssets(list); } + else setChannelsWorking(props.Channels); - props.UpdateChannels(channels); - props.UpdateAssets(list); + setShowAssetModal(false); setNewEditAsset(AssetAttributes.getNewAsset('Line')); }} DisableConfirm={(AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).length > 0) } ConfirmShowToolTip={AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).length > 0} ConfirmToolTipContent={ - AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).map((e, i) =>

    {CrossMark} {e}

    ) + AssetAttributes.AssetError(newEditAsset, newEditAsset.AssetType, allAssetKeys).map((e, i) =>

    {e}

    ) } >
    -
    -
    - { - if (record.AssetType == newEditAsset.AssetType) - setNewEditAsset(record); - else { - let newRecord = AssetAttributes.getNewAsset(record.AssetType); - newRecord.AssetKey = record.AssetKey; - newRecord.AssetName = record.AssetName; - newRecord.VoltageKV = record.VoltageKV; - newRecord.Description = record.Description; - newRecord.Channels = record.Channels; - setNewEditAsset(newRecord); - } - }} - GetDifferentAsset={getDifferentAsset} HideAssetType={newEdit == 'Edit'} HideSelectAsset={true} /> -
    -
    - {showAttributes()} -
    +
    +
    + { + if (record.AssetType == newEditAsset.AssetType) + setNewEditAsset(record); + else { + let newRecord = AssetAttributes.getNewAsset(record.AssetType); + newRecord.AssetKey = record.AssetKey; + newRecord.AssetName = record.AssetName; + newRecord.VoltageKV = record.VoltageKV; + newRecord.Description = record.Description; + newRecord.Channels = record.Channels; + setNewEditAsset(newRecord); + } + }} + GetDifferentAsset={getDifferentAsset} HideAssetType={newEdit == 'Edit'} HideSelectAsset={true} /> +
    +
    + {showAttributes()} +
    From 1f8a16c3e90aa3de7daa210b4907885046039994 Mon Sep 17 00:00:00 2001 From: collins-self Date: Mon, 17 Feb 2025 09:02:39 -0500 Subject: [PATCH 49/50] quick fixes --- .../Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx | 10 +++++----- .../TSX/SystemCenter/NewMeterWizard/AssetPage.tsx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx index a64adb71f..6d78d37ad 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/Asset/AssetConnection.tsx @@ -66,6 +66,11 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number const [hover, setHover] = React.useState<('Update' | 'Reset' | 'None' | 'Drawings')>('None'); const roles = useAppSelector(SelectRoles); + React.useEffect(() => { + const handle = getAssetConnections(); + return () => { if (handle != null && handle.abort != null) handle.abort(); } + }, [props.ID, trigger]) + React.useEffect(() => { if (props.ID > 0) { let sqlString = `(SELECT AssetRelationshipTypeID FROM AssetRelationshipTypeAssetType LEFT JOIN Asset ON ` @@ -105,11 +110,6 @@ function AssetConnectionWindow(props: { Name: string, ID: number, TypeID: number setSelectedAssetID(localAssets[0].ID) }, [localAssets]) - React.useEffect(() => { - const handle = getAssetConnections(); - return () => { if (handle != null && handle.abort != null) handle.abort(); } - }, [props.ID, trigger]) - React.useEffect(() => { setIsLoadingLocations(true); const h = $.ajax({ diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index 2d4df4252..afc66e944 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -533,7 +533,7 @@ export default function AssetPage(props: IProps) { const channelsWithNewKey = channelsWorking .map(chan => (chan.Asset === tempKey) ? ({ ...chan, Asset: record.AssetKey }) : chan); record.Channels = channelsWithNewKey - .filter(chan => chan.Asset === record.AssetKey);; + .filter(chan => chan.Asset === record.AssetKey); list.push(record); props.UpdateChannels(channelsWithNewKey); } From fac8a0fae60d9cbc242c20ff4a12eb49b282c145 Mon Sep 17 00:00:00 2001 From: collins-self Date: Mon, 17 Feb 2025 10:17:24 -0500 Subject: [PATCH 50/50] removed fieldset --- .../Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx index afc66e944..74e06ebfb 100644 --- a/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx +++ b/Source/Applications/SystemCenter/wwwroot/Scripts/TSX/SystemCenter/NewMeterWizard/AssetPage.tsx @@ -510,11 +510,6 @@ export default function AssetPage(props: IProps) { props.UpdateChannels(channels); props.UpdateAssetConnections(assetConnections); }}> -
  • -
    - Actions: -
    -