ydb-embedded-ui 5.0.0 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/components/BasicNodeViewer/BasicNodeViewer.d.ts +2 -2
- package/dist/components/BasicNodeViewer/BasicNodeViewer.js +1 -1
- package/dist/components/EntityStatus/EntityStatus.scss +1 -1
- package/dist/components/FullNodeViewer/FullNodeViewer.d.ts +2 -2
- package/dist/components/FullNodeViewer/FullNodeViewer.js +1 -1
- package/dist/components/LagImages/LagImages.js +2 -2
- package/dist/components/ProgressViewer/ProgressViewer.js +6 -5
- package/dist/components/ProgressViewer/ProgressViewer.scss +33 -17
- package/dist/components/TabletsOverall/TabletsOverall.js +6 -6
- package/dist/containers/App/App.js +2 -1
- package/dist/containers/App/Content.js +6 -12
- package/dist/containers/App/Providers.js +2 -1
- package/dist/containers/App/appSlots.d.ts +7 -7
- package/dist/containers/AppIcons/AppIcons.js +1 -1
- package/dist/containers/Cluster/Cluster.js +45 -27
- package/dist/containers/Cluster/Cluster.scss +15 -0
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.js +4 -18
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +0 -40
- package/dist/containers/Cluster/utils.d.ts +6 -1
- package/dist/containers/Cluster/utils.js +11 -3
- package/dist/containers/Clusters/Clusters.js +4 -3
- package/dist/containers/Clusters/columns.js +1 -1
- package/dist/containers/Clusters/constants.d.ts +1 -1
- package/dist/containers/Clusters/i18n/en.json +2 -1
- package/dist/containers/Clusters/i18n/index.d.ts +1 -1
- package/dist/containers/Clusters/i18n/index.js +2 -4
- package/dist/containers/Clusters/i18n/ru.json +2 -1
- package/dist/containers/Node/Node.js +11 -13
- package/dist/containers/Node/NodePages.js +4 -1
- package/dist/containers/Node/i18n/index.d.ts +1 -1
- package/dist/containers/Node/i18n/index.js +2 -4
- package/dist/containers/Nodes/getNodesColumns.js +2 -1
- package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.d.ts +1 -1
- package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.d.ts +1 -1
- package/dist/containers/Storage/StorageNodes/getStorageNodesColumns.js +2 -1
- package/dist/containers/Tablet/Tablet.js +24 -20
- package/dist/containers/Tablet/i18n/index.d.ts +1 -1
- package/dist/containers/Tablet/i18n/index.js +2 -4
- package/dist/containers/TabletsFilters/TabletsFilters.d.ts +2 -0
- package/dist/containers/TabletsFilters/TabletsFilters.js +25 -19
- package/dist/containers/TabletsFilters/i18n/en.json +3 -0
- package/dist/containers/TabletsFilters/i18n/index.d.ts +2 -0
- package/dist/containers/TabletsFilters/i18n/index.js +5 -0
- package/dist/containers/TabletsFilters/i18n/ru.json +3 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.js +12 -11
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.d.ts +19 -0
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.js +2 -1
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.d.ts +7 -25
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +88 -92
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.scss +1 -33
- package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/en.json +4 -0
- package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/index.d.ts +2 -0
- package/dist/containers/Tenant/Diagnostics/HotKeys/i18n/index.js +5 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.js +4 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.js +3 -4
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +12 -5
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.d.ts +2 -2
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.js +7 -10
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +7 -5
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/index.js +0 -2
- package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.js +10 -0
- package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.d.ts +1 -1
- package/dist/containers/Tenant/Query/Query.d.ts +2 -2
- package/dist/containers/Tenant/Query/Query.js +5 -2
- package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.d.ts +29 -31
- package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +150 -167
- package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.d.ts +2 -2
- package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.js +3 -3
- package/dist/containers/Tenant/Query/QueryTabs/QueryTabs.d.ts +10 -0
- package/dist/containers/Tenant/Query/QueryTabs/QueryTabs.js +1 -1
- package/dist/containers/Tenant/Query/utils/getPreparedResult.d.ts +1 -1
- package/dist/containers/Tenant/Query/utils/getPreparedResult.js +18 -16
- package/dist/containers/Tenant/Tenant.js +4 -1
- package/dist/containers/Tenant/i18n/en.json +1 -0
- package/dist/containers/Tenant/i18n/index.d.ts +1 -1
- package/dist/containers/Tenant/i18n/index.js +2 -4
- package/dist/containers/Tenant/i18n/ru.json +1 -0
- package/dist/containers/Versions/NodesTreeTitle/NodesTreeTitle.scss +1 -1
- package/dist/routes.d.ts +5 -0
- package/dist/routes.js +4 -0
- package/dist/services/api.d.ts +2 -1
- package/dist/services/api.js +2 -2
- package/dist/services/settings.d.ts +0 -1
- package/dist/services/settings.js +1 -14
- package/dist/store/index.d.ts +1 -1
- package/dist/store/reducers/cluster/cluster.d.ts +8 -2
- package/dist/store/reducers/cluster/cluster.js +29 -1
- package/dist/store/reducers/cluster/types.d.ts +4 -2
- package/dist/store/reducers/executeQuery.d.ts +1 -10
- package/dist/store/reducers/executeQuery.js +26 -29
- package/dist/store/reducers/executeTopQueries/executeTopQueries.js +2 -1
- package/dist/store/reducers/executeTopQueries/utils.js +7 -4
- package/dist/store/reducers/hotKeys/hotKeys.d.ts +25 -0
- package/dist/store/reducers/hotKeys/hotKeys.js +49 -0
- package/dist/store/reducers/hotKeys/types.d.ts +10 -0
- package/dist/store/reducers/hotKeys/types.js +1 -0
- package/dist/store/reducers/index.d.ts +2 -6
- package/dist/store/reducers/index.js +1 -1
- package/dist/store/reducers/node/node.d.ts +1 -1
- package/dist/store/reducers/node/node.js +2 -0
- package/dist/store/reducers/node/selectors.js +1 -1
- package/dist/store/reducers/node/types.d.ts +7 -3
- package/dist/store/reducers/node/utils.d.ts +3 -0
- package/dist/store/reducers/node/utils.js +8 -0
- package/dist/store/reducers/nodes/types.d.ts +1 -1
- package/dist/store/reducers/nodes/utils.js +3 -3
- package/dist/store/reducers/storage/types.d.ts +2 -0
- package/dist/store/reducers/storage/utils.js +3 -3
- package/dist/store/reducers/tenants/utils.d.ts +4 -3
- package/dist/store/reducers/tenants/utils.js +17 -12
- package/dist/store/reducers/tooltip.d.ts +1 -1
- package/dist/types/api/hotkeys.d.ts +7 -0
- package/dist/types/api/hotkeys.js +1 -0
- package/dist/types/api/nodes.d.ts +2 -1
- package/dist/types/store/executeQuery.d.ts +3 -6
- package/dist/types/store/explainQuery.d.ts +1 -0
- package/dist/utils/constants.d.ts +1 -1
- package/dist/utils/constants.js +1 -1
- package/dist/utils/diagnostics.d.ts +1 -0
- package/dist/utils/diagnostics.js +1 -0
- package/dist/utils/i18n/i18n.d.ts +2 -1
- package/dist/utils/i18n/i18n.js +15 -2
- package/dist/utils/monitoring.js +1 -3
- package/dist/utils/versions/getVersionsColors.js +1 -1
- package/package.json +9 -8
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +0 -26
- package/dist/store/reducers/hotKeys.d.ts +0 -11
- package/dist/store/reducers/hotKeys.js +0 -34
package/dist/services/api.d.ts
CHANGED
@@ -22,6 +22,7 @@ import type { QuerySyntax } from '../types/store/query';
|
|
22
22
|
import type { ComputeApiRequestParams, NodesApiRequestParams } from '../store/reducers/nodes/types';
|
23
23
|
import type { StorageApiRequestParams } from '../store/reducers/storage/types';
|
24
24
|
import type { MetaClusters } from '../types/api/meta';
|
25
|
+
import type { JsonHotKeysResponse } from '../types/api/hotkeys';
|
25
26
|
declare type AxiosOptions = {
|
26
27
|
concurrentId?: string;
|
27
28
|
};
|
@@ -89,7 +90,7 @@ export declare class YdbEmbeddedAPI extends AxiosWrapper {
|
|
89
90
|
}, { concurrentId }?: AxiosOptions): Promise<QueryAPIResponse<Action, Schema>>;
|
90
91
|
getExplainQuery<Action extends ExplainActions>(query: string, database: string, action: Action, syntax?: QuerySyntax): Promise<ExplainResponse<Action>>;
|
91
92
|
getExplainQueryAst(query: string, database: string): Promise<import("../types/api/query").ExplainQueryResponse>;
|
92
|
-
getHotKeys(path: string, enableSampling: boolean): Promise<
|
93
|
+
getHotKeys(path: string, enableSampling: boolean, { concurrentId }?: AxiosOptions): Promise<JsonHotKeysResponse>;
|
93
94
|
getHealthcheckInfo(database: string, { concurrentId }?: AxiosOptions): Promise<HealthCheckAPIResponse>;
|
94
95
|
killTablet(id?: string): Promise<string>;
|
95
96
|
stopTablet(id?: string, hiveId?: string): Promise<string>;
|
package/dist/services/api.js
CHANGED
@@ -201,11 +201,11 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
201
201
|
timeout: 600000,
|
202
202
|
}, {});
|
203
203
|
}
|
204
|
-
getHotKeys(path, enableSampling) {
|
204
|
+
getHotKeys(path, enableSampling, { concurrentId } = {}) {
|
205
205
|
return this.get(this.getPath('/viewer/json/hotkeys'), {
|
206
206
|
path,
|
207
207
|
enable_sampling: enableSampling,
|
208
|
-
});
|
208
|
+
}, { concurrentId: concurrentId || 'getHotKeys' });
|
209
209
|
}
|
210
210
|
getHealthcheckInfo(database, { concurrentId } = {}) {
|
211
211
|
return this.get(this.getPath('/viewer/json/healthcheck?merge_records=true'), { tenant: database }, { concurrentId });
|
@@ -2,7 +2,6 @@ export declare type SettingsObject = Record<string, unknown>;
|
|
2
2
|
/** User settings keys and their default values */
|
3
3
|
export declare const DEFAULT_USER_SETTINGS: SettingsObject;
|
4
4
|
declare class SettingsManager {
|
5
|
-
constructor();
|
6
5
|
/**
|
7
6
|
* Returns parsed settings value.
|
8
7
|
* If value cannot be parsed, returns initially stored string.
|
@@ -1,8 +1,7 @@
|
|
1
1
|
import { TENANT_PAGES_IDS } from '../store/reducers/tenant/constants';
|
2
|
-
import { ASIDE_HEADER_COMPACT_KEY,
|
2
|
+
import { ASIDE_HEADER_COMPACT_KEY, INVERTED_DISKS_KEY, LANGUAGE_KEY, LAST_USED_QUERY_ACTION_KEY, PARTITIONS_HIDDEN_COLUMNS_KEY, QUERY_INITIAL_MODE_KEY, QUERY_USE_MULTI_SCHEMA_KEY, SAVED_QUERIES_KEY, TENANT_INITIAL_PAGE_KEY, THEME_KEY, USE_BACKEND_PARAMS_FOR_TABLES_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, USE_CLUSTER_BALANCER_AS_BACKEND_KEY, } from '../utils/constants';
|
3
3
|
import { QUERY_ACTIONS, QUERY_MODES } from '../utils/query';
|
4
4
|
import { parseJson } from '../utils/utils';
|
5
|
-
const USE_LOCAL_STORAGE_FOR_SETTINGS_KEY = 'useLocalStorageForSettings';
|
6
5
|
/** User settings keys and their default values */
|
7
6
|
export const DEFAULT_USER_SETTINGS = {
|
8
7
|
[THEME_KEY]: 'system',
|
@@ -16,13 +15,11 @@ export const DEFAULT_USER_SETTINGS = {
|
|
16
15
|
[LAST_USED_QUERY_ACTION_KEY]: QUERY_ACTIONS.execute,
|
17
16
|
[ASIDE_HEADER_COMPACT_KEY]: true,
|
18
17
|
[PARTITIONS_HIDDEN_COLUMNS_KEY]: [],
|
19
|
-
[CLUSTER_INFO_HIDDEN_KEY]: true,
|
20
18
|
[USE_BACKEND_PARAMS_FOR_TABLES_KEY]: false,
|
21
19
|
[USE_CLUSTER_BALANCER_AS_BACKEND_KEY]: true,
|
22
20
|
};
|
23
21
|
class SettingsManager {
|
24
22
|
constructor() {
|
25
|
-
var _a;
|
26
23
|
/**
|
27
24
|
* Extract values by provided settings object
|
28
25
|
*/
|
@@ -52,16 +49,6 @@ class SettingsManager {
|
|
52
49
|
}
|
53
50
|
catch (_a) { }
|
54
51
|
};
|
55
|
-
// Migrate settings to LS if external API was used before
|
56
|
-
const settingsApi = window.web_version ? (_a = window.systemSettings) === null || _a === void 0 ? void 0 : _a.settingsApi : undefined;
|
57
|
-
const useLocalStorage = this.readUserSettingsValue(USE_LOCAL_STORAGE_FOR_SETTINGS_KEY);
|
58
|
-
if (settingsApi && !useLocalStorage) {
|
59
|
-
const externalUserSettings = window.userSettings;
|
60
|
-
if (externalUserSettings) {
|
61
|
-
Object.entries(externalUserSettings).forEach(([key, value]) => this.setUserSettingsValue(key, value));
|
62
|
-
}
|
63
|
-
this.setUserSettingsValue(USE_LOCAL_STORAGE_FOR_SETTINGS_KEY, true);
|
64
|
-
}
|
65
52
|
}
|
66
53
|
/**
|
67
54
|
* Returns parsed settings value.
|
package/dist/store/index.d.ts
CHANGED
@@ -73,7 +73,7 @@ export function configureStore({ aRootReducer, singleClusterMode, api, }?: {
|
|
73
73
|
healthcheckInfo: import("../types/store/healthcheck").IHealthcheckInfoState;
|
74
74
|
shardsWorkload: import("./reducers/shardsWorkload/types").IShardsWorkloadState;
|
75
75
|
tenantOverviewTopShards: import("./reducers/tenantOverview/topShards/types").TenantOverviewTopShardsState;
|
76
|
-
hotKeys:
|
76
|
+
hotKeys: import("./reducers/hotKeys/types").HotKeysState;
|
77
77
|
authentication: import("./reducers/authentication/types").AuthenticationState;
|
78
78
|
header: import("./reducers/header/types").HeaderState;
|
79
79
|
saveQuery: string | null;
|
@@ -1,4 +1,5 @@
|
|
1
|
-
import type { Reducer } from 'redux';
|
1
|
+
import type { Dispatch, Reducer } from 'redux';
|
2
|
+
import { ClusterTab } from '../../../containers/Cluster/utils';
|
2
3
|
import type { ClusterAction, ClusterState } from './types';
|
3
4
|
export declare const FETCH_CLUSTER: {
|
4
5
|
readonly REQUEST: "cluster/FETCH_CLUSTER_REQUEST";
|
@@ -6,5 +7,10 @@ export declare const FETCH_CLUSTER: {
|
|
6
7
|
readonly FAILURE: "cluster/FETCH_CLUSTER_FAILURE";
|
7
8
|
};
|
8
9
|
declare const cluster: Reducer<ClusterState, ClusterAction>;
|
9
|
-
export declare function
|
10
|
+
export declare function setDefaultClusterTab(tab: ClusterTab): {
|
11
|
+
readonly type: "cluster/SET_DEFAULT_CLUSTER_TAB";
|
12
|
+
readonly data: ClusterTab;
|
13
|
+
};
|
14
|
+
export declare function updateDefaultClusterTab(tab: string): (dispatch: Dispatch) => void;
|
15
|
+
export declare function getClusterInfo(clusterName?: string): (dispatch: Dispatch<import("redux").AnyAction>, getState: import("..").GetState) => Promise<unknown>;
|
10
16
|
export default cluster;
|
@@ -1,7 +1,18 @@
|
|
1
|
+
import { DEFAULT_CLUSTER_TAB_KEY } from '../../../utils/constants';
|
2
|
+
import { clusterTabsIds, isClusterTab } from '../../../containers/Cluster/utils';
|
1
3
|
import { createRequestActionTypes, createApiRequest } from '../../utils';
|
2
4
|
import { createSelectClusterGroupsQuery, parseGroupsStatsQueryResponse } from './utils';
|
5
|
+
const SET_DEFAULT_CLUSTER_TAB = 'cluster/SET_DEFAULT_CLUSTER_TAB';
|
3
6
|
export const FETCH_CLUSTER = createRequestActionTypes('cluster', 'FETCH_CLUSTER');
|
4
|
-
const
|
7
|
+
const defaultClusterTabLS = localStorage.getItem(DEFAULT_CLUSTER_TAB_KEY);
|
8
|
+
let defaultClusterTab;
|
9
|
+
if (isClusterTab(defaultClusterTabLS)) {
|
10
|
+
defaultClusterTab = defaultClusterTabLS;
|
11
|
+
}
|
12
|
+
else {
|
13
|
+
defaultClusterTab = clusterTabsIds.overview;
|
14
|
+
}
|
15
|
+
const initialState = { loading: true, wasLoaded: false, defaultClusterTab };
|
5
16
|
const cluster = (state = initialState, action) => {
|
6
17
|
var _a;
|
7
18
|
switch (action.type) {
|
@@ -18,10 +29,27 @@ const cluster = (state = initialState, action) => {
|
|
18
29
|
}
|
19
30
|
return Object.assign(Object.assign({}, state), { error: action.error, loading: false });
|
20
31
|
}
|
32
|
+
case SET_DEFAULT_CLUSTER_TAB: {
|
33
|
+
return Object.assign(Object.assign({}, state), { defaultClusterTab: action.data });
|
34
|
+
}
|
21
35
|
default:
|
22
36
|
return state;
|
23
37
|
}
|
24
38
|
};
|
39
|
+
export function setDefaultClusterTab(tab) {
|
40
|
+
return {
|
41
|
+
type: SET_DEFAULT_CLUSTER_TAB,
|
42
|
+
data: tab,
|
43
|
+
};
|
44
|
+
}
|
45
|
+
export function updateDefaultClusterTab(tab) {
|
46
|
+
return (dispatch) => {
|
47
|
+
if (isClusterTab(tab)) {
|
48
|
+
localStorage.setItem(DEFAULT_CLUSTER_TAB_KEY, tab);
|
49
|
+
dispatch(setDefaultClusterTab(tab));
|
50
|
+
}
|
51
|
+
};
|
52
|
+
}
|
25
53
|
export function getClusterInfo(clusterName) {
|
26
54
|
async function requestClusterData() {
|
27
55
|
// Error here is handled by createApiRequest
|
@@ -1,7 +1,8 @@
|
|
1
|
+
import type { ClusterTab } from '../../../containers/Cluster/utils';
|
1
2
|
import type { TClusterInfo } from '../../../types/api/cluster';
|
2
3
|
import type { IResponseError } from '../../../types/api/error';
|
3
4
|
import type { ApiRequestAction } from '../../utils';
|
4
|
-
import { FETCH_CLUSTER } from './cluster';
|
5
|
+
import type { FETCH_CLUSTER, setDefaultClusterTab } from './cluster';
|
5
6
|
export interface DiskErasureGroupsStats {
|
6
7
|
diskType: string;
|
7
8
|
erasure: string;
|
@@ -20,9 +21,10 @@ export interface ClusterState {
|
|
20
21
|
data?: TClusterInfo;
|
21
22
|
error?: IResponseError;
|
22
23
|
groupsStats?: ClusterGroupsStats;
|
24
|
+
defaultClusterTab: ClusterTab;
|
23
25
|
}
|
24
26
|
export interface HandledClusterResponse {
|
25
27
|
clusterData: TClusterInfo;
|
26
28
|
groupsStats: ClusterGroupsStats;
|
27
29
|
}
|
28
|
-
export declare type ClusterAction = ApiRequestAction<typeof FETCH_CLUSTER, HandledClusterResponse, IResponseError>;
|
30
|
+
export declare type ClusterAction = ApiRequestAction<typeof FETCH_CLUSTER, HandledClusterResponse, IResponseError> | ReturnType<typeof setDefaultClusterTab>;
|
@@ -1,17 +1,12 @@
|
|
1
1
|
import type { Reducer } from 'redux';
|
2
2
|
import type { Schemas } from '../../types/api/query';
|
3
|
-
import type { ExecuteQueryAction, ExecuteQueryState, ExecuteQueryStateSlice,
|
3
|
+
import type { ExecuteQueryAction, ExecuteQueryState, ExecuteQueryStateSlice, QueryInHistory } from '../../types/store/executeQuery';
|
4
4
|
import type { QueryRequestParams, QueryMode } from '../../types/store/query';
|
5
5
|
export declare const SEND_QUERY: {
|
6
6
|
readonly REQUEST: "query/SEND_QUERY_REQUEST";
|
7
7
|
readonly SUCCESS: "query/SEND_QUERY_SUCCESS";
|
8
8
|
readonly FAILURE: "query/SEND_QUERY_FAILURE";
|
9
9
|
};
|
10
|
-
export declare const MONACO_HOT_KEY_ACTIONS: {
|
11
|
-
readonly sendQuery: "sendQuery";
|
12
|
-
readonly goPrev: "goPrev";
|
13
|
-
readonly goNext: "goNext";
|
14
|
-
};
|
15
10
|
declare const executeQuery: Reducer<ExecuteQueryState, ExecuteQueryAction>;
|
16
11
|
interface SendQueryParams extends QueryRequestParams {
|
17
12
|
mode?: QueryMode;
|
@@ -39,10 +34,6 @@ export declare const changeUserInput: ({ input }: {
|
|
39
34
|
readonly input: string;
|
40
35
|
};
|
41
36
|
};
|
42
|
-
export declare const setMonacoHotKey: (value: MonacoHotKeyAction | null) => {
|
43
|
-
readonly type: "query/SET_MONACO_HOT_KEY";
|
44
|
-
readonly data: MonacoHotKeyAction | null;
|
45
|
-
};
|
46
37
|
export declare const setTenantPath: (value: string) => {
|
47
38
|
readonly type: "query/SET_TENANT_PATH";
|
48
39
|
readonly data: string;
|
@@ -9,25 +9,20 @@ const CHANGE_USER_INPUT = 'query/CHANGE_USER_INPUT';
|
|
9
9
|
const SAVE_QUERY_TO_HISTORY = 'query/SAVE_QUERY_TO_HISTORY';
|
10
10
|
const GO_TO_PREVIOUS_QUERY = 'query/GO_TO_PREVIOUS_QUERY';
|
11
11
|
const GO_TO_NEXT_QUERY = 'query/GO_TO_NEXT_QUERY';
|
12
|
-
const SET_MONACO_HOT_KEY = 'query/SET_MONACO_HOT_KEY';
|
13
12
|
const SET_TENANT_PATH = 'query/SET_TENANT_PATH';
|
14
13
|
const queriesHistoryInitial = settingsManager.readUserSettingsValue(QUERIES_HISTORY_KEY, []);
|
15
14
|
const sliceLimit = queriesHistoryInitial.length - MAXIMUM_QUERIES_IN_HISTORY;
|
16
|
-
export const MONACO_HOT_KEY_ACTIONS = {
|
17
|
-
sendQuery: 'sendQuery',
|
18
|
-
goPrev: 'goPrev',
|
19
|
-
goNext: 'goNext',
|
20
|
-
};
|
21
15
|
const initialState = {
|
22
16
|
loading: false,
|
23
17
|
input: '',
|
24
18
|
history: {
|
25
|
-
queries: queriesHistoryInitial
|
19
|
+
queries: queriesHistoryInitial
|
20
|
+
.slice(sliceLimit < 0 ? 0 : sliceLimit)
|
21
|
+
.map(getQueryInHistory),
|
26
22
|
currentIndex: queriesHistoryInitial.length > MAXIMUM_QUERIES_IN_HISTORY
|
27
23
|
? MAXIMUM_QUERIES_IN_HISTORY - 1
|
28
24
|
: queriesHistoryInitial.length - 1,
|
29
25
|
},
|
30
|
-
monacoHotKey: null,
|
31
26
|
};
|
32
27
|
const executeQuery = (state = initialState, action) => {
|
33
28
|
switch (action.type) {
|
@@ -56,16 +51,23 @@ const executeQuery = (state = initialState, action) => {
|
|
56
51
|
} });
|
57
52
|
}
|
58
53
|
case GO_TO_PREVIOUS_QUERY: {
|
59
|
-
const
|
60
|
-
|
54
|
+
const currentIndex = state.history.currentIndex;
|
55
|
+
if (currentIndex <= 0) {
|
56
|
+
return state;
|
57
|
+
}
|
58
|
+
const newCurrentIndex = currentIndex - 1;
|
59
|
+
const query = state.history.queries[newCurrentIndex];
|
60
|
+
return Object.assign(Object.assign({}, state), { history: Object.assign(Object.assign({}, state.history), { currentIndex: newCurrentIndex }), input: query.queryText });
|
61
61
|
}
|
62
62
|
case GO_TO_NEXT_QUERY: {
|
63
63
|
const lastIndexInHistory = state.history.queries.length - 1;
|
64
|
-
const
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
const currentIndex = state.history.currentIndex;
|
65
|
+
if (currentIndex >= lastIndexInHistory) {
|
66
|
+
return state;
|
67
|
+
}
|
68
|
+
const newCurrentIndex = currentIndex + 1;
|
69
|
+
const query = state.history.queries[newCurrentIndex];
|
70
|
+
return Object.assign(Object.assign({}, state), { history: Object.assign(Object.assign({}, state.history), { currentIndex: newCurrentIndex }), input: query.queryText });
|
69
71
|
}
|
70
72
|
case SET_TENANT_PATH: {
|
71
73
|
return Object.assign(Object.assign({}, state), { tenantPath: action.data });
|
@@ -119,12 +121,6 @@ export const changeUserInput = ({ input }) => {
|
|
119
121
|
data: { input },
|
120
122
|
};
|
121
123
|
};
|
122
|
-
export const setMonacoHotKey = (value) => {
|
123
|
-
return {
|
124
|
-
type: SET_MONACO_HOT_KEY,
|
125
|
-
data: value,
|
126
|
-
};
|
127
|
-
};
|
128
124
|
export const setTenantPath = (value) => {
|
129
125
|
return {
|
130
126
|
type: SET_TENANT_PATH,
|
@@ -132,13 +128,14 @@ export const setTenantPath = (value) => {
|
|
132
128
|
};
|
133
129
|
};
|
134
130
|
export const selectQueriesHistory = (state) => {
|
135
|
-
return state.executeQuery.history.queries
|
136
|
-
if (typeof rawQuery === 'string') {
|
137
|
-
return {
|
138
|
-
queryText: rawQuery,
|
139
|
-
};
|
140
|
-
}
|
141
|
-
return rawQuery;
|
142
|
-
});
|
131
|
+
return state.executeQuery.history.queries;
|
143
132
|
};
|
133
|
+
function getQueryInHistory(rawQuery) {
|
134
|
+
if (typeof rawQuery === 'string') {
|
135
|
+
return {
|
136
|
+
queryText: rawQuery,
|
137
|
+
};
|
138
|
+
}
|
139
|
+
return rawQuery;
|
140
|
+
}
|
144
141
|
export default executeQuery;
|
@@ -1,6 +1,8 @@
|
|
1
|
+
const endTimeColumn = 'EndTime';
|
2
|
+
const intervalEndColumn = 'IntervalEnd';
|
1
3
|
const getMaxIntervalSubquery = (path) => `(
|
2
4
|
SELECT
|
3
|
-
MAX(
|
5
|
+
MAX(${intervalEndColumn})
|
4
6
|
FROM \`${path}/.sys/top_queries_by_cpu_time_one_hour\`
|
5
7
|
)`;
|
6
8
|
export function getFiltersConditions(path, filters) {
|
@@ -12,13 +14,14 @@ export function getFiltersConditions(path, filters) {
|
|
12
14
|
// matching `from` & `to` is an edge case
|
13
15
|
// other cases should not include the starting point, since intervals are stored using the ending time
|
14
16
|
const gt = filters.to === filters.from ? '>=' : '>';
|
15
|
-
conditions.push(
|
17
|
+
conditions.push(`${endTimeColumn} ${gt} Timestamp('${new Date(filters.from).toISOString()}')`);
|
16
18
|
}
|
17
19
|
if (filters === null || filters === void 0 ? void 0 : filters.to) {
|
18
|
-
conditions.push(
|
20
|
+
conditions.push(`${endTimeColumn} <= Timestamp('${new Date(filters.to).toISOString()}')`);
|
19
21
|
}
|
22
|
+
// If there is no filters, return queries, that were executed in the last hour
|
20
23
|
if (!(filters === null || filters === void 0 ? void 0 : filters.from) && !(filters === null || filters === void 0 ? void 0 : filters.to)) {
|
21
|
-
conditions.push(
|
24
|
+
conditions.push(`${intervalEndColumn} IN ${getMaxIntervalSubquery(path)}`);
|
22
25
|
}
|
23
26
|
if (filters === null || filters === void 0 ? void 0 : filters.text) {
|
24
27
|
conditions.push(`QueryText ILIKE '%${filters.text}%'`);
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import type { Reducer } from 'redux';
|
2
|
+
import type { JsonHotKeysResponse } from '../../../types/api/hotkeys';
|
3
|
+
import type { IResponseError } from '../../../types/api/error';
|
4
|
+
import type { HotKeysAction, HotKeysState } from './types';
|
5
|
+
export declare const FETCH_HOT_KEYS: {
|
6
|
+
readonly REQUEST: "hot_keys/FETCH_HOT_KEYS_REQUEST";
|
7
|
+
readonly SUCCESS: "hot_keys/FETCH_HOT_KEYS_SUCCESS";
|
8
|
+
readonly FAILURE: "hot_keys/FETCH_HOT_KEYS_FAILURE";
|
9
|
+
};
|
10
|
+
declare const hotKeys: Reducer<HotKeysState, HotKeysAction>;
|
11
|
+
export declare function setHotKeysDataWasNotLoaded(): {
|
12
|
+
readonly type: "hot_keys/SET_DATA_WAS_NOT_LOADED";
|
13
|
+
};
|
14
|
+
export declare function setHotKeysLoading(): {
|
15
|
+
readonly type: "hot_keys/FETCH_HOT_KEYS_REQUEST";
|
16
|
+
};
|
17
|
+
export declare function setHotKeysData(data: JsonHotKeysResponse): {
|
18
|
+
readonly type: "hot_keys/FETCH_HOT_KEYS_SUCCESS";
|
19
|
+
readonly data: JsonHotKeysResponse;
|
20
|
+
};
|
21
|
+
export declare function setHotKeysError(error: IResponseError): {
|
22
|
+
readonly type: "hot_keys/FETCH_HOT_KEYS_FAILURE";
|
23
|
+
readonly error: IResponseError<unknown>;
|
24
|
+
};
|
25
|
+
export default hotKeys;
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import { createRequestActionTypes } from '../../utils';
|
2
|
+
export const FETCH_HOT_KEYS = createRequestActionTypes('hot_keys', 'FETCH_HOT_KEYS');
|
3
|
+
const SET_DATA_WAS_NOT_LOADED = 'hot_keys/SET_DATA_WAS_NOT_LOADED';
|
4
|
+
const initialState = { loading: true, wasLoaded: false, data: null };
|
5
|
+
const hotKeys = (state = initialState, action) => {
|
6
|
+
var _a;
|
7
|
+
switch (action.type) {
|
8
|
+
case FETCH_HOT_KEYS.REQUEST: {
|
9
|
+
return Object.assign(Object.assign({}, state), { loading: true });
|
10
|
+
}
|
11
|
+
case FETCH_HOT_KEYS.SUCCESS: {
|
12
|
+
return Object.assign(Object.assign({}, state), { data: action.data.hotkeys, loading: false, error: undefined, wasLoaded: true });
|
13
|
+
}
|
14
|
+
case FETCH_HOT_KEYS.FAILURE: {
|
15
|
+
if ((_a = action.error) === null || _a === void 0 ? void 0 : _a.isCancelled) {
|
16
|
+
return state;
|
17
|
+
}
|
18
|
+
return Object.assign(Object.assign({}, state), { error: action.error, loading: false });
|
19
|
+
}
|
20
|
+
case SET_DATA_WAS_NOT_LOADED: {
|
21
|
+
return Object.assign(Object.assign({}, state), { wasLoaded: false });
|
22
|
+
}
|
23
|
+
default:
|
24
|
+
return state;
|
25
|
+
}
|
26
|
+
};
|
27
|
+
export function setHotKeysDataWasNotLoaded() {
|
28
|
+
return {
|
29
|
+
type: SET_DATA_WAS_NOT_LOADED,
|
30
|
+
};
|
31
|
+
}
|
32
|
+
export function setHotKeysLoading() {
|
33
|
+
return {
|
34
|
+
type: FETCH_HOT_KEYS.REQUEST,
|
35
|
+
};
|
36
|
+
}
|
37
|
+
export function setHotKeysData(data) {
|
38
|
+
return {
|
39
|
+
type: FETCH_HOT_KEYS.SUCCESS,
|
40
|
+
data: data,
|
41
|
+
};
|
42
|
+
}
|
43
|
+
export function setHotKeysError(error) {
|
44
|
+
return {
|
45
|
+
type: FETCH_HOT_KEYS.FAILURE,
|
46
|
+
error: error,
|
47
|
+
};
|
48
|
+
}
|
49
|
+
export default hotKeys;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import type { IResponseError } from '../../../types/api/error';
|
2
|
+
import type { HotKey } from '../../../types/api/hotkeys';
|
3
|
+
import type { setHotKeysData, setHotKeysDataWasNotLoaded, setHotKeysError, setHotKeysLoading } from './hotKeys';
|
4
|
+
export interface HotKeysState {
|
5
|
+
loading: boolean;
|
6
|
+
wasLoaded: boolean;
|
7
|
+
data: null | HotKey[];
|
8
|
+
error?: IResponseError;
|
9
|
+
}
|
10
|
+
export declare type HotKeysAction = ReturnType<typeof setHotKeysDataWasNotLoaded> | ReturnType<typeof setHotKeysLoading> | ReturnType<typeof setHotKeysData> | ReturnType<typeof setHotKeysError>;
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -89,11 +89,7 @@ export declare const rootReducer: {
|
|
89
89
|
healthcheckInfo: import("redux").Reducer<import("../../types/store/healthcheck").IHealthcheckInfoState, import("../../types/store/healthcheck").IHealthCheckInfoAction>;
|
90
90
|
shardsWorkload: import("redux").Reducer<import("./shardsWorkload/types").IShardsWorkloadState, import("./shardsWorkload/types").IShardsWorkloadAction>;
|
91
91
|
tenantOverviewTopShards: import("redux").Reducer<import("./tenantOverview/topShards/types").TenantOverviewTopShardsState, import("./tenantOverview/topShards/types").TenantOverviewTopShardsAction>;
|
92
|
-
hotKeys: (
|
93
|
-
loading: boolean;
|
94
|
-
data: {};
|
95
|
-
wasLoaded: boolean;
|
96
|
-
} | undefined, action: any) => any;
|
92
|
+
hotKeys: import("redux").Reducer<import("./hotKeys/types").HotKeysState, import("./hotKeys/types").HotKeysAction>;
|
97
93
|
authentication: import("redux").Reducer<import("./authentication/types").AuthenticationState, import("./authentication/types").AuthenticationAction>;
|
98
94
|
header: import("redux").Reducer<import("./header/types").HeaderState, {
|
99
95
|
readonly type: "header/SET_HEADER_BREADCRUMBS";
|
@@ -187,7 +183,7 @@ declare const combinedReducer: import("redux").Reducer<import("redux").CombinedS
|
|
187
183
|
healthcheckInfo: import("../../types/store/healthcheck").IHealthcheckInfoState;
|
188
184
|
shardsWorkload: import("./shardsWorkload/types").IShardsWorkloadState;
|
189
185
|
tenantOverviewTopShards: import("./tenantOverview/topShards/types").TenantOverviewTopShardsState;
|
190
|
-
hotKeys:
|
186
|
+
hotKeys: import("./hotKeys/types").HotKeysState;
|
191
187
|
authentication: import("./authentication/types").AuthenticationState;
|
192
188
|
header: import("./header/types").HeaderState;
|
193
189
|
saveQuery: string | null;
|
@@ -34,7 +34,7 @@ import executeTopTables from './tenantOverview/executeTopTables/executeTopTables
|
|
34
34
|
import healthcheckInfo from './healthcheckInfo';
|
35
35
|
import shardsWorkload from './shardsWorkload/shardsWorkload';
|
36
36
|
import { tenantOverviewTopShards } from './tenantOverview/topShards/tenantOverviewTopShards';
|
37
|
-
import hotKeys from './hotKeys';
|
37
|
+
import hotKeys from './hotKeys/hotKeys';
|
38
38
|
import olapStats from './olapStats';
|
39
39
|
import authentication from './authentication/authentication';
|
40
40
|
import header from './header/header';
|
@@ -11,7 +11,7 @@ export declare const FETCH_NODE_STRUCTURE: {
|
|
11
11
|
readonly FAILURE: "node/FETCH_NODE_STRUCTURE_FAILURE";
|
12
12
|
};
|
13
13
|
declare const node: Reducer<NodeState, NodeAction>;
|
14
|
-
export declare const getNodeInfo: (id: string) => (dispatch: import("redux").Dispatch<import("redux").AnyAction>, getState: import("..").GetState) => Promise<
|
14
|
+
export declare const getNodeInfo: (id: string) => (dispatch: import("redux").Dispatch<import("redux").AnyAction>, getState: import("..").GetState) => Promise<import("./types").PreparedNode | undefined>;
|
15
15
|
export declare const getNodeStructure: (nodeId: string) => (dispatch: import("redux").Dispatch<import("redux").AnyAction>, getState: import("..").GetState) => Promise<unknown>;
|
16
16
|
export declare function resetNode(): {
|
17
17
|
readonly type: "node/RESET_NODE";
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { createRequestActionTypes, createApiRequest } from '../../utils';
|
2
|
+
import { prepareNodeData } from './utils';
|
2
3
|
export const FETCH_NODE = createRequestActionTypes('node', 'FETCH_NODE');
|
3
4
|
export const FETCH_NODE_STRUCTURE = createRequestActionTypes('node', 'FETCH_NODE_STRUCTURE');
|
4
5
|
const RESET_NODE = 'node/RESET_NODE';
|
@@ -41,6 +42,7 @@ export const getNodeInfo = (id) => {
|
|
41
42
|
return createApiRequest({
|
42
43
|
request: window.api.getNodeInfo(id),
|
43
44
|
actions: FETCH_NODE,
|
45
|
+
dataHandler: prepareNodeData,
|
44
46
|
});
|
45
47
|
};
|
46
48
|
export const getNodeStructure = (nodeId) => {
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { createSelector } from 'reselect';
|
2
2
|
import { stringifyVdiskId } from '../../../utils/dataFormatters/dataFormatters';
|
3
|
-
const selectNodeId = (state) => { var _a, _b
|
3
|
+
const selectNodeId = (state) => { var _a, _b; return (_b = (_a = state.node) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.NodeId; };
|
4
4
|
const selectRawNodeStructure = (state) => { var _a; return (_a = state.node) === null || _a === void 0 ? void 0 : _a.nodeStructure; };
|
5
5
|
export const selectNodeStructure = createSelector([selectNodeId, selectRawNodeStructure], (nodeId, storageInfo) => {
|
6
6
|
const pools = storageInfo === null || storageInfo === void 0 ? void 0 : storageInfo.StoragePools;
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import type { IResponseError } from '../../../types/api/error';
|
2
|
+
import type { TSystemStateInfo } from '../../../types/api/nodes';
|
2
3
|
import type { TPDiskStateInfo } from '../../../types/api/pdisk';
|
3
4
|
import type { TStorageInfo } from '../../../types/api/storage';
|
4
|
-
import type { TEvSystemStateResponse } from '../../../types/api/systemState';
|
5
5
|
import type { TVDiskStateInfo } from '../../../types/api/vdisk';
|
6
6
|
import type { ApiRequestAction } from '../../utils';
|
7
7
|
import { FETCH_NODE, FETCH_NODE_STRUCTURE, resetNode } from './node';
|
@@ -17,8 +17,12 @@ export interface PreparedStructurePDisk extends TPDiskStateInfo {
|
|
17
17
|
vDisks: PreparedStructureVDisk[];
|
18
18
|
}
|
19
19
|
export declare type PreparedNodeStructure = Record<string, PreparedStructurePDisk>;
|
20
|
+
export interface PreparedNode extends TSystemStateInfo {
|
21
|
+
DC?: string;
|
22
|
+
Rack?: string;
|
23
|
+
}
|
20
24
|
export interface NodeState {
|
21
|
-
data:
|
25
|
+
data: PreparedNode;
|
22
26
|
loading: boolean;
|
23
27
|
wasLoaded: boolean;
|
24
28
|
error?: IResponseError;
|
@@ -27,7 +31,7 @@ export interface NodeState {
|
|
27
31
|
wasLoadedStructure: boolean;
|
28
32
|
errorStructure?: IResponseError;
|
29
33
|
}
|
30
|
-
export declare type NodeAction = ApiRequestAction<typeof FETCH_NODE,
|
34
|
+
export declare type NodeAction = ApiRequestAction<typeof FETCH_NODE, PreparedNode, IResponseError> | ApiRequestAction<typeof FETCH_NODE_STRUCTURE, TStorageInfo, IResponseError> | ReturnType<typeof resetNode>;
|
31
35
|
export interface NodeStateSlice {
|
32
36
|
node: NodeState;
|
33
37
|
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
export const prepareNodeData = (data) => {
|
2
|
+
var _a, _b, _c;
|
3
|
+
if (!((_a = data.SystemStateInfo) === null || _a === void 0 ? void 0 : _a.length)) {
|
4
|
+
return {};
|
5
|
+
}
|
6
|
+
const nodeData = data.SystemStateInfo[0];
|
7
|
+
return Object.assign(Object.assign({}, nodeData), { DC: (_b = nodeData.Location) === null || _b === void 0 ? void 0 : _b.DataCenter, Rack: (_c = nodeData.Location) === null || _c === void 0 ? void 0 : _c.Rack });
|
8
|
+
};
|
@@ -4,7 +4,7 @@ const prepareComputeNode = (node, tenantName) => {
|
|
4
4
|
var _a;
|
5
5
|
return Object.assign(Object.assign({}, node), {
|
6
6
|
// v2 response has tenant name, v1 - doesn't
|
7
|
-
TenantName: (_a = node.Tenant) !== null && _a !== void 0 ? _a : tenantName, SystemState: node === null || node === void 0 ? void 0 : node.Overall, Uptime: calcUptime(node === null || node === void 0 ? void 0 : node.StartTime) });
|
7
|
+
TenantName: (_a = node.Tenant) !== null && _a !== void 0 ? _a : tenantName, SystemState: node === null || node === void 0 ? void 0 : node.Overall, Uptime: calcUptime(node === null || node === void 0 ? void 0 : node.StartTime), DC: node.DataCenter });
|
8
8
|
};
|
9
9
|
export const prepareComputeNodes = (nodes, tenants) => {
|
10
10
|
var _a;
|
@@ -36,10 +36,10 @@ export const prepareComputeNodesData = (data) => {
|
|
36
36
|
export const prepareNodesData = (data) => {
|
37
37
|
const rawNodes = data.Nodes || [];
|
38
38
|
const preparedNodes = rawNodes.map((node) => {
|
39
|
-
var _a, _b, _c, _d, _e;
|
39
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
40
40
|
// 0 limit means that limit is not set, so it should be undefined
|
41
41
|
const sharedCacheLimit = Number((_a = node.SystemState.SharedCacheStats) === null || _a === void 0 ? void 0 : _a.LimitBytes) || undefined;
|
42
|
-
return Object.assign(Object.assign({}, node.SystemState), { Tablets: node.Tablets, NodeId: node.NodeId, Uptime: calcUptime((_b = node.SystemState) === null || _b === void 0 ? void 0 : _b.StartTime), TenantName: (_d = (_c = node.SystemState) === null || _c === void 0 ? void 0 : _c.Tenants) === null || _d === void 0 ? void 0 : _d[0],
|
42
|
+
return Object.assign(Object.assign({}, node.SystemState), { Tablets: node.Tablets, NodeId: node.NodeId, Uptime: calcUptime((_b = node.SystemState) === null || _b === void 0 ? void 0 : _b.StartTime), TenantName: (_d = (_c = node.SystemState) === null || _c === void 0 ? void 0 : _c.Tenants) === null || _d === void 0 ? void 0 : _d[0], DC: (_e = node.SystemState.Location) === null || _e === void 0 ? void 0 : _e.DataCenter, Rack: (_f = node.SystemState.Location) === null || _f === void 0 ? void 0 : _f.Rack, SharedCacheUsed: (_g = node.SystemState.SharedCacheStats) === null || _g === void 0 ? void 0 : _g.UsedBytes, SharedCacheLimit: sharedCacheLimit });
|
43
43
|
});
|
44
44
|
return {
|
45
45
|
Nodes: preparedNodes,
|
@@ -85,7 +85,7 @@ export const prepareStorageGroups = (StorageGroups, StoragePools) => {
|
|
85
85
|
};
|
86
86
|
// ==== Prepare nodes ====
|
87
87
|
const prepareStorageNodeData = (node) => {
|
88
|
-
var _a, _b;
|
88
|
+
var _a, _b, _c, _d;
|
89
89
|
const systemState = (_a = node.SystemState) !== null && _a !== void 0 ? _a : {};
|
90
90
|
const missing = ((_b = node.PDisks) === null || _b === void 0 ? void 0 : _b.filter((pDisk) => {
|
91
91
|
return pDisk.State !== TPDiskState.Normal;
|
@@ -93,8 +93,8 @@ const prepareStorageNodeData = (node) => {
|
|
93
93
|
return {
|
94
94
|
NodeId: node.NodeId,
|
95
95
|
SystemState: systemState.SystemState,
|
96
|
-
|
97
|
-
Rack: systemState.Rack,
|
96
|
+
DC: (_c = systemState.Location) === null || _c === void 0 ? void 0 : _c.DataCenter,
|
97
|
+
Rack: (_d = systemState.Location) === null || _d === void 0 ? void 0 : _d.Rack,
|
98
98
|
Host: systemState.Host,
|
99
99
|
Endpoints: systemState.Endpoints,
|
100
100
|
Uptime: calcUptime(systemState.StartTime),
|