ydb-embedded-ui 20.5.0 → 21.1.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/README.md +41 -0
- package/dist/components/AutoRefreshControl/i18n/index.d.ts +1 -1
- package/dist/components/CriticalActionDialog/CriticalActionDialog.js +10 -6
- package/dist/components/CriticalActionDialog/CriticalActionDialog.js.map +1 -1
- package/dist/components/CriticalActionDialog/i18n/en.json +1 -2
- package/dist/components/CriticalActionDialog/i18n/index.d.ts +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.d.ts +2 -1
- package/dist/components/DropdownMenu/DropdownMenu.js +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/FullNodeViewer/i18n/index.d.ts +1 -1
- package/dist/components/Graph/BlockComponents/ConnectionBlockComponent.d.ts +7 -0
- package/dist/components/Graph/BlockComponents/ConnectionBlockComponent.js +30 -0
- package/dist/components/Graph/BlockComponents/ConnectionBlockComponent.js.map +1 -0
- package/dist/components/Graph/BlockComponents/QueryBlockComponent.d.ts +5 -0
- package/dist/components/Graph/BlockComponents/QueryBlockComponent.js +5 -0
- package/dist/components/Graph/BlockComponents/QueryBlockComponent.js.map +1 -0
- package/dist/components/Graph/BlockComponents/ResultBlockComponent.d.ts +7 -0
- package/dist/components/Graph/BlockComponents/ResultBlockComponent.js +5 -0
- package/dist/components/Graph/BlockComponents/ResultBlockComponent.js.map +1 -0
- package/dist/components/Graph/BlockComponents/StageBlockComponent.d.ts +7 -0
- package/dist/components/Graph/BlockComponents/StageBlockComponent.js +17 -0
- package/dist/components/Graph/BlockComponents/StageBlockComponent.js.map +1 -0
- package/dist/components/Graph/FullViewportBackground.d.ts +2 -0
- package/dist/components/Graph/FullViewportBackground.js +67 -0
- package/dist/components/Graph/FullViewportBackground.js.map +1 -0
- package/dist/components/Graph/GraphControls.d.ts +6 -0
- package/dist/components/Graph/GraphControls.js +24 -0
- package/dist/components/Graph/GraphControls.js.map +1 -0
- package/dist/components/Graph/GravityGraph.d.ts +9 -0
- package/dist/components/Graph/GravityGraph.js +122 -0
- package/dist/components/Graph/GravityGraph.js.map +1 -0
- package/dist/components/Graph/GravityGraph.scss +131 -0
- package/dist/components/Graph/NonSelectableConnection.d.ts +9 -0
- package/dist/components/Graph/NonSelectableConnection.js +16 -0
- package/dist/components/Graph/NonSelectableConnection.js.map +1 -0
- package/dist/components/Graph/TooltipComponent.d.ts +8 -0
- package/dist/components/Graph/TooltipComponent.js +63 -0
- package/dist/components/Graph/TooltipComponent.js.map +1 -0
- package/dist/components/Graph/colorsConfig.d.ts +19 -0
- package/dist/components/Graph/colorsConfig.js +20 -0
- package/dist/components/Graph/colorsConfig.js.map +1 -0
- package/dist/components/Graph/i18n/en.json +5 -0
- package/dist/components/Graph/i18n/index.d.ts +2 -0
- package/dist/components/Graph/i18n/index.js +5 -0
- package/dist/components/Graph/i18n/index.js.map +1 -0
- package/dist/components/Graph/runTreeLayout.d.ts +12 -0
- package/dist/components/Graph/runTreeLayout.js +75 -0
- package/dist/components/Graph/runTreeLayout.js.map +1 -0
- package/dist/components/Graph/treeLayout.d.ts +2 -0
- package/dist/components/Graph/treeLayout.js +284 -0
- package/dist/components/Graph/treeLayout.js.map +1 -0
- package/dist/components/Graph/types.d.ts +52 -0
- package/dist/components/Graph/types.js +2 -0
- package/dist/components/Graph/types.js.map +1 -0
- package/dist/components/Graph/utils.d.ts +6 -0
- package/dist/components/Graph/utils.js +88 -0
- package/dist/components/Graph/utils.js.map +1 -0
- package/dist/components/PDiskInfo/i18n/index.d.ts +1 -1
- package/dist/components/VDiskInfo/i18n/index.d.ts +1 -1
- package/dist/containers/Clusters/constants.d.ts +1 -1
- package/dist/containers/Header/HeaderActionsMenu.js +19 -3
- package/dist/containers/Header/HeaderActionsMenu.js.map +1 -1
- package/dist/containers/Header/hooks/useSharedDatabasePath.d.ts +4 -1
- package/dist/containers/Header/hooks/useSharedDatabasePath.js +14 -10
- package/dist/containers/Header/hooks/useSharedDatabasePath.js.map +1 -1
- package/dist/containers/Header/i18n/en.json +1 -0
- package/dist/containers/Header/i18n/index.d.ts +1 -1
- package/dist/containers/Nodes/i18n/index.d.ts +1 -1
- package/dist/containers/Operations/columns.js +2 -2
- package/dist/containers/Operations/columns.js.map +1 -1
- package/dist/containers/Operations/constants.d.ts +1 -1
- package/dist/containers/Operations/i18n/en.json +2 -2
- package/dist/containers/PDiskPage/DecommissionButton/DecommissionButton.js +1 -1
- package/dist/containers/PDiskPage/DecommissionButton/DecommissionButton.js.map +1 -1
- package/dist/containers/PDiskPage/PDiskPage.js +1 -1
- package/dist/containers/PDiskPage/PDiskPage.js.map +1 -1
- package/dist/containers/PDiskPage/i18n/en.json +3 -3
- package/dist/containers/Storage/PDisks/PDisks.js +1 -1
- package/dist/containers/Storage/PDisks/PDisks.js.map +1 -1
- package/dist/containers/Tablet/components/TabletControls/TabletControls.js +1 -1
- package/dist/containers/Tablet/components/TabletControls/TabletControls.js.map +1 -1
- package/dist/containers/Tablet/i18n/en.json +3 -3
- package/dist/containers/Tablets/TabletsTable.js +1 -1
- package/dist/containers/Tablets/TabletsTable.js.map +1 -1
- package/dist/containers/Tablets/i18n/en.json +1 -1
- package/dist/containers/Tenant/Diagnostics/Overview/TransferInfo/Credentials.d.ts +1 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.js +3 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.js.map +1 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +2 -2
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js.map +1 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/useTenantStorageNewData.d.ts +2 -2
- package/dist/containers/Tenant/Healthcheck/components/HealthcheckDrawer.js +10 -2
- package/dist/containers/Tenant/Healthcheck/components/HealthcheckDrawer.js.map +1 -1
- package/dist/containers/Tenant/Query/QueryResult/components/Graph/Graph.js +9 -4
- package/dist/containers/Tenant/Query/QueryResult/components/Graph/Graph.js.map +1 -1
- package/dist/containers/Tenant/Query/QueryResult/components/Graph/Graph.scss +2 -0
- package/dist/containers/Tenant/TenantNavigation/useTenantNavigation.d.ts +1 -1
- package/dist/graphLayout.worker.d.ts +1 -0
- package/dist/graphLayout.worker.js +17 -0
- package/dist/graphLayout.worker.js.map +1 -0
- package/dist/lib.d.ts +1 -1
- package/dist/lib.js.map +1 -1
- package/dist/store/reducers/query/parsers/preparePlanData.js.map +1 -1
- package/dist/store/reducers/query/types.d.ts +38 -1
- package/dist/store/reducers/settings/utils.d.ts +2 -2
- package/dist/store/reducers/storage/utils.js +3 -3
- package/dist/store/reducers/storage/utils.js.map +1 -1
- package/dist/uiFactory/types.d.ts +9 -0
- package/dist/uiFactory/uiFactory.js +5 -2
- package/dist/uiFactory/uiFactory.js.map +1 -1
- package/dist/utils/disks/helpers.d.ts +2 -2
- package/dist/utils/hooks/useChangedQuerySettings.d.ts +2 -2
- package/dist/utils/hooks/useLastQueryExecutionSettings.d.ts +2 -2
- package/dist/utils/hooks/useQueryExecutionSettings.d.ts +2 -2
- package/dist/utils/prepareQueryExplain.d.ts +1 -2
- package/dist/utils/prepareQueryExplain.js +10 -2
- package/dist/utils/prepareQueryExplain.js.map +1 -1
- package/dist/utils/query.d.ts +1 -1
- package/package.json +3 -3
- package/src/components/CriticalActionDialog/CriticalActionDialog.tsx +12 -25
- package/src/components/CriticalActionDialog/i18n/en.json +1 -2
- package/src/components/DropdownMenu/DropdownMenu.tsx +3 -2
- package/src/components/Graph/BlockComponents/ConnectionBlockComponent.tsx +49 -0
- package/src/components/Graph/BlockComponents/QueryBlockComponent.tsx +7 -0
- package/src/components/Graph/BlockComponents/ResultBlockComponent.tsx +10 -0
- package/src/components/Graph/BlockComponents/StageBlockComponent.tsx +35 -0
- package/src/components/Graph/FullViewportBackground.ts +122 -0
- package/src/components/Graph/GraphControls.tsx +49 -0
- package/src/components/Graph/GravityGraph.scss +131 -0
- package/src/components/Graph/GravityGraph.tsx +174 -0
- package/src/components/Graph/NonSelectableConnection.tsx +14 -0
- package/src/components/Graph/TooltipComponent.tsx +114 -0
- package/src/components/Graph/colorsConfig.ts +21 -0
- package/src/components/Graph/i18n/en.json +5 -0
- package/src/components/Graph/i18n/index.ts +7 -0
- package/src/components/Graph/runTreeLayout.ts +105 -0
- package/src/components/Graph/treeLayout.ts +378 -0
- package/src/components/Graph/types.ts +56 -0
- package/src/components/Graph/utils.ts +112 -0
- package/src/containers/Header/HeaderActionsMenu.tsx +22 -2
- package/src/containers/Header/hooks/useSharedDatabasePath.ts +33 -26
- package/src/containers/Header/i18n/en.json +1 -0
- package/src/containers/Operations/columns.tsx +4 -0
- package/src/containers/Operations/i18n/en.json +2 -2
- package/src/containers/PDiskPage/DecommissionButton/DecommissionButton.tsx +2 -0
- package/src/containers/PDiskPage/PDiskPage.tsx +3 -1
- package/src/containers/PDiskPage/i18n/en.json +3 -3
- package/src/containers/Storage/PDisks/PDisks.tsx +1 -1
- package/src/containers/Tablet/components/TabletControls/TabletControls.tsx +7 -1
- package/src/containers/Tablet/i18n/en.json +3 -3
- package/src/containers/Tablets/TabletsTable.tsx +3 -1
- package/src/containers/Tablets/i18n/en.json +1 -1
- package/src/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +3 -1
- package/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +2 -2
- package/src/containers/Tenant/Healthcheck/components/HealthcheckDrawer.tsx +16 -1
- package/src/containers/Tenant/Query/QueryResult/components/Graph/Graph.scss +2 -0
- package/src/containers/Tenant/Query/QueryResult/components/Graph/Graph.tsx +13 -7
- package/src/graphLayout.worker.ts +21 -0
- package/src/lib.ts +1 -0
- package/src/store/reducers/query/parsers/preparePlanData.ts +1 -3
- package/src/store/reducers/query/types.ts +42 -2
- package/src/store/reducers/storage/utils.ts +3 -3
- package/src/uiFactory/types.ts +10 -0
- package/src/uiFactory/uiFactory.ts +12 -2
- package/src/utils/prepareQueryExplain.ts +13 -5
- package/dist/components/Graph/Graph.d.ts +0 -12
- package/dist/components/Graph/Graph.js +0 -44
- package/dist/components/Graph/Graph.js.map +0 -1
- package/dist/components/Graph/colors.d.ts +0 -10
- package/dist/components/Graph/colors.js +0 -53
- package/dist/components/Graph/colors.js.map +0 -1
- package/src/components/Graph/Graph.tsx +0 -70
- package/src/components/Graph/colors.ts +0 -75
|
@@ -132,28 +132,30 @@ export function useSharedDatabasePath({
|
|
|
132
132
|
const shouldResolveSharedDatabaseFromViewer =
|
|
133
133
|
shouldResolveSharedDatabaseName && !window.api.meta;
|
|
134
134
|
|
|
135
|
-
const {currentData: sharedDatabaseFromViewer} =
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
135
|
+
const {currentData: sharedDatabaseFromViewer, isFetching: isSharedDatabaseFromViewerFetching} =
|
|
136
|
+
tenantsApi.useGetSharedDatabaseQuery(
|
|
137
|
+
shouldResolveSharedDatabaseFromViewer && databaseData?.ResourceId
|
|
138
|
+
? {
|
|
139
|
+
clusterName,
|
|
140
|
+
database: databaseData.Name,
|
|
141
|
+
backend: activeBackend,
|
|
142
|
+
environmentName: environment,
|
|
143
|
+
isMonitoringAllowed: isMonitoringAllowed === true,
|
|
144
|
+
needNodeIds: needSharedDatabaseNodeIds,
|
|
145
|
+
resourceId: databaseData.ResourceId,
|
|
146
|
+
}
|
|
147
|
+
: skipToken,
|
|
148
|
+
);
|
|
148
149
|
|
|
149
150
|
const shouldResolveSharedDatabaseFromMetaList =
|
|
150
151
|
shouldResolveSharedDatabaseName && Boolean(window.api.meta);
|
|
151
152
|
|
|
152
|
-
const {currentData: databases} =
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
const {currentData: databases, isFetching: isDatabasesFetching} =
|
|
154
|
+
tenantsApi.useGetTenantsInfoQuery(
|
|
155
|
+
shouldResolveSharedDatabaseFromMetaList
|
|
156
|
+
? {clusterName, environmentName: environment, isMetaDatabasesAvailable}
|
|
157
|
+
: skipToken,
|
|
158
|
+
);
|
|
157
159
|
|
|
158
160
|
const sharedDatabaseTarget = React.useMemo<SharedDatabaseTarget | undefined>(() => {
|
|
159
161
|
if (databaseData?.sharedTenantName) {
|
|
@@ -184,12 +186,17 @@ export function useSharedDatabasePath({
|
|
|
184
186
|
const sharedDatabase = useDatabaseId ? databaseData?.ResourceId : sharedDatabaseTarget?.name;
|
|
185
187
|
const backend = getSharedDatabaseBackend(sharedDatabaseTarget, prepareTenantBackend);
|
|
186
188
|
|
|
187
|
-
return
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
189
|
+
return {
|
|
190
|
+
isSharedDatabaseLoading:
|
|
191
|
+
(isSharedDatabaseFromViewerFetching && sharedDatabaseFromViewer === undefined) ||
|
|
192
|
+
(isDatabasesFetching && databases === undefined),
|
|
193
|
+
sharedDatabasePath: getResolvedSharedDatabasePath({
|
|
194
|
+
backend,
|
|
195
|
+
clusterName,
|
|
196
|
+
databaseData,
|
|
197
|
+
isClusterBaseInfoResolved: isClusterBaseInfoAvailable,
|
|
198
|
+
isViewerUser,
|
|
199
|
+
sharedDatabase,
|
|
200
|
+
}),
|
|
201
|
+
};
|
|
195
202
|
}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"action_delete-cluster": "Delete Cluster",
|
|
17
17
|
"action_connect-to-db": "Connect to database",
|
|
18
18
|
"action_go-to-shared-db": "Go to shared database",
|
|
19
|
+
"status_loading-shared-db": "Loading shared database",
|
|
19
20
|
"action_manage": "Manage",
|
|
20
21
|
|
|
21
22
|
"title_developer-ui": "Developer UI",
|
|
@@ -216,6 +216,8 @@ function OperationsActions({operation, database}: OperationsActionsProps) {
|
|
|
216
216
|
buttonView="outlined"
|
|
217
217
|
dialogHeader={i18n('header_forget')}
|
|
218
218
|
dialogText={i18n('text_forget')}
|
|
219
|
+
applyButtonText={i18n('header_forget')}
|
|
220
|
+
applyButtonView="outlined-danger"
|
|
219
221
|
onConfirmAction={() =>
|
|
220
222
|
forgetOperation({id, database})
|
|
221
223
|
.unwrap()
|
|
@@ -244,6 +246,8 @@ function OperationsActions({operation, database}: OperationsActionsProps) {
|
|
|
244
246
|
buttonView="outlined"
|
|
245
247
|
dialogHeader={i18n('header_cancel')}
|
|
246
248
|
dialogText={i18n('text_cancel')}
|
|
249
|
+
applyButtonText={i18n('header_cancel')}
|
|
250
|
+
applyButtonView="outlined-danger"
|
|
247
251
|
onConfirmAction={() =>
|
|
248
252
|
cancelOperation({id, database})
|
|
249
253
|
.unwrap()
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"value_progress_create_changefeeds": "Creating Changefeeds",
|
|
34
34
|
"header_cancel": "Cancel operation",
|
|
35
35
|
"header_forget": "Forget operation",
|
|
36
|
-
"text_cancel": "
|
|
37
|
-
"text_forget": "
|
|
36
|
+
"text_cancel": "This will cancel the operation in progress. This action cannot be undone.",
|
|
37
|
+
"text_forget": "This will remove the operation from the list. This action cannot be undone.",
|
|
38
38
|
"text_forgotten": "The operation {{id}} has been forgotten",
|
|
39
39
|
"text_cancelled": "The operation {{id}} has been cancelled"
|
|
40
40
|
}
|
|
@@ -139,6 +139,8 @@ export function DecommissionButton({
|
|
|
139
139
|
warningText={getDecommissionWarningText(newDecommission)}
|
|
140
140
|
withRetry={withRetry}
|
|
141
141
|
withCheckBox
|
|
142
|
+
applyButtonText={pDiskPageKeyset('decommission-dialog-title')}
|
|
143
|
+
applyButtonView="outlined-danger"
|
|
142
144
|
retryButtonText={pDiskPageKeyset('decommission-dialog-force-change')}
|
|
143
145
|
onConfirm={handleConfirmAction}
|
|
144
146
|
onConfirmActionSuccess={handleConfirmActionSuccess}
|
|
@@ -187,7 +187,9 @@ export function PDiskPage() {
|
|
|
187
187
|
buttonDisabled={!pDiskParamsDefined || !isUserAllowedToMakeChanges}
|
|
188
188
|
buttonView="normal"
|
|
189
189
|
dialogHeader={pDiskPageKeyset('restart-pdisk-dialog-header')}
|
|
190
|
-
|
|
190
|
+
dialogText={pDiskPageKeyset('restart-pdisk-dialog-text')}
|
|
191
|
+
applyButtonText={pDiskPageKeyset('restart-pdisk-button')}
|
|
192
|
+
applyButtonView="action"
|
|
191
193
|
retryButtonText={pDiskPageKeyset('force-restart-pdisk-button')}
|
|
192
194
|
withPopover
|
|
193
195
|
popoverContent={pDiskPageKeyset('restart-pdisk-not-allowed')}
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
"no-slots-data": "No slots data",
|
|
17
17
|
|
|
18
18
|
"restart-pdisk-button": "Restart PDisk",
|
|
19
|
-
"force-restart-pdisk-button": "Restart anyway",
|
|
19
|
+
"force-restart-pdisk-button": "Restart PDisk anyway",
|
|
20
20
|
"restart-pdisk-not-allowed": "You don't have enough rights to restart PDisk",
|
|
21
21
|
|
|
22
22
|
"restart-pdisk-dialog-header": "Restart PDisk",
|
|
23
|
-
"restart-pdisk-dialog-text": "
|
|
23
|
+
"restart-pdisk-dialog-text": "Are you sure you want to restart this PDisk?",
|
|
24
24
|
|
|
25
25
|
"decommission-none": "None",
|
|
26
26
|
"decommission-imminent": "Imminent",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"decommission-dialog-title": "Change decommission status",
|
|
35
35
|
"decommission-dialog-force-change": "Change anyway",
|
|
36
36
|
|
|
37
|
-
"decommission-dialog-imminent-warning": "This will start imminent decommission.
|
|
37
|
+
"decommission-dialog-imminent-warning": "This will start imminent decommission. All existing slots will be moved from the disk.",
|
|
38
38
|
"decommission-dialog-pending-warning": "This will start pending decommission. Decommission will be planned for this disk, but will not start immediatelly. Existing slots will not be moved from the disk, but no new slots will be allocated on it",
|
|
39
39
|
"decommission-dialog-rejected-warning": "This will start rejected decommission. No slots from other disks are placed on this disk in the process of decommission",
|
|
40
40
|
"decommission-dialog-none-warning": "This will reset decommission mode, allowing the disk to be used by the storage"
|
|
@@ -31,7 +31,7 @@ export function PDisks({pDisks = [], vDisks = [], viewContext, pDiskWidth}: PDis
|
|
|
31
31
|
|
|
32
32
|
const relatedVDisks = vDisks.filter((vdisk) => vdisk.PDiskId === pDisk.PDiskId);
|
|
33
33
|
|
|
34
|
-
const highlighted = highlightedDisk === id;
|
|
34
|
+
const highlighted = id !== undefined && highlightedDisk === id;
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
37
|
<div className={b('pdisks-item')} key={id}>
|
|
@@ -42,7 +42,9 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
|
42
42
|
<Flex gap={2} wrap="nowrap">
|
|
43
43
|
<ButtonWithConfirmDialog
|
|
44
44
|
dialogHeader={i18n('dialog.kill-header')}
|
|
45
|
-
|
|
45
|
+
dialogText={i18n('dialog.kill-text')}
|
|
46
|
+
applyButtonText={i18n('dialog.kill-header')}
|
|
47
|
+
applyButtonView="action"
|
|
46
48
|
onConfirmAction={() => killTablet({id: TabletId}).unwrap()}
|
|
47
49
|
buttonDisabled={isDisabledRestart || !isUserAllowedToMakeChanges}
|
|
48
50
|
withPopover
|
|
@@ -59,6 +61,8 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
|
59
61
|
<ButtonWithConfirmDialog
|
|
60
62
|
dialogHeader={i18n('dialog.stop-header')}
|
|
61
63
|
dialogText={i18n('dialog.stop-text')}
|
|
64
|
+
applyButtonText={i18n('dialog.stop-header')}
|
|
65
|
+
applyButtonView="outlined-danger"
|
|
62
66
|
onConfirmAction={() => stopTablet({id: TabletId, hiveId: HiveId}).unwrap()}
|
|
63
67
|
buttonDisabled={isDisabledStop || !isUserAllowedToMakeChanges}
|
|
64
68
|
withPopover
|
|
@@ -73,6 +77,8 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
|
|
|
73
77
|
<ButtonWithConfirmDialog
|
|
74
78
|
dialogHeader={i18n('dialog.resume-header')}
|
|
75
79
|
dialogText={i18n('dialog.resume-text')}
|
|
80
|
+
applyButtonText={i18n('dialog.resume-header')}
|
|
81
|
+
applyButtonView="action"
|
|
76
82
|
onConfirmAction={() =>
|
|
77
83
|
resumeTablet({id: TabletId, hiveId: HiveId}).unwrap()
|
|
78
84
|
}
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"dialog.stop-header": "Stop tablet",
|
|
17
17
|
"dialog.resume-header": "Resume tablet",
|
|
18
18
|
|
|
19
|
-
"dialog.kill-text": "The tablet will be
|
|
20
|
-
"dialog.stop-text": "The tablet will be stopped.
|
|
21
|
-
"dialog.resume-text": "The tablet will be resumed
|
|
19
|
+
"dialog.kill-text": "The tablet will restart. A portion of table data will be temporarily unavailable. Active transactions and scans will be interrupted with a retriable error and can be retried.",
|
|
20
|
+
"dialog.stop-text": "The tablet will be stopped. The key range will be unavailable until the tablet is manually resumed. Data is not deleted and will be restored after resume.",
|
|
21
|
+
"dialog.resume-text": "The tablet will be resumed and return to Active state.",
|
|
22
22
|
|
|
23
23
|
"emptyState": "The tablet was not found",
|
|
24
24
|
|
|
@@ -190,7 +190,9 @@ function TabletActions(tablet: TTabletStateInfo) {
|
|
|
190
190
|
<ButtonWithConfirmDialog
|
|
191
191
|
buttonView="outlined"
|
|
192
192
|
dialogHeader={i18n('dialog.kill-header')}
|
|
193
|
-
|
|
193
|
+
dialogText={i18n('dialog.kill-text')}
|
|
194
|
+
applyButtonText={i18n('dialog.kill-header')}
|
|
195
|
+
applyButtonView="action"
|
|
194
196
|
onConfirmAction={() => {
|
|
195
197
|
return killTablet({id}).unwrap();
|
|
196
198
|
}}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"Generation": "Generation",
|
|
11
11
|
"Uptime": "Uptime",
|
|
12
12
|
"dialog.kill-header": "Restart tablet",
|
|
13
|
-
"dialog.kill-text": "The tablet will be
|
|
13
|
+
"dialog.kill-text": "The tablet will restart. A portion of table data will be temporarily unavailable. Active transactions and scans will be interrupted with a retriable error and can be retried.",
|
|
14
14
|
"controls.kill-not-allowed": "You don't have enough rights to restart tablet",
|
|
15
15
|
"controls.kill-impossible-follower": "It's impossible to restart a follower",
|
|
16
16
|
"controls.search-placeholder": "Tablet ID",
|
|
@@ -7,6 +7,7 @@ import {healthcheckApi} from '../../../../../store/reducers/healthcheckInfo/heal
|
|
|
7
7
|
import {SelfCheckResult} from '../../../../../types/api/healthcheck';
|
|
8
8
|
import {cn} from '../../../../../utils/cn';
|
|
9
9
|
import {useAutoRefreshInterval} from '../../../../../utils/hooks';
|
|
10
|
+
import {useClusterNameFromQuery} from '../../../../../utils/hooks/useDatabaseFromQuery';
|
|
10
11
|
import {isEnumMember} from '../../../../../utils/typecheckers';
|
|
11
12
|
import {HEALTHCHECK_RESULT_TO_TEXT} from '../../../constants';
|
|
12
13
|
import {useTenantQueryParams} from '../../../useTenantQueryParams';
|
|
@@ -24,6 +25,7 @@ interface HealthcheckPreviewProps {
|
|
|
24
25
|
|
|
25
26
|
export function HealthcheckPreview(props: HealthcheckPreviewProps) {
|
|
26
27
|
const {database} = props;
|
|
28
|
+
const clusterName = useClusterNameFromQuery();
|
|
27
29
|
const [autoRefreshInterval] = useAutoRefreshInterval();
|
|
28
30
|
|
|
29
31
|
const {handleShowHealthcheckChange} = useTenantQueryParams();
|
|
@@ -33,7 +35,7 @@ export function HealthcheckPreview(props: HealthcheckPreviewProps) {
|
|
|
33
35
|
isFetching,
|
|
34
36
|
error,
|
|
35
37
|
} = healthcheckApi.useGetHealthcheckInfoQuery(
|
|
36
|
-
{database},
|
|
38
|
+
{database, clusterName},
|
|
37
39
|
{
|
|
38
40
|
pollingInterval: autoRefreshInterval,
|
|
39
41
|
},
|
|
@@ -311,11 +311,11 @@ export function TenantOverview({
|
|
|
311
311
|
|
|
312
312
|
// Use healthcheck self_check_result as the database status color when available;
|
|
313
313
|
// fall back to tenantinfo.Overall (e.g. for Serverless databases where healthcheck is skipped).
|
|
314
|
-
// Polling is managed by HealthcheckPreview
|
|
314
|
+
// Polling is managed by HealthcheckPreview via the same {database, clusterName} cache key. The database
|
|
315
315
|
// status badge is only rendered when !isV2NavigationEnabled, so skip the query in V2 mode
|
|
316
316
|
// and until tenant info is loaded to avoid spurious requests.
|
|
317
317
|
const {currentData: healthcheckData} = healthcheckApi.useGetHealthcheckInfoQuery(
|
|
318
|
-
{database},
|
|
318
|
+
{database, clusterName},
|
|
319
319
|
{
|
|
320
320
|
skip: shouldSkipHealthcheck({isServerless, isV2NavigationEnabled, tenant}),
|
|
321
321
|
},
|
|
@@ -7,6 +7,7 @@ import {DrawerWrapper} from '../../../../components/Drawer';
|
|
|
7
7
|
import type {DrawerControl} from '../../../../components/Drawer';
|
|
8
8
|
import {EnableFullscreenButton} from '../../../../components/EnableFullscreenButton/EnableFullscreenButton';
|
|
9
9
|
import type {SelfCheckResult} from '../../../../types/api/healthcheck';
|
|
10
|
+
import {uiFactory} from '../../../../uiFactory/uiFactory';
|
|
10
11
|
import {createAndDownloadJsonFile} from '../../../../utils/downloadFile';
|
|
11
12
|
|
|
12
13
|
import {HealthcheckDrawerTitle} from './HealthcheckDrawerTitle';
|
|
@@ -42,6 +43,20 @@ export function HealthcheckDrawer({
|
|
|
42
43
|
downloadTooltip,
|
|
43
44
|
isDownloadDisabled,
|
|
44
45
|
}: HealthcheckDrawerProps) {
|
|
46
|
+
const renderDrawerExtension = uiFactory.healthcheck.renderDrawerExtension;
|
|
47
|
+
const renderContentWithExtension = React.useCallback(() => {
|
|
48
|
+
if (!renderDrawerExtension) {
|
|
49
|
+
return renderDrawerContent();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<React.Fragment>
|
|
54
|
+
{renderDrawerExtension()}
|
|
55
|
+
{renderDrawerContent()}
|
|
56
|
+
</React.Fragment>
|
|
57
|
+
);
|
|
58
|
+
}, [renderDrawerContent, renderDrawerExtension]);
|
|
59
|
+
|
|
45
60
|
const handleDownload = React.useCallback(
|
|
46
61
|
(event: React.MouseEvent<HTMLButtonElement>) => {
|
|
47
62
|
event.stopPropagation();
|
|
@@ -86,7 +101,7 @@ export function HealthcheckDrawer({
|
|
|
86
101
|
isDrawerVisible={isDrawerVisible}
|
|
87
102
|
onCloseDrawer={onCloseDrawer}
|
|
88
103
|
onTransitionInComplete={onTransitionInComplete}
|
|
89
|
-
renderDrawerContent={
|
|
104
|
+
renderDrawerContent={renderContentWithExtension}
|
|
90
105
|
drawerId={drawerId}
|
|
91
106
|
storageKey={storageKey}
|
|
92
107
|
detectClickOutside
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import {YDBGraph} from '../../../../../../components/Graph/Graph';
|
|
3
|
+
import {GravityGraph} from '../../../../../../components/Graph/GravityGraph';
|
|
6
4
|
import type {PreparedPlan} from '../../../../../../store/reducers/query/types';
|
|
7
5
|
import {cn} from '../../../../../../utils/cn';
|
|
8
6
|
import i18n from '../../i18n';
|
|
@@ -17,22 +15,30 @@ interface GraphProps {
|
|
|
17
15
|
theme?: string;
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
function isValidGraphData(data: Partial<
|
|
18
|
+
function isValidGraphData(data: Partial<PreparedPlan>) {
|
|
21
19
|
return Boolean(data.links && data.nodes && data.nodes.length);
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
export function Graph({explain = {}, theme}: GraphProps) {
|
|
25
23
|
const {links, nodes} = explain;
|
|
26
24
|
|
|
27
|
-
const data = React.useMemo(() => ({links, nodes}), [links, nodes]);
|
|
25
|
+
const data = React.useMemo(() => ({links: links || [], nodes: nodes || []}), [links, nodes]);
|
|
26
|
+
const [failedData, setFailedData] = React.useState<typeof data>();
|
|
27
|
+
const handleLayoutError = React.useCallback(
|
|
28
|
+
(error: Error) => {
|
|
29
|
+
console.error(error);
|
|
30
|
+
setFailedData(data);
|
|
31
|
+
},
|
|
32
|
+
[data],
|
|
33
|
+
);
|
|
28
34
|
|
|
29
|
-
if (!isValidGraphData(data)) {
|
|
35
|
+
if (!isValidGraphData(data) || failedData === data) {
|
|
30
36
|
return <StubMessage message={i18n('description.graph-is-not-supported')} />;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
return (
|
|
34
40
|
<div className={b('canvas-container')}>
|
|
35
|
-
<
|
|
41
|
+
<GravityGraph data={data} onError={handleLayoutError} theme={theme} />
|
|
36
42
|
</div>
|
|
37
43
|
);
|
|
38
44
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {prepareTreeLayout} from './components/Graph/treeLayout';
|
|
2
|
+
import type {TreeLayoutRequest, TreeLayoutWorkerResponse} from './components/Graph/types';
|
|
3
|
+
|
|
4
|
+
const workerScope = globalThis as unknown as {
|
|
5
|
+
onmessage: ((event: MessageEvent<TreeLayoutRequest>) => void) | null;
|
|
6
|
+
postMessage: (response: TreeLayoutWorkerResponse) => void;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
workerScope.onmessage = ({data}) => {
|
|
10
|
+
try {
|
|
11
|
+
workerScope.postMessage({
|
|
12
|
+
type: 'success',
|
|
13
|
+
result: prepareTreeLayout(data),
|
|
14
|
+
});
|
|
15
|
+
} catch (error) {
|
|
16
|
+
workerScope.postMessage({
|
|
17
|
+
type: 'error',
|
|
18
|
+
error: error instanceof Error ? error.message : String(error),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
};
|
package/src/lib.ts
CHANGED
|
@@ -40,6 +40,7 @@ export type {ExternalQueryToOpen} from './containers/Tenant/Query/hooks/useOpenE
|
|
|
40
40
|
export type {DrawerContextType} from './components/Drawer';
|
|
41
41
|
export type {GetMonitoringLink, GetMonitoringClusterLink} from './utils/monitoring';
|
|
42
42
|
export type {
|
|
43
|
+
CreateGraphLayoutWorker,
|
|
43
44
|
GetAdditionalDatabaseInfoItems,
|
|
44
45
|
GetReportProblemUrl,
|
|
45
46
|
IllustrationComponent,
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import type {ExplainPlanNodeData, GraphNode, Link} from '@gravity-ui/paranoid';
|
|
2
|
-
|
|
3
1
|
import type {QueryPlan, ScriptPlan, TKqpStatsQuery} from '../../../../types/api/query';
|
|
4
2
|
import {preparePlan, prepareSimplifiedPlan} from '../../../../utils/prepareQueryExplain';
|
|
5
3
|
import {parseQueryExplainPlan} from '../../../../utils/query';
|
|
6
|
-
import type {PreparedQueryData} from '../types';
|
|
4
|
+
import type {ExplainPlanNodeData, GraphNode, Link, PreparedQueryData} from '../types';
|
|
7
5
|
|
|
8
6
|
const explainVersions = {
|
|
9
7
|
v2: '0.2',
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type {ExplainPlanNodeData, GraphNode, Link} from '@gravity-ui/paranoid';
|
|
2
|
-
|
|
3
1
|
import type {
|
|
4
2
|
PlanTable,
|
|
5
3
|
QueryPlan,
|
|
@@ -27,6 +25,48 @@ export interface QueryInHistory extends RawQueryInHistory {
|
|
|
27
25
|
status?: QueryExecutionStatusType;
|
|
28
26
|
}
|
|
29
27
|
|
|
28
|
+
export interface Link {
|
|
29
|
+
from: string;
|
|
30
|
+
to: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface Metric {
|
|
34
|
+
name: string;
|
|
35
|
+
value: string;
|
|
36
|
+
theme?: 'warning' | 'danger';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface GraphNode<TData = any> {
|
|
40
|
+
name: string;
|
|
41
|
+
status?: string;
|
|
42
|
+
meta?: string;
|
|
43
|
+
group?: string;
|
|
44
|
+
data?: TData;
|
|
45
|
+
metrics?: Metric[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ExplainPlanNodeData {
|
|
49
|
+
id?: number;
|
|
50
|
+
type: 'query' | 'result' | 'stage' | 'connection' | 'materialize';
|
|
51
|
+
name?: string;
|
|
52
|
+
operators?: string[];
|
|
53
|
+
tables?: string[];
|
|
54
|
+
cte?: string;
|
|
55
|
+
stats?: TopologyNodeDataStats[];
|
|
56
|
+
}
|
|
57
|
+
export interface TopologyNodeDataStatsItem {
|
|
58
|
+
name: string;
|
|
59
|
+
value: string | number;
|
|
60
|
+
}
|
|
61
|
+
export interface TopologyNodeDataStatsSection {
|
|
62
|
+
name: string;
|
|
63
|
+
items: TopologyNodeDataStatsItem[];
|
|
64
|
+
}
|
|
65
|
+
export interface TopologyNodeDataStats {
|
|
66
|
+
group: string;
|
|
67
|
+
stats: TopologyNodeDataStatsSection[] | TopologyNodeDataStatsItem[];
|
|
68
|
+
}
|
|
69
|
+
|
|
30
70
|
export interface PreparedPlan {
|
|
31
71
|
links?: Link[];
|
|
32
72
|
nodes?: GraphNode<ExplainPlanNodeData>[];
|
|
@@ -237,10 +237,10 @@ const prepareStorageNodeData = (
|
|
|
237
237
|
}).length || 0;
|
|
238
238
|
|
|
239
239
|
const pDisks = PDisks?.map((pDisk) => {
|
|
240
|
-
return {
|
|
241
|
-
...
|
|
240
|
+
return prepareWhiteboardPDiskData({
|
|
241
|
+
...pDisk,
|
|
242
242
|
NodeId,
|
|
243
|
-
};
|
|
243
|
+
});
|
|
244
244
|
});
|
|
245
245
|
const vDisks = VDisks?.map((vDisk) => {
|
|
246
246
|
return {
|
package/src/uiFactory/types.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type {GetLogsLink} from '../utils/logs';
|
|
|
19
19
|
import type {GetMonitoringClusterLink, GetMonitoringLink} from '../utils/monitoring';
|
|
20
20
|
|
|
21
21
|
export type IllustrationComponent = React.ComponentType<React.SVGProps<SVGSVGElement>>;
|
|
22
|
+
export type CreateGraphLayoutWorker = () => Worker;
|
|
22
23
|
|
|
23
24
|
export type IllustrationName =
|
|
24
25
|
| 'InternalError'
|
|
@@ -52,14 +53,23 @@ export interface UIFactory<H extends string = CommonIssueCategory, T extends str
|
|
|
52
53
|
renderNodeTooltipActions?: RenderNodeTooltipActions;
|
|
53
54
|
clusterOrDatabaseAccessError?: Partial<EmptyStateProps>;
|
|
54
55
|
|
|
56
|
+
/** Defaults to true. Undefined preserves the current value when configuring the UI. */
|
|
55
57
|
enableMultiTabQueryEditor?: boolean;
|
|
56
58
|
|
|
59
|
+
/** Creates a fresh computation-graph layout worker for each layout run. */
|
|
60
|
+
createGraphLayoutWorker?: CreateGraphLayoutWorker;
|
|
61
|
+
|
|
57
62
|
healthcheck: {
|
|
58
63
|
issueCategories: ReadonlyArray<H>;
|
|
59
64
|
isIssueTypeOfCategory: (type: string, category: H) => boolean;
|
|
60
65
|
getHealthckechViewTitles: GetHealthcheckViewTitles<H>;
|
|
61
66
|
getHealthcheckViewsOrder: GetHealthcheckViewsOrder<H>;
|
|
62
67
|
renderAssistantAction?: RenderHealthcheckAssistantAction;
|
|
68
|
+
/**
|
|
69
|
+
* Renders after the drawer header and before Healthcheck content.
|
|
70
|
+
* Stays mounted while the drawer is open, independent of loading, error or issue state.
|
|
71
|
+
*/
|
|
72
|
+
renderDrawerExtension?: () => React.ReactNode;
|
|
63
73
|
};
|
|
64
74
|
hasAccess: HasAccess;
|
|
65
75
|
hideGrantAccess?: boolean;
|
|
@@ -30,7 +30,7 @@ const uiFactoryBase: ResolvedUIFactory = {
|
|
|
30
30
|
useDatabaseId: false,
|
|
31
31
|
settingsBackend: undefined,
|
|
32
32
|
docs: undefined,
|
|
33
|
-
enableMultiTabQueryEditor:
|
|
33
|
+
enableMultiTabQueryEditor: true,
|
|
34
34
|
hasDeveloperUi: true,
|
|
35
35
|
isDetailedStorageViewAvailable: () => true,
|
|
36
36
|
maxVDisksInStorageGroup: 9,
|
|
@@ -46,10 +46,20 @@ type UIFactoryOverrides<H extends string, T extends string> = Omit<
|
|
|
46
46
|
export function configureUIFactory<H extends string, T extends string = string>(
|
|
47
47
|
overrides: UIFactoryOverrides<H, T>,
|
|
48
48
|
) {
|
|
49
|
-
const {
|
|
49
|
+
const {
|
|
50
|
+
healthcheck,
|
|
51
|
+
hasAccess,
|
|
52
|
+
maxVDisksInStorageGroup,
|
|
53
|
+
enableMultiTabQueryEditor,
|
|
54
|
+
...restOverrides
|
|
55
|
+
} = overrides;
|
|
50
56
|
|
|
51
57
|
Object.assign(uiFactoryBase, restOverrides);
|
|
52
58
|
|
|
59
|
+
if (typeof enableMultiTabQueryEditor === 'boolean') {
|
|
60
|
+
uiFactoryBase.enableMultiTabQueryEditor = enableMultiTabQueryEditor;
|
|
61
|
+
}
|
|
62
|
+
|
|
53
63
|
// Only override hasAccess when an actual function is provided.
|
|
54
64
|
// Forwarding an optional config field could pass `undefined` here,
|
|
55
65
|
// which would overwrite the default and crash on the next hasAccess(...) call.
|
|
@@ -2,12 +2,11 @@ import type {
|
|
|
2
2
|
ExplainPlanNodeData,
|
|
3
3
|
GraphNode,
|
|
4
4
|
Link,
|
|
5
|
+
SimplifiedPlanItem,
|
|
5
6
|
TopologyNodeDataStats,
|
|
6
7
|
TopologyNodeDataStatsItem,
|
|
7
8
|
TopologyNodeDataStatsSection,
|
|
8
|
-
} from '
|
|
9
|
-
|
|
10
|
-
import type {SimplifiedPlanItem} from '../store/reducers/query/types';
|
|
9
|
+
} from '../store/reducers/query/types';
|
|
11
10
|
import type {PlanNode, SimplifiedNode} from '../types/api/query';
|
|
12
11
|
|
|
13
12
|
const CONNECTION_NODE_META_FIELDS = new Set(['PlanNodeId', 'PlanNodeType', 'Node Type', 'Plans']);
|
|
@@ -96,11 +95,19 @@ function getNodeType(plan: PlanNode) {
|
|
|
96
95
|
export function preparePlan(plan: PlanNode) {
|
|
97
96
|
const nodes: GraphNode<ExplainPlanNodeData>[] = [];
|
|
98
97
|
const links: Link[] = [];
|
|
98
|
+
let generatedNodeId = 0;
|
|
99
|
+
|
|
100
|
+
const getGraphNodeId = (node: PlanNode) => {
|
|
101
|
+
return node.PlanNodeId === undefined
|
|
102
|
+
? `generated-plan-node:${generatedNodeId++}`
|
|
103
|
+
: String(node.PlanNodeId);
|
|
104
|
+
};
|
|
99
105
|
|
|
100
106
|
function parsePlans(plans: PlanNode[] = [], from: string) {
|
|
101
107
|
plans.forEach((p) => {
|
|
108
|
+
const nodeId = getGraphNodeId(p);
|
|
102
109
|
const node: GraphNode<ExplainPlanNodeData> = {
|
|
103
|
-
name:
|
|
110
|
+
name: nodeId,
|
|
104
111
|
data: {
|
|
105
112
|
id: p.PlanNodeId,
|
|
106
113
|
type: getNodeType(p),
|
|
@@ -117,8 +124,9 @@ export function preparePlan(plan: PlanNode) {
|
|
|
117
124
|
}
|
|
118
125
|
|
|
119
126
|
const rootPlan = plan;
|
|
127
|
+
const rootNodeId = getGraphNodeId(rootPlan);
|
|
120
128
|
const rootNode: GraphNode<ExplainPlanNodeData> = {
|
|
121
|
-
name:
|
|
129
|
+
name: rootNodeId,
|
|
122
130
|
data: {
|
|
123
131
|
id: rootPlan.PlanNodeId,
|
|
124
132
|
type: getNodeType(rootPlan),
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { Data, Options, Shapes } from '@gravity-ui/paranoid';
|
|
2
|
-
interface GraphProps<T> {
|
|
3
|
-
data: Data<T>;
|
|
4
|
-
opts?: Options;
|
|
5
|
-
shapes?: Shapes;
|
|
6
|
-
}
|
|
7
|
-
export declare function Graph<T>(props: GraphProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
interface YDBGraphProps<T> {
|
|
9
|
-
data: Data<T>;
|
|
10
|
-
}
|
|
11
|
-
export declare function YDBGraph<T>(props: YDBGraphProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
12
|
-
export {};
|