@@ -33,7 +33,7 @@ import SaveIcon from '@material-ui/icons/Save'
33
33
import { Alert } from '@material-ui/lab'
34
34
import classNames from 'classnames'
35
35
import DOMPurify from 'dompurify'
36
- import { isArray , isNaN , partition , range } from 'lodash'
36
+ import { isArray , isNaN , isPlainObject , partition , range } from 'lodash'
37
37
import { complex , format } from 'mathjs'
38
38
import PropTypes from 'prop-types'
39
39
import React , { useCallback , useContext , useEffect , useMemo , useRef , useState } from 'react'
@@ -60,6 +60,7 @@ import { useErrors } from '../errors'
60
60
import Markdown from '../Markdown'
61
61
import { EntryButton } from '../nav/Routes'
62
62
import { Quantity as Q } from '../units/Quantity'
63
+ import { Unit } from '../units/Unit'
63
64
import { useDisplayUnit } from '../units/useDisplayUnit'
64
65
import H5Web from '../visualization/H5Web'
65
66
import Pagination from '../visualization/Pagination'
@@ -673,11 +674,13 @@ class QuantityAdaptor extends ArchiveAdaptor {
673
674
}
674
675
675
676
render ( ) {
676
- if ( quantityUsesFullStorage ( this . def ) ) {
677
- return < FullStorageQuantity value = { this . obj } def = { this . def } />
678
- } else {
679
- return < Quantity value = { this . obj } def = { this . def } />
680
- }
677
+ return < Quantity value = { this . obj } def = { this . def } >
678
+ { this . obj ?. m_attributes ?. length > 0 && < Compartment title = "attributes" >
679
+ { Object . keys ( this . obj ?. m_attributes ) . map ( key => (
680
+ < Item key = { key } itemKey = { key } > { key } </ Item >
681
+ ) ) }
682
+ </ Compartment > }
683
+ </ Quantity >
681
684
}
682
685
}
683
686
@@ -694,7 +697,7 @@ const convertComplexArray = (real, imag) => {
694
697
}
695
698
696
699
export function QuantityItemPreview ( { value, def} ) {
697
- const displayUnit = useDisplayUnit ( def )
700
+ let { finalValue , displayUnit, storageUnit } = useQuantityData ( value , def )
698
701
699
702
if ( isReference ( def ) ) {
700
703
return < Box component = "span" fontStyle = "italic" >
@@ -720,14 +723,14 @@ export function QuantityItemPreview({value, def}) {
720
723
const dimensions = [ ]
721
724
let typeLabel = 'unknown'
722
725
try {
723
- let current = value . re || value . im || value
726
+ let current = finalValue . re || finalValue . im || finalValue
724
727
for ( let i = 0 ; i < def . shape . length ; i ++ ) {
725
728
dimensions . push ( current . length )
726
729
current = current [ 0 ]
727
730
}
728
731
if ( def . type . type_kind === 'python' ) {
729
732
typeLabel = 'list'
730
- } else if ( typeof value === 'string' ) {
733
+ } else if ( typeof finalValue === 'string' ) {
731
734
typeLabel = 'HDF5 array'
732
735
dimensions . length = 0
733
736
} else {
@@ -752,17 +755,13 @@ export function QuantityItemPreview({value, def}) {
752
755
</ Typography >
753
756
</ Box >
754
757
} else {
755
- let finalValue
756
758
if ( def . type . type_data === 'nomad.metainfo.metainfo._Datetime' || def . type . type_data === 'nomad.metainfo.data_type.Datetime' ) {
757
- finalValue = formatTimestamp ( value )
759
+ finalValue = formatTimestamp ( finalValue )
758
760
} else if ( def . type . type_data . startsWith ?. ( 'complex' ) ) {
759
- finalValue = convertComplexArray ( value . re , value . im )
760
- } else {
761
- finalValue = value
761
+ finalValue = convertComplexArray ( finalValue . re , finalValue . im )
762
762
}
763
-
764
763
if ( displayUnit ) {
765
- finalValue = new Q ( finalValue , def . unit ) . to ( displayUnit ) . value ( )
764
+ finalValue = new Q ( finalValue , storageUnit ) . to ( displayUnit ) . value ( )
766
765
}
767
766
return < Box component = "span" whiteSpace = "nowarp" >
768
767
< Number component = "span" variant = "body1" value = { finalValue } exp = { 8 } />
@@ -776,35 +775,57 @@ QuantityItemPreview.propTypes = ({
776
775
def : PropTypes . object . isRequired
777
776
} )
778
777
778
+ /**
779
+ * Hook for getting the final value and units for a quantity. Also supports
780
+ * quantities using full storage.
781
+ *
782
+ * @param {* } data Value of the quantity
783
+ * @param {* } def Defintion of the quantity
784
+ * @returns Object containing the final value, storage unit and display unit.
785
+ */
786
+ function useQuantityData ( data , def ) {
787
+ let storageUnit = def . unit
788
+ let displayUnit = useDisplayUnit ( def )
789
+ let finalValue = data
790
+ if ( quantityUsesFullStorage ( def ) && isPlainObject ( data ) ) {
791
+ displayUnit = data ?. m_unit && new Unit ( data . m_unit )
792
+ storageUnit = data ?. m_original_unit
793
+ finalValue = data ?. m_value
794
+ }
795
+ return { finalValue, displayUnit, storageUnit}
796
+ }
797
+
779
798
export const QuantityValue = React . memo ( function QuantityValue ( { value, def} ) {
780
799
const { uploadId} = useEntryStore ( ) || { }
781
- const displayUnit = useDisplayUnit ( def )
800
+ let { finalValue , displayUnit, storageUnit } = useQuantityData ( value , def )
782
801
783
- const getRenderValue = useCallback ( value => {
784
- let finalValue
802
+ const getRenderValue = useCallback ( ( value ) => {
803
+ let finalValue , finalUnit
785
804
if ( def . type . type_data === 'nomad.metainfo.metainfo._Datetime' || def . type . type_data === 'nomad.metainfo.data_type.Datetime' ) {
786
805
finalValue = formatTimestamp ( value )
787
806
} else if ( def . type . type_data . startsWith ?. ( 'complex' ) ) {
788
807
finalValue = convertComplexArray ( value . re , value . im )
789
808
} else {
790
809
finalValue = value
791
810
}
792
- let finalUnit
793
- if ( def . unit && typeof finalValue !== 'string' ) {
794
- const systemUnitQ = new Q ( finalValue , def . unit ) . to ( displayUnit )
811
+
812
+ if ( typeof finalValue !== 'string' && storageUnit && displayUnit ) {
813
+ const systemUnitQ = new Q ( finalValue , storageUnit ) . to ( displayUnit )
795
814
finalValue = systemUnitQ . value ( )
796
815
finalUnit = systemUnitQ . label ( )
797
816
}
817
+
798
818
return [ finalValue , finalUnit ]
799
- } , [ def , displayUnit ] )
819
+ } , [ def , storageUnit , displayUnit ] )
800
820
801
821
const isMathValue = ( def . type . type_kind === 'numpy' || def . type . type_kind === 'python' ) && typeof value !== 'string'
802
822
if ( isMathValue ) {
803
- const [ finalValue , finalUnit ] = getRenderValue ( value )
823
+ const [ renderValue , finalUnit ] = getRenderValue ( finalValue )
804
824
if ( def . shape . length > 0 ) {
825
+ console . log ( renderValue )
805
826
return < Box textAlign = "center" >
806
827
< Matrix
807
- values = { finalValue }
828
+ values = { renderValue }
808
829
shape = { def . shape }
809
830
invert = { def . shape . length === 1 }
810
831
type = { def . type . type_data }
@@ -818,54 +839,53 @@ export const QuantityValue = React.memo(function QuantityValue({value, def}) {
818
839
{ finalUnit && < Typography noWrap > { finalUnit } </ Typography > }
819
840
</ Box >
820
841
} else {
821
- return < Number value = { finalValue } exp = { 16 } variant = "body1" unit = { finalUnit } />
842
+ return < Number value = { renderValue } exp = { 16 } variant = "body1" unit = { finalUnit } />
822
843
}
823
844
} else if ( def . m_annotations ?. browser ?. [ 0 ] ?. render_value === 'HtmlValue' || def . m_annotations ?. eln ?. [ 0 ] ?. component === 'RichTextEditQuantity' ) {
824
- const html = DOMPurify . sanitize ( value )
845
+ const html = DOMPurify . sanitize ( finalValue )
825
846
return < div dangerouslySetInnerHTML = { { __html : html } } />
826
847
} else if ( def . type ?. type_data === 'nomad.metainfo.metainfo._JSON' || def . type ?. type_data === 'nomad.metainfo.data_type.JSON' ) {
827
848
return < ReactJson
828
849
name = "value"
829
- src = { value }
850
+ src = { finalValue }
830
851
enableClipboard = { false }
831
852
collapsed = { 2 }
832
853
displayObjectSize = { false }
833
854
/>
834
855
} else {
835
856
if ( def . type . type_data . startsWith ?. ( 'complex' ) ) {
836
- value = convertComplexArray ( value . re , value . im )
857
+ finalValue = convertComplexArray ( finalValue . re , finalValue . im )
837
858
838
- return Array . isArray ( value )
859
+ return Array . isArray ( finalValue )
839
860
? < ul style = { { margin : 0 } } >
840
- { value . map ( ( value , index ) => < li key = { index } > < Typography > { value } </ Typography > </ li > ) }
861
+ { finalValue . map ( ( value , index ) => < li key = { index } > < Typography > { value } </ Typography > </ li > ) }
841
862
</ ul >
842
- : < Typography > { value } </ Typography >
843
- } else if ( Array . isArray ( value ) ) {
863
+ : < Typography > { finalValue } </ Typography >
864
+ } else if ( Array . isArray ( finalValue ) ) {
844
865
return < ul style = { { margin : 0 } } >
845
- { value . map ( ( value , index ) => {
846
- const [ finalValue ] = getRenderValue ( value )
866
+ { finalValue . map ( ( value , index ) => {
867
+ const [ renderValue ] = getRenderValue ( value )
847
868
return < li key = { index } >
848
- < Typography > { typeof finalValue === 'object' ? JSON . stringify ( finalValue ) : finalValue ?. toString ( ) } </ Typography >
869
+ < Typography > { typeof renderValue === 'object' ? JSON . stringify ( renderValue ) : renderValue ?. toString ( ) } </ Typography >
849
870
</ li >
850
871
} ) }
851
872
</ ul >
852
873
} else if ( def . type ?. type_data === 'nomad.datamodel.hdf5.HDF5Dataset' || def . type ?. type_data === 'nomad.datamodel.hdf5.HDF5Reference' ) {
853
- const { h5UploadId, h5File, h5Source, h5Path} = matchH5Path ( value )
874
+ const { h5UploadId, h5File, h5Source, h5Path} = matchH5Path ( finalValue )
854
875
return < Compartment title = 'hdf5' >
855
876
< H5Web upload_id = { h5UploadId || uploadId } filename = { h5File } initialPath = { h5Path } source = { h5Source } sidebarOpen = { false } > </ H5Web >
856
877
</ Compartment >
857
878
} else if ( def ?. type ?. type_kind === 'custom' && def ?. type ?. type_data === 'nomad.datamodel.data.Query' ) {
858
- return < Query value = { value } def = { def } />
879
+ return < Query value = { finalValue } def = { def } />
859
880
} else {
860
- const [ finalValue ] = getRenderValue ( value )
861
- return < Typography > { typeof finalValue === 'object' ? JSON . stringify ( finalValue ) : finalValue ?. toString ( ) } </ Typography >
881
+ const [ renderValue ] = getRenderValue ( finalValue )
882
+ return < Typography > { typeof renderValue === 'object' ? JSON . stringify ( renderValue ) : renderValue ?. toString ( ) } </ Typography >
862
883
}
863
884
}
864
885
} )
865
886
QuantityValue . propTypes = ( {
866
887
value : PropTypes . any ,
867
- def : PropTypes . object . isRequired ,
868
- unit : PropTypes . string
888
+ def : PropTypes . object . isRequired
869
889
} )
870
890
871
891
const InheritingSections = React . memo ( function InheritingSections ( { def, section, lane} ) {
@@ -1072,7 +1092,7 @@ export function Section({section, def, property, parentRelation, sectionIsEditab
1072
1092
const storage = section [ quantityDef . name ] || { }
1073
1093
return < React . Fragment key = { key } >
1074
1094
{ Object . keys ( storage ) . map ( quantityName =>
1075
- renderQuantityItem ( key , quantityName , quantityDef , storage [ quantityName ] ?. m_value , disabled )
1095
+ renderQuantityItem ( key , quantityName , quantityDef , storage [ quantityName ] , disabled )
1076
1096
) }
1077
1097
</ React . Fragment >
1078
1098
} else {
@@ -1623,23 +1643,7 @@ SectionPlots.propTypes = {
1623
1643
entryId : PropTypes . string
1624
1644
}
1625
1645
1626
- function FullStorageQuantity ( { value, def} ) {
1627
- const attributes = value . m_attributes || { }
1628
- return < Quantity value = { value . m_value } def = { def } unit = { value . m_unit } >
1629
- { Object . keys ( attributes ) . length > 0 && < Compartment title = "attributes" >
1630
- { Object . keys ( attributes ) . map ( key => (
1631
- < Item key = { key } itemKey = { key } > { key } </ Item >
1632
- ) ) }
1633
- </ Compartment > }
1634
- </ Quantity >
1635
- }
1636
-
1637
- FullStorageQuantity . propTypes = ( {
1638
- value : PropTypes . any ,
1639
- def : PropTypes . object . isRequired
1640
- } )
1641
-
1642
- function Quantity ( { value, def, unit, children} ) {
1646
+ function Quantity ( { value, def, children} ) {
1643
1647
const { prev} = useLane ( )
1644
1648
return < Content >
1645
1649
< ArchiveTitle def = { def } data = { value } kindLabel = "value" />
@@ -1657,7 +1661,6 @@ function Quantity({value, def, unit, children}) {
1657
1661
< QuantityValue
1658
1662
value = { value }
1659
1663
def = { def }
1660
- unit = { unit }
1661
1664
/>
1662
1665
</ Compartment >
1663
1666
{ children }
0 commit comments