ydb-embedded-ui 1.12.2 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
 - package/dist/containers/Storage/Storage.js +28 -5
 - package/dist/containers/Storage/StorageFilter/StorageFilter.tsx +52 -0
 - package/dist/containers/Storage/StorageFilter/index.ts +1 -0
 - package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +2 -1
 - package/dist/containers/Storage/UsageFilter/UsageFilter.scss +31 -0
 - package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +100 -0
 - package/dist/containers/Storage/UsageFilter/i18n/en.json +10 -0
 - package/dist/containers/Storage/UsageFilter/i18n/index.ts +11 -0
 - package/dist/containers/Storage/UsageFilter/i18n/ru.json +10 -0
 - package/dist/containers/Storage/UsageFilter/index.ts +1 -0
 - package/dist/containers/Storage/utils/index.ts +13 -19
 - package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.scss +0 -22
 - package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +8 -45
 - package/dist/containers/Tenant/ObjectGeneralTabs/ObjectGeneralTabs.scss +9 -0
 - package/dist/containers/Tenant/ObjectGeneralTabs/ObjectGeneralTabs.tsx +68 -0
 - package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +1 -1
 - package/dist/containers/Tenant/Tenant.tsx +27 -23
 - package/dist/store/reducers/storage.js +80 -19
 - package/dist/utils/storage.ts +12 -0
 - package/package.json +1 -1
 - package/dist/containers/Storage/StorageFilter/StorageFilter.js +0 -31
 
    
        package/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,5 +1,20 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # Changelog
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            ## [1.13.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.12.2...v1.13.0) (2022-09-01)
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            ### Features
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            * **Storage:** add usage filter component ([a35067f](https://github.com/ydb-platform/ydb-embedded-ui/commit/a35067f8c34ad5d3faf4fb9381c0d6023df9afbd))
         
     | 
| 
      
 9 
     | 
    
         
            +
            * **Storage:** usage filter ([276f027](https://github.com/ydb-platform/ydb-embedded-ui/commit/276f0270a458601929624a4872ec81e001931853))
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            ### Bug Fixes
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            * **Storage:** properly debounce text input filter ([bc5e8fd](https://github.com/ydb-platform/ydb-embedded-ui/commit/bc5e8fd7b067b850f0376b55d995213292b8a31e))
         
     | 
| 
      
 15 
     | 
    
         
            +
            * **Storage:** use current list size for counter ([e6fea58](https://github.com/ydb-platform/ydb-embedded-ui/commit/e6fea58b075de4c35ad8a60d339417c1e7204d83))
         
     | 
| 
      
 16 
     | 
    
         
            +
            * **Tenant:** move general tabs outside navigation ([5bf21ea](https://github.com/ydb-platform/ydb-embedded-ui/commit/5bf21eac6f38c0392c8dc6e04be1b6fd0e147064))
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
       3 
18 
     | 
    
         
             
            ## [1.12.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.12.1...v1.12.2) (2022-08-29)
         
     | 
| 
       4 
19 
     | 
    
         | 
| 
       5 
20 
     | 
    
         | 
| 
         @@ -5,7 +5,8 @@ import cn from 'bem-cn-lite'; 
     | 
|
| 
       5 
5 
     | 
    
         
             
            import DataTable from '@yandex-cloud/react-data-table';
         
     | 
| 
       6 
6 
     | 
    
         
             
            import {RadioButton, Label} from '@yandex-cloud/uikit';
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
            import StorageFilter from './StorageFilter 
     | 
| 
      
 8 
     | 
    
         
            +
            import {StorageFilter} from './StorageFilter';
         
     | 
| 
      
 9 
     | 
    
         
            +
            import {UsageFilter} from './UsageFilter';
         
     | 
| 
       9 
10 
     | 
    
         
             
            import {AutoFetcher} from '../../utils/autofetcher';
         
     | 
| 
       10 
11 
     | 
    
         
             
            import {TableSkeleton} from '../../components/TableSkeleton/TableSkeleton';
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
         @@ -16,12 +17,14 @@ import { 
     | 
|
| 
       16 
17 
     | 
    
         
             
                VisibleEntities,
         
     | 
| 
       17 
18 
     | 
    
         
             
                setVisibleEntities,
         
     | 
| 
       18 
19 
     | 
    
         
             
                setStorageFilter,
         
     | 
| 
      
 20 
     | 
    
         
            +
                setUsageFilter,
         
     | 
| 
       19 
21 
     | 
    
         
             
                getNodesObject,
         
     | 
| 
       20 
22 
     | 
    
         
             
                StorageTypes,
         
     | 
| 
       21 
23 
     | 
    
         
             
                setStorageType,
         
     | 
| 
       22 
24 
     | 
    
         
             
                VisibleEntitiesTitles,
         
     | 
| 
       23 
25 
     | 
    
         
             
                getStoragePoolsGroupsCount,
         
     | 
| 
       24 
26 
     | 
    
         
             
                getStorageNodesCount,
         
     | 
| 
      
 27 
     | 
    
         
            +
                getUsageFilterOptions,
         
     | 
| 
       25 
28 
     | 
    
         
             
            } from '../../store/reducers/storage';
         
     | 
| 
       26 
29 
     | 
    
         
             
            import {getNodesList} from '../../store/reducers/clusterNodes';
         
     | 
| 
       27 
30 
     | 
    
         
             
            import StorageGroups from './StorageGroups/StorageGroups';
         
     | 
| 
         @@ -211,6 +214,7 @@ class Storage extends React.Component { 
     | 
|
| 
       211 
214 
     | 
    
         
             
                        storageType,
         
     | 
| 
       212 
215 
     | 
    
         
             
                        groupsCount,
         
     | 
| 
       213 
216 
     | 
    
         
             
                        nodesCount,
         
     | 
| 
      
 217 
     | 
    
         
            +
                        flatListStorageEntities,
         
     | 
| 
       214 
218 
     | 
    
         
             
                        loading,
         
     | 
| 
       215 
219 
     | 
    
         
             
                        wasLoaded,
         
     | 
| 
       216 
220 
     | 
    
         
             
                    } = this.props;
         
     | 
| 
         @@ -223,10 +227,10 @@ class Storage extends React.Component { 
     | 
|
| 
       223 
227 
     | 
    
         
             
                        return label;
         
     | 
| 
       224 
228 
     | 
    
         
             
                    }
         
     | 
| 
       225 
229 
     | 
    
         | 
| 
       226 
     | 
    
         
            -
                    if (count.total ===  
     | 
| 
      
 230 
     | 
    
         
            +
                    if (count.total === flatListStorageEntities.length) {
         
     | 
| 
       227 
231 
     | 
    
         
             
                        label += count.total;
         
     | 
| 
       228 
232 
     | 
    
         
             
                    } else {
         
     | 
| 
       229 
     | 
    
         
            -
                        label += `${ 
     | 
| 
      
 233 
     | 
    
         
            +
                        label += `${flatListStorageEntities.length} of ${count.total}`;
         
     | 
| 
       230 
234 
     | 
    
         
             
                    }
         
     | 
| 
       231 
235 
     | 
    
         | 
| 
       232 
236 
     | 
    
         
             
                    return label;
         
     | 
| 
         @@ -234,17 +238,22 @@ class Storage extends React.Component { 
     | 
|
| 
       234 
238 
     | 
    
         | 
| 
       235 
239 
     | 
    
         
             
                renderControls() {
         
     | 
| 
       236 
240 
     | 
    
         
             
                    const {
         
     | 
| 
      
 241 
     | 
    
         
            +
                        filter,
         
     | 
| 
       237 
242 
     | 
    
         
             
                        setStorageFilter,
         
     | 
| 
       238 
243 
     | 
    
         
             
                        visibleEntities,
         
     | 
| 
       239 
244 
     | 
    
         
             
                        storageType,
         
     | 
| 
      
 245 
     | 
    
         
            +
                        usageFilter,
         
     | 
| 
      
 246 
     | 
    
         
            +
                        setUsageFilter,
         
     | 
| 
      
 247 
     | 
    
         
            +
                        usageFilterOptions,
         
     | 
| 
       240 
248 
     | 
    
         
             
                    } = this.props;
         
     | 
| 
       241 
249 
     | 
    
         | 
| 
       242 
250 
     | 
    
         
             
                    return (
         
     | 
| 
       243 
251 
     | 
    
         
             
                        <div className={b('controls')}>
         
     | 
| 
       244 
252 
     | 
    
         
             
                            <div className={b('search')}>
         
     | 
| 
       245 
253 
     | 
    
         
             
                                <StorageFilter
         
     | 
| 
       246 
     | 
    
         
            -
                                     
     | 
| 
       247 
     | 
    
         
            -
                                     
     | 
| 
      
 254 
     | 
    
         
            +
                                    placeholder={storageType === StorageTypes.groups ? 'Group ID, Pool name' : 'Node ID, FQDN'}
         
     | 
| 
      
 255 
     | 
    
         
            +
                                    onChange={setStorageFilter}
         
     | 
| 
      
 256 
     | 
    
         
            +
                                    value={filter}
         
     | 
| 
       248 
257 
     | 
    
         
             
                                />
         
     | 
| 
       249 
258 
     | 
    
         
             
                            </div>
         
     | 
| 
       250 
259 
     | 
    
         
             
                            <RadioButton value={visibleEntities} onUpdate={this.onGroupVisibilityChange}>
         
     | 
| 
         @@ -267,6 +276,16 @@ class Storage extends React.Component { 
     | 
|
| 
       267 
276 
     | 
    
         
             
                                    {StorageTypes.nodes}
         
     | 
| 
       268 
277 
     | 
    
         
             
                                </RadioButton.Option>
         
     | 
| 
       269 
278 
     | 
    
         
             
                            </RadioButton>
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
                            {storageType === StorageTypes.groups && (
         
     | 
| 
      
 281 
     | 
    
         
            +
                                <UsageFilter
         
     | 
| 
      
 282 
     | 
    
         
            +
                                    value={usageFilter}
         
     | 
| 
      
 283 
     | 
    
         
            +
                                    onChange={setUsageFilter}
         
     | 
| 
      
 284 
     | 
    
         
            +
                                    groups={usageFilterOptions}
         
     | 
| 
      
 285 
     | 
    
         
            +
                                    disabled={usageFilterOptions.length === 0}
         
     | 
| 
      
 286 
     | 
    
         
            +
                                />
         
     | 
| 
      
 287 
     | 
    
         
            +
                            )}
         
     | 
| 
      
 288 
     | 
    
         
            +
             
     | 
| 
       270 
289 
     | 
    
         
             
                            <Label theme="info" size="m">
         
     | 
| 
       271 
290 
     | 
    
         
             
                                {this.renderEntitiesCount()}
         
     | 
| 
       272 
291 
     | 
    
         
             
                            </Label>
         
     | 
| 
         @@ -302,6 +321,7 @@ function mapStateToProps(state) { 
     | 
|
| 
       302 
321 
     | 
    
         
             
                    visible: visibleEntities,
         
     | 
| 
       303 
322 
     | 
    
         
             
                    type: storageType,
         
     | 
| 
       304 
323 
     | 
    
         
             
                    filter,
         
     | 
| 
      
 324 
     | 
    
         
            +
                    usageFilter,
         
     | 
| 
       305 
325 
     | 
    
         
             
                } = state.storage;
         
     | 
| 
       306 
326 
     | 
    
         | 
| 
       307 
327 
     | 
    
         
             
                return {
         
     | 
| 
         @@ -316,6 +336,8 @@ function mapStateToProps(state) { 
     | 
|
| 
       316 
336 
     | 
    
         
             
                    visibleEntities,
         
     | 
| 
       317 
337 
     | 
    
         
             
                    storageType,
         
     | 
| 
       318 
338 
     | 
    
         
             
                    filter,
         
     | 
| 
      
 339 
     | 
    
         
            +
                    usageFilter,
         
     | 
| 
      
 340 
     | 
    
         
            +
                    usageFilterOptions: getUsageFilterOptions(state),
         
     | 
| 
       319 
341 
     | 
    
         
             
                };
         
     | 
| 
       320 
342 
     | 
    
         
             
            }
         
     | 
| 
       321 
343 
     | 
    
         | 
| 
         @@ -323,6 +345,7 @@ const mapDispatchToProps = { 
     | 
|
| 
       323 
345 
     | 
    
         
             
                getStorageInfo,
         
     | 
| 
       324 
346 
     | 
    
         
             
                setInitialState,
         
     | 
| 
       325 
347 
     | 
    
         
             
                setStorageFilter,
         
     | 
| 
      
 348 
     | 
    
         
            +
                setUsageFilter,
         
     | 
| 
       326 
349 
     | 
    
         
             
                setVisibleEntities: setVisibleEntities,
         
     | 
| 
       327 
350 
     | 
    
         
             
                getNodesList,
         
     | 
| 
       328 
351 
     | 
    
         
             
                setStorageType,
         
     | 
| 
         @@ -0,0 +1,52 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import {useEffect, useRef, useState} from 'react';
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            import {TextInput} from '@yandex-cloud/uikit';
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            interface StorageFilterProps {
         
     | 
| 
      
 6 
     | 
    
         
            +
                className?: string;
         
     | 
| 
      
 7 
     | 
    
         
            +
                value?: string;
         
     | 
| 
      
 8 
     | 
    
         
            +
                placeholder?: string;
         
     | 
| 
      
 9 
     | 
    
         
            +
                onChange?: (value: string) => void;
         
     | 
| 
      
 10 
     | 
    
         
            +
                debounce?: number;
         
     | 
| 
      
 11 
     | 
    
         
            +
            }
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            export const StorageFilter = (props: StorageFilterProps) => {
         
     | 
| 
      
 14 
     | 
    
         
            +
                const {
         
     | 
| 
      
 15 
     | 
    
         
            +
                    className,
         
     | 
| 
      
 16 
     | 
    
         
            +
                    value = '',
         
     | 
| 
      
 17 
     | 
    
         
            +
                    placeholder,
         
     | 
| 
      
 18 
     | 
    
         
            +
                    onChange,
         
     | 
| 
      
 19 
     | 
    
         
            +
                    debounce = 200,
         
     | 
| 
      
 20 
     | 
    
         
            +
                } = props;
         
     | 
| 
      
 21 
     | 
    
         
            +
                const [filterValue, setFilterValue] = useState(value);
         
     | 
| 
      
 22 
     | 
    
         
            +
                const timer = useRef<number>();
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                useEffect(() => {
         
     | 
| 
      
 25 
     | 
    
         
            +
                    setFilterValue((prevValue) => {
         
     | 
| 
      
 26 
     | 
    
         
            +
                        if (prevValue !== value) {
         
     | 
| 
      
 27 
     | 
    
         
            +
                            return value;
         
     | 
| 
      
 28 
     | 
    
         
            +
                        }
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                        return prevValue;
         
     | 
| 
      
 31 
     | 
    
         
            +
                    });
         
     | 
| 
      
 32 
     | 
    
         
            +
                }, [value]);
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                const changeFilter = (newValue: string) => {
         
     | 
| 
      
 35 
     | 
    
         
            +
                    setFilterValue(newValue);
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    window.clearTimeout(timer.current);
         
     | 
| 
      
 38 
     | 
    
         
            +
                    timer.current = window.setTimeout(() => {
         
     | 
| 
      
 39 
     | 
    
         
            +
                        onChange?.(newValue);
         
     | 
| 
      
 40 
     | 
    
         
            +
                    }, debounce);
         
     | 
| 
      
 41 
     | 
    
         
            +
                };
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                return (
         
     | 
| 
      
 44 
     | 
    
         
            +
                    <TextInput
         
     | 
| 
      
 45 
     | 
    
         
            +
                        className={className}
         
     | 
| 
      
 46 
     | 
    
         
            +
                        placeholder={placeholder}
         
     | 
| 
      
 47 
     | 
    
         
            +
                        value={filterValue}
         
     | 
| 
      
 48 
     | 
    
         
            +
                        onUpdate={changeFilter}
         
     | 
| 
      
 49 
     | 
    
         
            +
                        hasClear
         
     | 
| 
      
 50 
     | 
    
         
            +
                    />
         
     | 
| 
      
 51 
     | 
    
         
            +
                );
         
     | 
| 
      
 52 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            export * from './StorageFilter';
         
     | 
| 
         @@ -14,9 +14,10 @@ import {VisibleEntities} from '../../../store/reducers/storage'; 
     | 
|
| 
       14 
14 
     | 
    
         
             
            import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
         
     | 
| 
       15 
15 
     | 
    
         
             
            //@ts-ignore
         
     | 
| 
       16 
16 
     | 
    
         
             
            import {stringifyVdiskId} from '../../../utils';
         
     | 
| 
      
 17 
     | 
    
         
            +
            import {getUsage, isFullDonorData} from '../../../utils/storage';
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
19 
     | 
    
         
             
            import Vdisk from '../Vdisk/Vdisk';
         
     | 
| 
       19 
     | 
    
         
            -
            import { 
     | 
| 
      
 20 
     | 
    
         
            +
            import {getDegradedSeverity, getUsageSeverity} from '../utils';
         
     | 
| 
       20 
21 
     | 
    
         | 
| 
       21 
22 
     | 
    
         
             
            import './StorageGroups.scss';
         
     | 
| 
       22 
23 
     | 
    
         | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            .usage-filter {
         
     | 
| 
      
 2 
     | 
    
         
            +
                &__option {
         
     | 
| 
      
 3 
     | 
    
         
            +
                    flex-grow: 1;
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                    &-title {
         
     | 
| 
      
 6 
     | 
    
         
            +
                        height: var(--yc-text-body-1-line-height);
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                        font-size: var(--yc-text-body-1-font-size);
         
     | 
| 
      
 9 
     | 
    
         
            +
                        line-height: var(--yc-text-body-1-line-height);
         
     | 
| 
      
 10 
     | 
    
         
            +
                    }
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    &-meta {
         
     | 
| 
      
 13 
     | 
    
         
            +
                        padding: 0 5px;
         
     | 
| 
      
 14 
     | 
    
         
            +
                        position: relative;
         
     | 
| 
      
 15 
     | 
    
         
            +
                        border-radius: 3px;
         
     | 
| 
      
 16 
     | 
    
         
            +
                        font-size: var(--yc-text-caption-2-font-size);
         
     | 
| 
      
 17 
     | 
    
         
            +
                        line-height: var(--yc-text-caption-2-line-height);
         
     | 
| 
      
 18 
     | 
    
         
            +
                    }
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    &-bar {
         
     | 
| 
      
 21 
     | 
    
         
            +
                        position: absolute;
         
     | 
| 
      
 22 
     | 
    
         
            +
                        left: 0;
         
     | 
| 
      
 23 
     | 
    
         
            +
                        top: 0;
         
     | 
| 
      
 24 
     | 
    
         
            +
                        bottom: 0;
         
     | 
| 
      
 25 
     | 
    
         
            +
                        z-index: -1;
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                        background-color: var(--yc-color-infographics-info-medium);
         
     | 
| 
      
 28 
     | 
    
         
            +
                        border-radius: 3px;
         
     | 
| 
      
 29 
     | 
    
         
            +
                    }
         
     | 
| 
      
 30 
     | 
    
         
            +
                }
         
     | 
| 
      
 31 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1,100 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import {useEffect, useMemo, useRef, useState} from 'react';
         
     | 
| 
      
 2 
     | 
    
         
            +
            import cn from 'bem-cn-lite';
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            import {Select, SelectOption} from '@yandex-cloud/uikit';
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            import EntityStatus from "../../../components/EntityStatus/EntityStatus";
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            import {getUsageSeverityForEntityStatus} from '../utils';
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            import i18n from './i18n';
         
     | 
| 
      
 11 
     | 
    
         
            +
            import './UsageFilter.scss';
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            interface UsageFilterItem {
         
     | 
| 
      
 14 
     | 
    
         
            +
                threshold: number;
         
     | 
| 
      
 15 
     | 
    
         
            +
                count: number;
         
     | 
| 
      
 16 
     | 
    
         
            +
            }
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            interface UsageFilterProps {
         
     | 
| 
      
 19 
     | 
    
         
            +
                className?: string;
         
     | 
| 
      
 20 
     | 
    
         
            +
                value?: string[];
         
     | 
| 
      
 21 
     | 
    
         
            +
                groups?: UsageFilterItem[];
         
     | 
| 
      
 22 
     | 
    
         
            +
                onChange?: (value: string[]) => void;
         
     | 
| 
      
 23 
     | 
    
         
            +
                debounce?: number;
         
     | 
| 
      
 24 
     | 
    
         
            +
                disabled?: boolean;
         
     | 
| 
      
 25 
     | 
    
         
            +
            }
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            const b = cn('usage-filter');
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            export const UsageFilter = (props: UsageFilterProps) => {
         
     | 
| 
      
 30 
     | 
    
         
            +
                const {
         
     | 
| 
      
 31 
     | 
    
         
            +
                    className,
         
     | 
| 
      
 32 
     | 
    
         
            +
                    value = [],
         
     | 
| 
      
 33 
     | 
    
         
            +
                    groups = [],
         
     | 
| 
      
 34 
     | 
    
         
            +
                    onChange,
         
     | 
| 
      
 35 
     | 
    
         
            +
                    debounce = 200,
         
     | 
| 
      
 36 
     | 
    
         
            +
                    disabled,
         
     | 
| 
      
 37 
     | 
    
         
            +
                } = props;
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                const [filterValue, setFilterValue] = useState(value);
         
     | 
| 
      
 40 
     | 
    
         
            +
                const timer = useRef<number>();
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                useEffect(() => {
         
     | 
| 
      
 43 
     | 
    
         
            +
                    // sync inner state with external value
         
     | 
| 
      
 44 
     | 
    
         
            +
                    setFilterValue((prevValue) => {
         
     | 
| 
      
 45 
     | 
    
         
            +
                        if (prevValue.join(',') !== value.join(',')) {
         
     | 
| 
      
 46 
     | 
    
         
            +
                            return value;
         
     | 
| 
      
 47 
     | 
    
         
            +
                        }
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                        return prevValue;
         
     | 
| 
      
 50 
     | 
    
         
            +
                    });
         
     | 
| 
      
 51 
     | 
    
         
            +
                }, [value]);
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                const options = useMemo(() => groups.map(({threshold, count}) => ({
         
     | 
| 
      
 54 
     | 
    
         
            +
                    value: String(threshold),
         
     | 
| 
      
 55 
     | 
    
         
            +
                    text: `${threshold}%`,
         
     | 
| 
      
 56 
     | 
    
         
            +
                    data: {count}
         
     | 
| 
      
 57 
     | 
    
         
            +
                })), [groups]);
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                const handleUpdate = (newValue: string[]) => {
         
     | 
| 
      
 60 
     | 
    
         
            +
                    setFilterValue(newValue);
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    window.clearTimeout(timer.current);
         
     | 
| 
      
 63 
     | 
    
         
            +
                    timer.current = window.setTimeout(() => {
         
     | 
| 
      
 64 
     | 
    
         
            +
                        onChange?.(newValue);
         
     | 
| 
      
 65 
     | 
    
         
            +
                    }, debounce);
         
     | 
| 
      
 66 
     | 
    
         
            +
                };
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                const maxWidth = Math.max(...groups.map(({count}) => count));
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                const renderOption = ({value, data, text}: SelectOption) => (
         
     | 
| 
      
 71 
     | 
    
         
            +
                    <div className={b('option')}>
         
     | 
| 
      
 72 
     | 
    
         
            +
                        <EntityStatus
         
     | 
| 
      
 73 
     | 
    
         
            +
                            className={b('option-title')}
         
     | 
| 
      
 74 
     | 
    
         
            +
                            status={getUsageSeverityForEntityStatus(Number(value))}
         
     | 
| 
      
 75 
     | 
    
         
            +
                            name={text}
         
     | 
| 
      
 76 
     | 
    
         
            +
                            size="xs"
         
     | 
| 
      
 77 
     | 
    
         
            +
                        />
         
     | 
| 
      
 78 
     | 
    
         
            +
                        <div className={b('option-meta')}>
         
     | 
| 
      
 79 
     | 
    
         
            +
                            {i18n('groups_count', {count: data.count})}
         
     | 
| 
      
 80 
     | 
    
         
            +
                            <div className={b('option-bar')} style={{width: `${data.count / maxWidth * 100}%`}} />
         
     | 
| 
      
 81 
     | 
    
         
            +
                        </div>
         
     | 
| 
      
 82 
     | 
    
         
            +
                    </div>
         
     | 
| 
      
 83 
     | 
    
         
            +
                );
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                return (
         
     | 
| 
      
 86 
     | 
    
         
            +
                    <Select
         
     | 
| 
      
 87 
     | 
    
         
            +
                        className={b(null, className)}
         
     | 
| 
      
 88 
     | 
    
         
            +
                        label={i18n('label')}
         
     | 
| 
      
 89 
     | 
    
         
            +
                        value={filterValue}
         
     | 
| 
      
 90 
     | 
    
         
            +
                        placeholder={i18n('default_value')}
         
     | 
| 
      
 91 
     | 
    
         
            +
                        options={options}
         
     | 
| 
      
 92 
     | 
    
         
            +
                        multiple
         
     | 
| 
      
 93 
     | 
    
         
            +
                        onUpdate={handleUpdate}
         
     | 
| 
      
 94 
     | 
    
         
            +
                        renderOption={renderOption}
         
     | 
| 
      
 95 
     | 
    
         
            +
                        getOptionHeight={() => 50}
         
     | 
| 
      
 96 
     | 
    
         
            +
                        popupWidth={280}
         
     | 
| 
      
 97 
     | 
    
         
            +
                        disabled={disabled}
         
     | 
| 
      
 98 
     | 
    
         
            +
                    />
         
     | 
| 
      
 99 
     | 
    
         
            +
                );
         
     | 
| 
      
 100 
     | 
    
         
            +
            };
         
     | 
| 
         @@ -0,0 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import {i18n, Lang} from '../../../../utils/i18n';
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            import en from './en.json';
         
     | 
| 
      
 4 
     | 
    
         
            +
            import ru from './ru.json';
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            const COMPONENT = 'ydb-usage-filter';
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            i18n.registerKeyset(Lang.En, COMPONENT, en);
         
     | 
| 
      
 9 
     | 
    
         
            +
            i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            export default i18n.keyset(COMPONENT);
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            export * from './UsageFilter';
         
     | 
| 
         @@ -1,33 +1,33 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            import type {TVDiskStateInfo, TVSlotId} from '../../../types/api/storage';
         
     | 
| 
       2 
1 
     | 
    
         
             
            import type {IStoragePoolGroup} from '../../../types/store/storage';
         
     | 
| 
       3 
2 
     | 
    
         | 
| 
       4 
3 
     | 
    
         
             
            export * from './constants';
         
     | 
| 
       5 
4 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
                 
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
            const generateEvaluator = <
         
     | 
| 
      
 6 
     | 
    
         
            +
                OkLevel extends string,
         
     | 
| 
      
 7 
     | 
    
         
            +
                WarnLevel extends string,
         
     | 
| 
      
 8 
     | 
    
         
            +
                CritLevel extends string
         
     | 
| 
      
 9 
     | 
    
         
            +
            >(warn: number, crit: number, levels: [OkLevel, WarnLevel, CritLevel]) =>
         
     | 
| 
       10 
10 
     | 
    
         
             
                (value: number) => {
         
     | 
| 
       11 
11 
     | 
    
         
             
                    if (0 <= value && value < warn) {
         
     | 
| 
       12 
     | 
    
         
            -
                        return  
     | 
| 
      
 12 
     | 
    
         
            +
                        return levels[0];
         
     | 
| 
       13 
13 
     | 
    
         
             
                    }
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
                    if (warn <= value && value < crit) {
         
     | 
| 
       16 
     | 
    
         
            -
                        return  
     | 
| 
      
 16 
     | 
    
         
            +
                        return levels[1];
         
     | 
| 
       17 
17 
     | 
    
         
             
                    }
         
     | 
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
                    if (crit <= value) {
         
     | 
| 
       20 
     | 
    
         
            -
                        return  
     | 
| 
      
 20 
     | 
    
         
            +
                        return levels[2];
         
     | 
| 
       21 
21 
     | 
    
         
             
                    }
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                    return undefined;
         
     | 
| 
       24 
24 
     | 
    
         
             
                };
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
            const defaultDegradationEvaluator = generateEvaluator(1, 2);
         
     | 
| 
      
 26 
     | 
    
         
            +
            const defaultDegradationEvaluator = generateEvaluator(1, 2, ['success', 'warning', 'danger']);
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
            const degradationEvaluators = {
         
     | 
| 
       29 
     | 
    
         
            -
                'block-4-2': generateEvaluator(1, 2),
         
     | 
| 
       30 
     | 
    
         
            -
                'mirror-3-dc': generateEvaluator(1, 3),
         
     | 
| 
      
 29 
     | 
    
         
            +
                'block-4-2': generateEvaluator(1, 2, ['success', 'warning', 'danger']),
         
     | 
| 
      
 30 
     | 
    
         
            +
                'mirror-3-dc': generateEvaluator(1, 3, ['success', 'warning', 'danger']),
         
     | 
| 
       31 
31 
     | 
    
         
             
            };
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         
             
            const canEvaluateErasureSpecies = (value?: string): value is keyof typeof degradationEvaluators =>
         
     | 
| 
         @@ -41,11 +41,5 @@ export const getDegradedSeverity = (group: IStoragePoolGroup) => { 
     | 
|
| 
       41 
41 
     | 
    
         
             
                return evaluate(group.Missing);
         
     | 
| 
       42 
42 
     | 
    
         
             
            };
         
     | 
| 
       43 
43 
     | 
    
         | 
| 
       44 
     | 
    
         
            -
            export const getUsageSeverity = generateEvaluator(80, 85);
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
            export const getUsage = (data: IStoragePoolGroup, step = 1) => {
         
     | 
| 
       47 
     | 
    
         
            -
                // if limit is 0, display 0
         
     | 
| 
       48 
     | 
    
         
            -
                const usage = Math.round((data.Used * 100) / data.Limit) || 0;
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
                return Math.floor(usage / step) * step;
         
     | 
| 
       51 
     | 
    
         
            -
            };
         
     | 
| 
      
 44 
     | 
    
         
            +
            export const getUsageSeverity = generateEvaluator(80, 85, ['success', 'warning', 'danger']);
         
     | 
| 
      
 45 
     | 
    
         
            +
            export const getUsageSeverityForEntityStatus = generateEvaluator(80, 85, ['Green', 'Yellow', 'Red']);
         
     | 
| 
         @@ -9,28 +9,6 @@ 
     | 
|
| 
       9 
9 
     | 
    
         
             
                height: 100%;
         
     | 
| 
       10 
10 
     | 
    
         
             
                max-height: 100%;
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
                &__tabs {
         
     | 
| 
       13 
     | 
    
         
            -
                    display: flex;
         
     | 
| 
       14 
     | 
    
         
            -
                    gap: 20px;
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
                    padding: 13px 20px 0;
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                    box-shadow: inset 0 -1px 0 0 var(--yc-color-line-generic);
         
     | 
| 
       19 
     | 
    
         
            -
                    .yc-tabs {
         
     | 
| 
       20 
     | 
    
         
            -
                        box-shadow: unset;
         
     | 
| 
       21 
     | 
    
         
            -
                    }
         
     | 
| 
       22 
     | 
    
         
            -
                }
         
     | 
| 
       23 
     | 
    
         
            -
                &__tab {
         
     | 
| 
       24 
     | 
    
         
            -
                    text-decoration: none;
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                    // fix for bug in uikit, gap is set for yc-tabs__item:not(:last-child),
         
     | 
| 
       27 
     | 
    
         
            -
                    // it doesn't work for wrapped items
         
     | 
| 
       28 
     | 
    
         
            -
                    // feel free to remove if the bug is fixed
         
     | 
| 
       29 
     | 
    
         
            -
                    &:not(:last-child) {
         
     | 
| 
       30 
     | 
    
         
            -
                        margin-right: var(--yc-tabs-gap);
         
     | 
| 
       31 
     | 
    
         
            -
                    }
         
     | 
| 
       32 
     | 
    
         
            -
                }
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
12 
     | 
    
         
             
                &__loader {
         
     | 
| 
       35 
13 
     | 
    
         
             
                    display: flex;
         
     | 
| 
       36 
14 
     | 
    
         
             
                }
         
     | 
| 
         @@ -1,20 +1,15 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            import {connect} from 'react-redux';
         
     | 
| 
       2 
     | 
    
         
            -
            import {Link} from 'react-router-dom';
         
     | 
| 
       3 
     | 
    
         
            -
            import cn from 'bem-cn-lite';
         
     | 
| 
       4 
     | 
    
         
            -
            import {useLocation} from 'react-router';
         
     | 
| 
       5 
1 
     | 
    
         
             
            import qs from 'qs';
         
     | 
| 
       6 
     | 
    
         
            -
            import  
     | 
| 
      
 2 
     | 
    
         
            +
            import {useLocation} from 'react-router';
         
     | 
| 
      
 3 
     | 
    
         
            +
            import cn from 'bem-cn-lite';
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            import {useThemeValue} from '@yandex-cloud/uikit';
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            import type {EPathType} from '../../../types/api/schema';
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
            import {Tabs, useThemeValue} from '@yandex-cloud/uikit';
         
     | 
| 
       9 
     | 
    
         
            -
            //@ts-ignore
         
     | 
| 
       10 
9 
     | 
    
         
             
            import QueryEditor from '../QueryEditor/QueryEditor';
         
     | 
| 
       11 
10 
     | 
    
         
             
            import Diagnostics from '../Diagnostics/Diagnostics';
         
     | 
| 
       12 
11 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
            import {TenantGeneralTabsIds 
     | 
| 
       14 
     | 
    
         
            -
            import routes, {createHref} from '../../../routes';
         
     | 
| 
       15 
     | 
    
         
            -
            import {setSettingValue} from '../../../store/reducers/settings';
         
     | 
| 
       16 
     | 
    
         
            -
            import {TENANT_INITIAL_TAB_KEY} from '../../../utils/constants';
         
     | 
| 
       17 
     | 
    
         
            -
            import type {EPathType} from '../../../types/api/schema';
         
     | 
| 
      
 12 
     | 
    
         
            +
            import {TenantGeneralTabsIds} from '../TenantPages';
         
     | 
| 
       18 
13 
     | 
    
         | 
| 
       19 
14 
     | 
    
         
             
            import './ObjectGeneral.scss';
         
     | 
| 
       20 
15 
     | 
    
         | 
| 
         @@ -24,7 +19,6 @@ interface ObjectGeneralProps { 
     | 
|
| 
       24 
19 
     | 
    
         
             
                type?: EPathType;
         
     | 
| 
       25 
20 
     | 
    
         
             
                additionalTenantInfo?: any;
         
     | 
| 
       26 
21 
     | 
    
         
             
                additionalNodesInfo?: any;
         
     | 
| 
       27 
     | 
    
         
            -
                setSettingValue: (name: string, value: string) => void;
         
     | 
| 
       28 
22 
     | 
    
         
             
            }
         
     | 
| 
       29 
23 
     | 
    
         | 
| 
       30 
24 
     | 
    
         
             
            function ObjectGeneral(props: ObjectGeneralProps) {
         
     | 
| 
         @@ -38,32 +32,6 @@ function ObjectGeneral(props: ObjectGeneralProps) { 
     | 
|
| 
       38 
32 
     | 
    
         | 
| 
       39 
33 
     | 
    
         
             
                const {name: tenantName, general: generalTab} = queryParams;
         
     | 
| 
       40 
34 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
                const renderTabs = () => {
         
     | 
| 
       42 
     | 
    
         
            -
                    return (
         
     | 
| 
       43 
     | 
    
         
            -
                        <div className={b('tabs')}>
         
     | 
| 
       44 
     | 
    
         
            -
                            <Tabs
         
     | 
| 
       45 
     | 
    
         
            -
                                size="xl"
         
     | 
| 
       46 
     | 
    
         
            -
                                items={TENANT_GENERAL_TABS}
         
     | 
| 
       47 
     | 
    
         
            -
                                activeTab={generalTab as string}
         
     | 
| 
       48 
     | 
    
         
            -
                                wrapTo={({id}, node) => {
         
     | 
| 
       49 
     | 
    
         
            -
                                    const path = createHref(routes.tenant, undefined, {
         
     | 
| 
       50 
     | 
    
         
            -
                                        ...queryParams,
         
     | 
| 
       51 
     | 
    
         
            -
                                        name: tenantName as string,
         
     | 
| 
       52 
     | 
    
         
            -
                                        [TenantTabsGroups.general]: id,
         
     | 
| 
       53 
     | 
    
         
            -
                                    });
         
     | 
| 
       54 
     | 
    
         
            -
                                    return (
         
     | 
| 
       55 
     | 
    
         
            -
                                        <Link to={path} key={id} className={b('tab')}>
         
     | 
| 
       56 
     | 
    
         
            -
                                            {node}
         
     | 
| 
       57 
     | 
    
         
            -
                                        </Link>
         
     | 
| 
       58 
     | 
    
         
            -
                                    );
         
     | 
| 
       59 
     | 
    
         
            -
                                }}
         
     | 
| 
       60 
     | 
    
         
            -
                                allowNotSelected
         
     | 
| 
       61 
     | 
    
         
            -
                                onSelectTab={(id) => props.setSettingValue(TENANT_INITIAL_TAB_KEY, id)}
         
     | 
| 
       62 
     | 
    
         
            -
                            />
         
     | 
| 
       63 
     | 
    
         
            -
                        </div>
         
     | 
| 
       64 
     | 
    
         
            -
                    );
         
     | 
| 
       65 
     | 
    
         
            -
                };
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
35 
     | 
    
         
             
                const renderTabContent = () => {
         
     | 
| 
       68 
36 
     | 
    
         
             
                    const {type, additionalTenantInfo, additionalNodesInfo} = props;
         
     | 
| 
       69 
37 
     | 
    
         
             
                    switch (generalTab) {
         
     | 
| 
         @@ -88,7 +56,6 @@ function ObjectGeneral(props: ObjectGeneralProps) { 
     | 
|
| 
       88 
56 
     | 
    
         
             
                    }
         
     | 
| 
       89 
57 
     | 
    
         
             
                    return (
         
     | 
| 
       90 
58 
     | 
    
         
             
                        <div className={b()}>
         
     | 
| 
       91 
     | 
    
         
            -
                            {renderTabs()}
         
     | 
| 
       92 
59 
     | 
    
         
             
                            {renderTabContent()}
         
     | 
| 
       93 
60 
     | 
    
         
             
                        </div>
         
     | 
| 
       94 
61 
     | 
    
         
             
                    );
         
     | 
| 
         @@ -97,8 +64,4 @@ function ObjectGeneral(props: ObjectGeneralProps) { 
     | 
|
| 
       97 
64 
     | 
    
         
             
                return renderContent();
         
     | 
| 
       98 
65 
     | 
    
         
             
            }
         
     | 
| 
       99 
66 
     | 
    
         | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
                setSettingValue,
         
     | 
| 
       102 
     | 
    
         
            -
            };
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
            export default connect(null, mapDispatchToProps)(ObjectGeneral);
         
     | 
| 
      
 67 
     | 
    
         
            +
            export default ObjectGeneral;
         
     | 
| 
         @@ -0,0 +1,68 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import qs from 'qs';
         
     | 
| 
      
 2 
     | 
    
         
            +
            import {connect} from 'react-redux';
         
     | 
| 
      
 3 
     | 
    
         
            +
            import {useLocation} from 'react-router';
         
     | 
| 
      
 4 
     | 
    
         
            +
            import {Link} from 'react-router-dom';
         
     | 
| 
      
 5 
     | 
    
         
            +
            import cn from 'bem-cn-lite';
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            import {Tabs} from '@yandex-cloud/uikit';
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            import routes, {createHref} from '../../../routes';
         
     | 
| 
      
 10 
     | 
    
         
            +
            import {TENANT_INITIAL_TAB_KEY} from '../../../utils/constants';
         
     | 
| 
      
 11 
     | 
    
         
            +
            import {setSettingValue} from '../../../store/reducers/settings';
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            import {TenantTabsGroups, TENANT_GENERAL_TABS} from '../TenantPages';
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            import './ObjectGeneralTabs.scss';
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            const b = cn('object-general-tabs');
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            interface ObjectGeneralTabsProps {
         
     | 
| 
      
 20 
     | 
    
         
            +
                setSettingValue: (name: string, value: string) => void;
         
     | 
| 
      
 21 
     | 
    
         
            +
            }
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            function ObjectGeneralTabs(props: ObjectGeneralTabsProps) {
         
     | 
| 
      
 24 
     | 
    
         
            +
                const location = useLocation();
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                const queryParams = qs.parse(location.search, {
         
     | 
| 
      
 27 
     | 
    
         
            +
                    ignoreQueryPrefix: true,
         
     | 
| 
      
 28 
     | 
    
         
            +
                });
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                const {name: tenantName, general: generalTab} = queryParams;
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                const renderContent = () => {
         
     | 
| 
      
 33 
     | 
    
         
            +
                    if (!tenantName) {
         
     | 
| 
      
 34 
     | 
    
         
            +
                        return null;
         
     | 
| 
      
 35 
     | 
    
         
            +
                    }
         
     | 
| 
      
 36 
     | 
    
         
            +
                    return (
         
     | 
| 
      
 37 
     | 
    
         
            +
                        <div className={b()}>
         
     | 
| 
      
 38 
     | 
    
         
            +
                            <Tabs
         
     | 
| 
      
 39 
     | 
    
         
            +
                                size="xl"
         
     | 
| 
      
 40 
     | 
    
         
            +
                                items={TENANT_GENERAL_TABS}
         
     | 
| 
      
 41 
     | 
    
         
            +
                                activeTab={generalTab as string}
         
     | 
| 
      
 42 
     | 
    
         
            +
                                wrapTo={({id}, node) => {
         
     | 
| 
      
 43 
     | 
    
         
            +
                                    const path = createHref(routes.tenant, undefined, {
         
     | 
| 
      
 44 
     | 
    
         
            +
                                        ...queryParams,
         
     | 
| 
      
 45 
     | 
    
         
            +
                                        name: tenantName as string,
         
     | 
| 
      
 46 
     | 
    
         
            +
                                        [TenantTabsGroups.general]: id,
         
     | 
| 
      
 47 
     | 
    
         
            +
                                    });
         
     | 
| 
      
 48 
     | 
    
         
            +
                                    return (
         
     | 
| 
      
 49 
     | 
    
         
            +
                                        <Link to={path} key={id} className={b('tab')}>
         
     | 
| 
      
 50 
     | 
    
         
            +
                                            {node}
         
     | 
| 
      
 51 
     | 
    
         
            +
                                        </Link>
         
     | 
| 
      
 52 
     | 
    
         
            +
                                    );
         
     | 
| 
      
 53 
     | 
    
         
            +
                                }}
         
     | 
| 
      
 54 
     | 
    
         
            +
                                allowNotSelected
         
     | 
| 
      
 55 
     | 
    
         
            +
                                onSelectTab={(id) => props.setSettingValue(TENANT_INITIAL_TAB_KEY, id)}
         
     | 
| 
      
 56 
     | 
    
         
            +
                            />
         
     | 
| 
      
 57 
     | 
    
         
            +
                        </div>
         
     | 
| 
      
 58 
     | 
    
         
            +
                    );
         
     | 
| 
      
 59 
     | 
    
         
            +
                };
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                return renderContent();
         
     | 
| 
      
 62 
     | 
    
         
            +
            }
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            const mapDispatchToProps = {
         
     | 
| 
      
 65 
     | 
    
         
            +
                setSettingValue,
         
     | 
| 
      
 66 
     | 
    
         
            +
            };
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            export default connect(null, mapDispatchToProps)(ObjectGeneralTabs);
         
     | 
| 
         @@ -7,8 +7,9 @@ import qs from 'qs'; 
     | 
|
| 
       7 
7 
     | 
    
         
             
            import EmptyState from '../../components/EmptyState/EmptyState';
         
     | 
| 
       8 
8 
     | 
    
         
             
            import {Illustration} from '../../components/Illustration';
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
            import ObjectSummary from './ObjectSummary/ObjectSummary';
         
     | 
| 
       11 
10 
     | 
    
         
             
            import {setHeader} from '../../store/reducers/header';
         
     | 
| 
      
 11 
     | 
    
         
            +
            import ObjectGeneralTabs from './ObjectGeneralTabs/ObjectGeneralTabs';
         
     | 
| 
      
 12 
     | 
    
         
            +
            import ObjectSummary from './ObjectSummary/ObjectSummary';
         
     | 
| 
       12 
13 
     | 
    
         
             
            import ObjectGeneral from './ObjectGeneral/ObjectGeneral';
         
     | 
| 
       13 
14 
     | 
    
         
             
            //@ts-ignore
         
     | 
| 
       14 
15 
     | 
    
         
             
            import SplitPane from '../../components/SplitPane';
         
     | 
| 
         @@ -131,28 +132,31 @@ function Tenant(props: TenantProps) { 
     | 
|
| 
       131 
132 
     | 
    
         
             
                                description="You don’t have the necessary roles to view this page."
         
     | 
| 
       132 
133 
     | 
    
         
             
                            />
         
     | 
| 
       133 
134 
     | 
    
         
             
                        ) : (
         
     | 
| 
       134 
     | 
    
         
            -
                             
     | 
| 
       135 
     | 
    
         
            -
                                 
     | 
| 
       136 
     | 
    
         
            -
                                 
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
                                     
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
             
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
             
     | 
| 
       151 
     | 
    
         
            -
                                     
     | 
| 
       152 
     | 
    
         
            -
                                     
     | 
| 
       153 
     | 
    
         
            -
             
     | 
| 
       154 
     | 
    
         
            -
             
     | 
| 
       155 
     | 
    
         
            -
             
     | 
| 
      
 135 
     | 
    
         
            +
                            <>
         
     | 
| 
      
 136 
     | 
    
         
            +
                                <ObjectGeneralTabs />
         
     | 
| 
      
 137 
     | 
    
         
            +
                                <SplitPane
         
     | 
| 
      
 138 
     | 
    
         
            +
                                    defaultSizePaneKey={DEFAULT_SIZE_TENANT_KEY}
         
     | 
| 
      
 139 
     | 
    
         
            +
                                    defaultSizes={[25, 75]}
         
     | 
| 
      
 140 
     | 
    
         
            +
                                    triggerCollapse={summaryVisibilityState.triggerCollapse}
         
     | 
| 
      
 141 
     | 
    
         
            +
                                    triggerExpand={summaryVisibilityState.triggerExpand}
         
     | 
| 
      
 142 
     | 
    
         
            +
                                    minSize={[36, 200]}
         
     | 
| 
      
 143 
     | 
    
         
            +
                                    onSplitStartDragAdditional={onSplitStartDragAdditional}
         
     | 
| 
      
 144 
     | 
    
         
            +
                                >
         
     | 
| 
      
 145 
     | 
    
         
            +
                                    <ObjectSummary
         
     | 
| 
      
 146 
     | 
    
         
            +
                                        type={currentPathType}
         
     | 
| 
      
 147 
     | 
    
         
            +
                                        subType={currentPathSubType}
         
     | 
| 
      
 148 
     | 
    
         
            +
                                        onCollapseSummary={onCollapseSummaryHandler}
         
     | 
| 
      
 149 
     | 
    
         
            +
                                        onExpandSummary={onExpandSummaryHandler}
         
     | 
| 
      
 150 
     | 
    
         
            +
                                        isCollapsed={summaryVisibilityState.collapsed}
         
     | 
| 
      
 151 
     | 
    
         
            +
                                        additionalTenantInfo={props.additionalTenantInfo}
         
     | 
| 
      
 152 
     | 
    
         
            +
                                    />
         
     | 
| 
      
 153 
     | 
    
         
            +
                                    <ObjectGeneral
         
     | 
| 
      
 154 
     | 
    
         
            +
                                        type={currentPathType}
         
     | 
| 
      
 155 
     | 
    
         
            +
                                        additionalTenantInfo={props.additionalTenantInfo}
         
     | 
| 
      
 156 
     | 
    
         
            +
                                        additionalNodesInfo={props.additionalNodesInfo}
         
     | 
| 
      
 157 
     | 
    
         
            +
                                    />
         
     | 
| 
      
 158 
     | 
    
         
            +
                                </SplitPane>
         
     | 
| 
      
 159 
     | 
    
         
            +
                            </>
         
     | 
| 
       156 
160 
     | 
    
         
             
                        )}
         
     | 
| 
       157 
161 
     | 
    
         
             
                    </div>
         
     | 
| 
       158 
162 
     | 
    
         
             
                );
         
     | 
| 
         @@ -3,6 +3,7 @@ import '../../services/api'; 
     | 
|
| 
       3 
3 
     | 
    
         
             
            import _ from 'lodash';
         
     | 
| 
       4 
4 
     | 
    
         
             
            import {createSelector} from 'reselect';
         
     | 
| 
       5 
5 
     | 
    
         
             
            import {calcUptime} from '../../utils';
         
     | 
| 
      
 6 
     | 
    
         
            +
            import {getUsage} from '../../utils/storage';
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
8 
     | 
    
         
             
            export const VisibleEntities = {
         
     | 
| 
       8 
9 
     | 
    
         
             
                All: 'All',
         
     | 
| 
         @@ -24,6 +25,7 @@ export const StorageTypes = { 
     | 
|
| 
       24 
25 
     | 
    
         
             
            const FETCH_STORAGE = createRequestActionTypes('storage', 'FETCH_STORAGE');
         
     | 
| 
       25 
26 
     | 
    
         
             
            const SET_INITIAL = 'storage/SET_INITIAL';
         
     | 
| 
       26 
27 
     | 
    
         
             
            const SET_FILTER = 'storage/SET_FILTER';
         
     | 
| 
      
 28 
     | 
    
         
            +
            const SET_USAGE_FILTER = 'storage/SET_USAGE_FILTER';
         
     | 
| 
       27 
29 
     | 
    
         
             
            const SET_VISIBLE_GROUPS = 'storage/SET_VISIBLE_GROUPS';
         
     | 
| 
       28 
30 
     | 
    
         
             
            const SET_STORAGE_TYPE = 'storage/SET_STORAGE_TYPE';
         
     | 
| 
       29 
31 
     | 
    
         | 
| 
         @@ -31,6 +33,7 @@ const initialState = { 
     | 
|
| 
       31 
33 
     | 
    
         
             
                loading: true,
         
     | 
| 
       32 
34 
     | 
    
         
             
                wasLoaded: false,
         
     | 
| 
       33 
35 
     | 
    
         
             
                filter: '',
         
     | 
| 
      
 36 
     | 
    
         
            +
                usageFilter: [],
         
     | 
| 
       34 
37 
     | 
    
         
             
                visible: VisibleEntities.Missing,
         
     | 
| 
       35 
38 
     | 
    
         
             
                type: StorageTypes.groups,
         
     | 
| 
       36 
39 
     | 
    
         
             
            };
         
     | 
| 
         @@ -70,6 +73,12 @@ const storage = function z(state = initialState, action) { 
     | 
|
| 
       70 
73 
     | 
    
         
             
                            filter: action.data,
         
     | 
| 
       71 
74 
     | 
    
         
             
                        };
         
     | 
| 
       72 
75 
     | 
    
         
             
                    }
         
     | 
| 
      
 76 
     | 
    
         
            +
                    case SET_USAGE_FILTER: {
         
     | 
| 
      
 77 
     | 
    
         
            +
                        return {
         
     | 
| 
      
 78 
     | 
    
         
            +
                            ...state,
         
     | 
| 
      
 79 
     | 
    
         
            +
                            usageFilter: action.data,
         
     | 
| 
      
 80 
     | 
    
         
            +
                        };
         
     | 
| 
      
 81 
     | 
    
         
            +
                    }
         
     | 
| 
       73 
82 
     | 
    
         
             
                    case SET_VISIBLE_GROUPS: {
         
     | 
| 
       74 
83 
     | 
    
         
             
                        return {
         
     | 
| 
       75 
84 
     | 
    
         
             
                            ...state,
         
     | 
| 
         @@ -82,6 +91,8 @@ const storage = function z(state = initialState, action) { 
     | 
|
| 
       82 
91 
     | 
    
         
             
                        return {
         
     | 
| 
       83 
92 
     | 
    
         
             
                            ...state,
         
     | 
| 
       84 
93 
     | 
    
         
             
                            type: action.data,
         
     | 
| 
      
 94 
     | 
    
         
            +
                            filter: '',
         
     | 
| 
      
 95 
     | 
    
         
            +
                            usageFilter: [],
         
     | 
| 
       85 
96 
     | 
    
         
             
                            wasLoaded: false,
         
     | 
| 
       86 
97 
     | 
    
         
             
                            error: undefined,
         
     | 
| 
       87 
98 
     | 
    
         
             
                        };
         
     | 
| 
         @@ -117,6 +128,14 @@ export function setStorageFilter(value) { 
     | 
|
| 
       117 
128 
     | 
    
         
             
                    data: value,
         
     | 
| 
       118 
129 
     | 
    
         
             
                };
         
     | 
| 
       119 
130 
     | 
    
         
             
            }
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
            export function setUsageFilter(value) {
         
     | 
| 
      
 133 
     | 
    
         
            +
                return {
         
     | 
| 
      
 134 
     | 
    
         
            +
                    type: SET_USAGE_FILTER,
         
     | 
| 
      
 135 
     | 
    
         
            +
                    data: value,
         
     | 
| 
      
 136 
     | 
    
         
            +
                };
         
     | 
| 
      
 137 
     | 
    
         
            +
            }
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
       120 
139 
     | 
    
         
             
            export function setVisibleEntities(value) {
         
     | 
| 
       121 
140 
     | 
    
         
             
                return {
         
     | 
| 
       122 
141 
     | 
    
         
             
                    type: SET_VISIBLE_GROUPS,
         
     | 
| 
         @@ -135,6 +154,7 @@ export const getStorageNodesCount = (state) => ({ 
     | 
|
| 
       135 
154 
     | 
    
         
             
                found: state.storage.data?.FoundNodes || 0,
         
     | 
| 
       136 
155 
     | 
    
         
             
            });
         
     | 
| 
       137 
156 
     | 
    
         
             
            export const getStorageFilter = (state) => state.storage.filter;
         
     | 
| 
      
 157 
     | 
    
         
            +
            export const getUsageFilter = (state) => state.storage.usageFilter;
         
     | 
| 
       138 
158 
     | 
    
         
             
            export const getVisibleEntities = (state) => state.storage.visible;
         
     | 
| 
       139 
159 
     | 
    
         
             
            export const getStorageType = (state) => state.storage.type;
         
     | 
| 
       140 
160 
     | 
    
         
             
            export const getNodesObject = (state) =>
         
     | 
| 
         @@ -271,26 +291,67 @@ export const getVisibleEntitiesList = createSelector( 
     | 
|
| 
       271 
291 
     | 
    
         
             
                },
         
     | 
| 
       272 
292 
     | 
    
         
             
            );
         
     | 
| 
       273 
293 
     | 
    
         | 
| 
       274 
     | 
    
         
            -
             
     | 
| 
       275 
     | 
    
         
            -
                 
     | 
| 
       276 
     | 
    
         
            -
             
     | 
| 
       277 
     | 
    
         
            -
             
     | 
| 
       278 
     | 
    
         
            -
                     
     | 
| 
       279 
     | 
    
         
            -
             
     | 
| 
       280 
     | 
    
         
            -
             
     | 
| 
       281 
     | 
    
         
            -
             
     | 
| 
       282 
     | 
    
         
            -
             
     | 
| 
       283 
     | 
    
         
            -
             
     | 
| 
       284 
     | 
    
         
            -
             
     | 
| 
       285 
     | 
    
         
            -
             
     | 
| 
       286 
     | 
    
         
            -
             
     | 
| 
       287 
     | 
    
         
            -
                            }
         
     | 
| 
       288 
     | 
    
         
            -
                            return (
         
     | 
| 
       289 
     | 
    
         
            -
                                e.NodeId.toString().includes(cleanedFilter) ||
         
     | 
| 
       290 
     | 
    
         
            -
                                e.FQDN.toLowerCase().includes(cleanedFilter)
         
     | 
| 
       291 
     | 
    
         
            -
                            );
         
     | 
| 
       292 
     | 
    
         
            -
                        });
         
     | 
| 
      
 294 
     | 
    
         
            +
            const filterByText = (entities, type, text) => {
         
     | 
| 
      
 295 
     | 
    
         
            +
                const cleanedFilter = text.trim().toLowerCase();
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
                if (!cleanedFilter) {
         
     | 
| 
      
 298 
     | 
    
         
            +
                    return entities;
         
     | 
| 
      
 299 
     | 
    
         
            +
                }
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
      
 301 
     | 
    
         
            +
                return entities.filter((entity) => {
         
     | 
| 
      
 302 
     | 
    
         
            +
                    if (type === StorageTypes.groups) {
         
     | 
| 
      
 303 
     | 
    
         
            +
                        return (
         
     | 
| 
      
 304 
     | 
    
         
            +
                            entity.PoolName.toLowerCase().includes(cleanedFilter) ||
         
     | 
| 
      
 305 
     | 
    
         
            +
                            entity.GroupID?.toString().includes(cleanedFilter)
         
     | 
| 
      
 306 
     | 
    
         
            +
                        );
         
     | 
| 
       293 
307 
     | 
    
         
             
                    }
         
     | 
| 
      
 308 
     | 
    
         
            +
             
     | 
| 
      
 309 
     | 
    
         
            +
                    return (
         
     | 
| 
      
 310 
     | 
    
         
            +
                        entity.NodeId.toString().includes(cleanedFilter) ||
         
     | 
| 
      
 311 
     | 
    
         
            +
                        entity.FQDN.toLowerCase().includes(cleanedFilter)
         
     | 
| 
      
 312 
     | 
    
         
            +
                    );
         
     | 
| 
      
 313 
     | 
    
         
            +
                });
         
     | 
| 
      
 314 
     | 
    
         
            +
            };
         
     | 
| 
      
 315 
     | 
    
         
            +
             
     | 
| 
      
 316 
     | 
    
         
            +
            const filterByUsage = (entities, usage) => {
         
     | 
| 
      
 317 
     | 
    
         
            +
                if (!Array.isArray(usage) || usage.length === 0) {
         
     | 
| 
      
 318 
     | 
    
         
            +
                    return entities;
         
     | 
| 
      
 319 
     | 
    
         
            +
                }
         
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
      
 321 
     | 
    
         
            +
                return entities.filter((entity) => {
         
     | 
| 
      
 322 
     | 
    
         
            +
                    const entityUsage = getUsage(entity, 5);
         
     | 
| 
      
 323 
     | 
    
         
            +
                    return usage.some((val) => Number(val) <= entityUsage && entityUsage < Number(val) + 5);
         
     | 
| 
      
 324 
     | 
    
         
            +
                });
         
     | 
| 
      
 325 
     | 
    
         
            +
            };
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
            export const getFilteredEntities = createSelector(
         
     | 
| 
      
 328 
     | 
    
         
            +
                [getStorageFilter, getUsageFilter, getStorageType, getVisibleEntitiesList],
         
     | 
| 
      
 329 
     | 
    
         
            +
                (textFilter, usageFilter, type, entities) => {
         
     | 
| 
      
 330 
     | 
    
         
            +
                    let result = entities;
         
     | 
| 
      
 331 
     | 
    
         
            +
                    result = filterByText(result, type, textFilter);
         
     | 
| 
      
 332 
     | 
    
         
            +
                    result = filterByUsage(result, usageFilter);
         
     | 
| 
      
 333 
     | 
    
         
            +
                    return result;
         
     | 
| 
      
 334 
     | 
    
         
            +
                },
         
     | 
| 
      
 335 
     | 
    
         
            +
            );
         
     | 
| 
      
 336 
     | 
    
         
            +
             
     | 
| 
      
 337 
     | 
    
         
            +
            export const getUsageFilterOptions = createSelector(
         
     | 
| 
      
 338 
     | 
    
         
            +
                getVisibleEntitiesList,
         
     | 
| 
      
 339 
     | 
    
         
            +
                (entities) => {
         
     | 
| 
      
 340 
     | 
    
         
            +
                    const items = {};
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
      
 342 
     | 
    
         
            +
                    entities.forEach((entity) => {
         
     | 
| 
      
 343 
     | 
    
         
            +
                        const usage = getUsage(entity, 5);
         
     | 
| 
      
 344 
     | 
    
         
            +
             
     | 
| 
      
 345 
     | 
    
         
            +
                        if (!Object.hasOwn(items, usage)) {
         
     | 
| 
      
 346 
     | 
    
         
            +
                            items[usage] = 0;
         
     | 
| 
      
 347 
     | 
    
         
            +
                        }
         
     | 
| 
      
 348 
     | 
    
         
            +
             
     | 
| 
      
 349 
     | 
    
         
            +
                        items[usage] += 1;
         
     | 
| 
      
 350 
     | 
    
         
            +
                    });
         
     | 
| 
      
 351 
     | 
    
         
            +
             
     | 
| 
      
 352 
     | 
    
         
            +
                    return Object.entries(items)
         
     | 
| 
      
 353 
     | 
    
         
            +
                        .map(([threshold, count]) => ({threshold, count}))
         
     | 
| 
      
 354 
     | 
    
         
            +
                        .sort((a, b) => b.threshold - a.threshold);
         
     | 
| 
       294 
355 
     | 
    
         
             
                },
         
     | 
| 
       295 
356 
     | 
    
         
             
            );
         
     | 
| 
       296 
357 
     | 
    
         | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import type {TVDiskStateInfo, TVSlotId} from '../types/api/storage';
         
     | 
| 
      
 2 
     | 
    
         
            +
            import type {IStoragePoolGroup} from '../types/store/storage';
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            export const isFullDonorData = (donor: TVDiskStateInfo | TVSlotId): donor is TVDiskStateInfo =>
         
     | 
| 
      
 5 
     | 
    
         
            +
                'VDiskId' in donor;
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            export const getUsage = (data: IStoragePoolGroup, step = 1) => {
         
     | 
| 
      
 8 
     | 
    
         
            +
                // if limit is 0, display 0
         
     | 
| 
      
 9 
     | 
    
         
            +
                const usage = Math.round((data.Used * 100) / data.Limit) || 0;
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                return Math.floor(usage / step) * step;
         
     | 
| 
      
 12 
     | 
    
         
            +
            };
         
     | 
    
        package/package.json
    CHANGED
    
    
| 
         @@ -1,31 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            import {useEffect, useState} from 'react';
         
     | 
| 
       2 
     | 
    
         
            -
            import {TextInput} from '@yandex-cloud/uikit';
         
     | 
| 
       3 
     | 
    
         
            -
            import {StorageTypes} from '../../../store/reducers/storage';
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            function StorageFilter(props) {
         
     | 
| 
       6 
     | 
    
         
            -
                const [filter, setFilter] = useState('');
         
     | 
| 
       7 
     | 
    
         
            -
                let timer;
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
                useEffect(() => {
         
     | 
| 
       10 
     | 
    
         
            -
                    return () => clearTimeout(timer);
         
     | 
| 
       11 
     | 
    
         
            -
                }, []);
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                useEffect(() => {
         
     | 
| 
       14 
     | 
    
         
            -
                    setFilter('');
         
     | 
| 
       15 
     | 
    
         
            -
                    props.changeReduxStorageFilter('');
         
     | 
| 
       16 
     | 
    
         
            -
                }, [props.storageType]);
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                const changeFilter = (value) => {
         
     | 
| 
       19 
     | 
    
         
            -
                    clearTimeout(timer);
         
     | 
| 
       20 
     | 
    
         
            -
                    setFilter(value);
         
     | 
| 
       21 
     | 
    
         
            -
                    timer = setTimeout(() => {
         
     | 
| 
       22 
     | 
    
         
            -
                        props.changeReduxStorageFilter(value);
         
     | 
| 
       23 
     | 
    
         
            -
                    }, 200);
         
     | 
| 
       24 
     | 
    
         
            -
                };
         
     | 
| 
       25 
     | 
    
         
            -
                const placeholder =
         
     | 
| 
       26 
     | 
    
         
            -
                    props.storageType === StorageTypes.groups ? 'Group ID, Pool name' : 'Node ID, FQDN';
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
                return <TextInput placeholder={placeholder} value={filter} onUpdate={changeFilter} hasClear />;
         
     | 
| 
       29 
     | 
    
         
            -
            }
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
            export default StorageFilter;
         
     |