1- import { useEffect , useRef , useState , useMemo } from 'react' ;
1+ import { useEffect , useRef , useMemo } from 'react' ;
22import { useDispatch , useSelector } from 'react-redux' ;
33import url from 'url' ;
44import _ from 'lodash' ;
55
66import cn from 'bem-cn-lite' ;
77
8- import { ArrowToggle , Button , Loader , Tooltip } from '@yandex-cloud/uikit' ;
9- import DataTable , { Column , Settings } from '@yandex-cloud/react-data-table' ;
8+ import { Loader } from '@yandex-cloud/uikit' ;
109
11- import EntityStatus from '../../../components/EntityStatus/EntityStatus' ;
12- import InfoViewer from '../../../components/InfoViewer/InfoViewer' ;
13- import ProgressViewer from '../../../components/ProgressViewer/ProgressViewer' ;
14- import Icon from '../../../components/Icon/Icon' ;
15- //@ts -ignore
16- import { Vdisk } from '../../VdiskPdiskNode/VdiskPdiskNode' ;
17-
18- import { bytesToGB , pad9 } from '../../../utils/utils' ;
19- import { formatStorageValuesToGb } from '../../../utils' ;
10+ import { PDisk } from './Pdisk' ;
2011
2112import { getNodeStructure , selectNodeStructure } from '../../../store/reducers/node' ;
2213
@@ -26,284 +17,14 @@ import './NodeStructure.scss';
2617
2718const b = cn ( 'kv-node-structure' ) ;
2819
29- function valueIsDefined ( value : any ) {
20+ export function valueIsDefined ( value : any ) {
3021 return value !== null && value !== undefined ;
3122}
3223
3324function generateId ( { type, id} : { type : 'pdisk' | 'vdisk' ; id : string } ) {
3425 return `${ type } -${ id } ` ;
3526}
3627
37- interface PDiskProps {
38- data : Record < string , any > ;
39- unfolded ?: boolean ;
40- id : string ;
41- selectedVdiskId ?: string ;
42- nodeHref ?: string ;
43- }
44-
45- enum VDiskTableColumnsIds {
46- slotId = 'VDiskSlotId' ,
47- VDiskState = 'VDiskState' ,
48- Size = 'Size' ,
49- Info = 'Info' ,
50- }
51-
52- type VDiskTableColumnsIdsKeys = keyof typeof VDiskTableColumnsIds ;
53- type VDiskTableColumnsIdsValues = typeof VDiskTableColumnsIds [ VDiskTableColumnsIdsKeys ] ;
54-
55- const vDiskTableColumnsNames : Record < VDiskTableColumnsIdsValues , string > = {
56- VDiskSlotId : 'Slot id' ,
57- VDiskState : 'Status' ,
58- Size : 'Size' ,
59- Info : '' ,
60- } ;
61-
62- function getColumns ( {
63- pDiskId,
64- selectedVdiskId,
65- nodeHref,
66- } : {
67- pDiskId : number ;
68- selectedVdiskId ?: string ;
69- nodeHref ?: string ;
70- } ) {
71- const columns : Column < any > [ ] = [
72- {
73- name : VDiskTableColumnsIds . slotId as string ,
74- header : vDiskTableColumnsNames [ VDiskTableColumnsIds . slotId ] ,
75- width : 100 ,
76- render : ( { value, row} ) => {
77- let vdiskInternalViewerLink : string | undefined ;
78-
79- if ( nodeHref && value !== undefined ) {
80- vdiskInternalViewerLink +=
81- nodeHref + '/actors/vdisks/vdisk' + pad9 ( pDiskId ) + '_' + pad9 ( value ) ;
82- }
83-
84- return (
85- < div className = { b ( 'vdisk-id' , { selected : row . id === selectedVdiskId } ) } >
86- < span > { value as any } </ span >
87- { vdiskInternalViewerLink && (
88- < Button
89- size = "s"
90- className = { b ( 'external-button' , { hidden : true } ) }
91- href = { vdiskInternalViewerLink }
92- target = "_blank"
93- >
94- < Icon name = "external" />
95- </ Button >
96- ) }
97- </ div >
98- ) ;
99- } ,
100- align : DataTable . LEFT ,
101- } ,
102- {
103- name : VDiskTableColumnsIds . VDiskState as string ,
104- header : vDiskTableColumnsNames [ VDiskTableColumnsIds . VDiskState ] ,
105- width : 70 ,
106- render : ( { value} ) => {
107- return < EntityStatus status = { value === 'OK' ? 'green' : 'red' } /> ;
108- } ,
109- sortAccessor : ( row ) => ( row [ VDiskTableColumnsIds . VDiskState ] === 'OK' ? 1 : 0 ) ,
110- align : DataTable . CENTER ,
111- } ,
112- {
113- name : VDiskTableColumnsIds . Size as string ,
114- header : vDiskTableColumnsNames [ VDiskTableColumnsIds . Size ] ,
115- width : 100 ,
116- render : ( { row} ) => {
117- return (
118- < ProgressViewer
119- value = { row . AllocatedSize }
120- capacity = { Number ( row . AllocatedSize ) + Number ( row . AvailableSize ) }
121- formatValues = { formatStorageValuesToGb }
122- colorizeProgress = { true }
123- />
124- ) ;
125- } ,
126- sortAccessor : ( row ) => Number ( row . AllocatedSize ) ,
127- align : DataTable . CENTER ,
128- } ,
129- {
130- name : VDiskTableColumnsIds . Info as string ,
131- header : vDiskTableColumnsNames [ VDiskTableColumnsIds . Info ] ,
132- width : 70 ,
133- render : ( { row} ) => {
134- return (
135- < Tooltip
136- placement = { [ 'right' ] }
137- content = { < Vdisk { ...row } /> }
138- contentClassName = { b ( 'vdisk-details' ) }
139- >
140- < Button
141- view = "clear"
142- className = { b ( 'vdisk-details-button' , {
143- selected : row . id === selectedVdiskId ,
144- } ) }
145- >
146- < Icon name = "information" viewBox = "0 0 512 512" height = { 16 } width = { 16 } />
147- </ Button >
148- </ Tooltip >
149- ) ;
150- } ,
151- sortable : false ,
152- } ,
153- ] ;
154- return columns ;
155- }
156-
157- function PDisk ( props : PDiskProps ) {
158- const [ unfolded , setUnfolded ] = useState ( props . unfolded ?? false ) ;
159-
160- const data = props . data ?? { } ;
161-
162- const onOpenPDiskDetails = ( ) => {
163- setUnfolded ( true ) ;
164- } ;
165- const onClosePDiskDetails = ( ) => {
166- setUnfolded ( false ) ;
167- } ;
168-
169- const renderVDisks = ( ) => {
170- const { selectedVdiskId, data, nodeHref} = props ;
171- const { vDisks} = data ;
172-
173- return (
174- < DataTable
175- theme = "yandex-cloud"
176- data = { vDisks }
177- columns = { getColumns ( { nodeHref, pDiskId : data . PDiskId , selectedVdiskId} ) }
178- settings = { { ...DEFAULT_TABLE_SETTINGS , dynamicRender : false } as Settings }
179- rowClassName = { ( row ) => {
180- return row . id === selectedVdiskId ? b ( 'selected-vdisk' ) : '' ;
181- } }
182- />
183- ) ;
184- } ;
185-
186- const renderPDiskDetails = ( ) => {
187- if ( _ . isEmpty ( data ) ) {
188- return < div > No information about PDisk</ div > ;
189- }
190- const { nodeHref} = props ;
191- const {
192- TotalSize,
193- AvailableSize,
194- Device,
195- Guid,
196- PDiskId,
197- Path,
198- Realtime,
199- State,
200- Category,
201- SerialNumber,
202- } = data ;
203-
204- let pDiskInternalViewerLink : string | undefined ;
205-
206- if ( nodeHref ) {
207- pDiskInternalViewerLink += nodeHref + '/actors/pdisks/pdisk' + pad9 ( PDiskId ) ;
208- }
209-
210- const pdiskInfo : any = [
211- {
212- label : 'PDisk Id' ,
213- value : (
214- < div className = { b ( 'pdisk-id' ) } >
215- { PDiskId }
216- { pDiskInternalViewerLink && (
217- < Button
218- size = "s"
219- className = { b ( 'external-button' ) }
220- href = { pDiskInternalViewerLink }
221- target = "_blank"
222- view = "clear"
223- >
224- < Icon name = "external" />
225- </ Button >
226- ) }
227- </ div >
228- ) ,
229- } ,
230- ] ;
231- if ( valueIsDefined ( Path ) ) {
232- pdiskInfo . push ( { label : 'Path' , value : Path } ) ;
233- }
234- if ( valueIsDefined ( Guid ) ) {
235- pdiskInfo . push ( { label : 'GUID' , value : Guid } ) ;
236- }
237- if ( valueIsDefined ( Category ) ) {
238- pdiskInfo . push ( { label : 'Category' , value : Category } ) ;
239- }
240- pdiskInfo . push ( {
241- label : 'Allocated Size' ,
242- value : bytesToGB ( TotalSize - AvailableSize ) ,
243- } ) ;
244- pdiskInfo . push ( {
245- label : 'Available Size' ,
246- value : bytesToGB ( AvailableSize ) ,
247- } ) ;
248- if ( Number ( TotalSize ) >= 0 && Number ( AvailableSize ) >= 0 ) {
249- pdiskInfo . push ( {
250- label : 'Size' ,
251- value : (
252- < ProgressViewer
253- value = { TotalSize - AvailableSize }
254- capacity = { TotalSize }
255- formatValues = { formatStorageValuesToGb }
256- colorizeProgress = { true }
257- className = { b ( 'size' ) }
258- />
259- ) ,
260- } ) ;
261- }
262- if ( valueIsDefined ( State ) ) {
263- pdiskInfo . push ( { label : 'State' , value : State } ) ;
264- }
265- if ( valueIsDefined ( Device ) ) {
266- pdiskInfo . push ( {
267- label : 'Device' ,
268- value : < EntityStatus status = { Device } /> ,
269- } ) ;
270- }
271- if ( valueIsDefined ( Realtime ) ) {
272- pdiskInfo . push ( {
273- label : 'Realtime' ,
274- value : < EntityStatus status = { Realtime } /> ,
275- } ) ;
276- }
277- if ( valueIsDefined ( SerialNumber ) ) {
278- pdiskInfo . push ( { label : 'SerialNumber' , value : SerialNumber } ) ;
279- }
280- return (
281- < div >
282- < InfoViewer className = { b ( 'pdisk-details' ) } info = { pdiskInfo } />
283- < div className = { b ( 'vdisks-container' ) } >
284- < div className = { b ( 'vdisks-header' ) } > VDisks</ div >
285- { renderVDisks ( ) }
286- </ div >
287- </ div >
288- ) ;
289- } ;
290-
291- return (
292- < div className = { b ( 'pdisk' ) } id = { props . id } >
293- < div className = { b ( 'pdisk-header' ) } >
294- < div className = { b ( 'pdisk-title-wrapper' ) } >
295- < span > { data . Path } </ span >
296- < EntityStatus status = { data . Device } name = { `${ data . NodeId } -${ data . PDiskId } ` } />
297- </ div >
298- < Button onClick = { unfolded ? onClosePDiskDetails : onOpenPDiskDetails } view = "clear" >
299- < ArrowToggle direction = { unfolded ? 'top' : 'bottom' } />
300- </ Button >
301- </ div >
302- { unfolded && renderPDiskDetails ( ) }
303- </ div >
304- ) ;
305- }
306-
30728interface NodeStructureProps {
30829 nodeId : string ;
30930 className ?: string ;
0 commit comments