ydb-embedded-ui 21.0.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.
Files changed (64) hide show
  1. package/dist/components/CriticalActionDialog/CriticalActionDialog.js +10 -6
  2. package/dist/components/CriticalActionDialog/CriticalActionDialog.js.map +1 -1
  3. package/dist/components/CriticalActionDialog/i18n/en.json +1 -2
  4. package/dist/components/CriticalActionDialog/i18n/index.d.ts +1 -1
  5. package/dist/components/DropdownMenu/DropdownMenu.d.ts +2 -1
  6. package/dist/components/DropdownMenu/DropdownMenu.js +1 -1
  7. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  8. package/dist/containers/Header/HeaderActionsMenu.js +19 -3
  9. package/dist/containers/Header/HeaderActionsMenu.js.map +1 -1
  10. package/dist/containers/Header/hooks/useSharedDatabasePath.d.ts +4 -1
  11. package/dist/containers/Header/hooks/useSharedDatabasePath.js +14 -10
  12. package/dist/containers/Header/hooks/useSharedDatabasePath.js.map +1 -1
  13. package/dist/containers/Header/i18n/en.json +1 -0
  14. package/dist/containers/Header/i18n/index.d.ts +1 -1
  15. package/dist/containers/Operations/columns.js +2 -2
  16. package/dist/containers/Operations/columns.js.map +1 -1
  17. package/dist/containers/Operations/i18n/en.json +2 -2
  18. package/dist/containers/PDiskPage/DecommissionButton/DecommissionButton.js +1 -1
  19. package/dist/containers/PDiskPage/DecommissionButton/DecommissionButton.js.map +1 -1
  20. package/dist/containers/PDiskPage/PDiskPage.js +1 -1
  21. package/dist/containers/PDiskPage/PDiskPage.js.map +1 -1
  22. package/dist/containers/PDiskPage/i18n/en.json +3 -3
  23. package/dist/containers/Storage/PDisks/PDisks.js +1 -1
  24. package/dist/containers/Storage/PDisks/PDisks.js.map +1 -1
  25. package/dist/containers/Tablet/components/TabletControls/TabletControls.js +1 -1
  26. package/dist/containers/Tablet/components/TabletControls/TabletControls.js.map +1 -1
  27. package/dist/containers/Tablet/i18n/en.json +3 -3
  28. package/dist/containers/Tablets/TabletsTable.js +1 -1
  29. package/dist/containers/Tablets/TabletsTable.js.map +1 -1
  30. package/dist/containers/Tablets/i18n/en.json +1 -1
  31. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.js +3 -1
  32. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.js.map +1 -1
  33. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +2 -2
  34. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js.map +1 -1
  35. package/dist/containers/Tenant/Healthcheck/components/HealthcheckDrawer.js +10 -2
  36. package/dist/containers/Tenant/Healthcheck/components/HealthcheckDrawer.js.map +1 -1
  37. package/dist/store/reducers/storage/utils.js +3 -3
  38. package/dist/store/reducers/storage/utils.js.map +1 -1
  39. package/dist/uiFactory/types.d.ts +6 -0
  40. package/dist/uiFactory/uiFactory.js +5 -2
  41. package/dist/uiFactory/uiFactory.js.map +1 -1
  42. package/package.json +2 -2
  43. package/src/components/CriticalActionDialog/CriticalActionDialog.tsx +12 -25
  44. package/src/components/CriticalActionDialog/i18n/en.json +1 -2
  45. package/src/components/DropdownMenu/DropdownMenu.tsx +3 -2
  46. package/src/containers/Header/HeaderActionsMenu.tsx +22 -2
  47. package/src/containers/Header/hooks/useSharedDatabasePath.ts +33 -26
  48. package/src/containers/Header/i18n/en.json +1 -0
  49. package/src/containers/Operations/columns.tsx +4 -0
  50. package/src/containers/Operations/i18n/en.json +2 -2
  51. package/src/containers/PDiskPage/DecommissionButton/DecommissionButton.tsx +2 -0
  52. package/src/containers/PDiskPage/PDiskPage.tsx +3 -1
  53. package/src/containers/PDiskPage/i18n/en.json +3 -3
  54. package/src/containers/Storage/PDisks/PDisks.tsx +1 -1
  55. package/src/containers/Tablet/components/TabletControls/TabletControls.tsx +7 -1
  56. package/src/containers/Tablet/i18n/en.json +3 -3
  57. package/src/containers/Tablets/TabletsTable.tsx +3 -1
  58. package/src/containers/Tablets/i18n/en.json +1 -1
  59. package/src/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +3 -1
  60. package/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +2 -2
  61. package/src/containers/Tenant/Healthcheck/components/HealthcheckDrawer.tsx +16 -1
  62. package/src/store/reducers/storage/utils.ts +3 -3
  63. package/src/uiFactory/types.ts +6 -0
  64. package/src/uiFactory/uiFactory.ts +12 -2
@@ -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
- dialogWarning={i18n('dialog.kill-text')}
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 restarted. Do you want to proceed?",
20
- "dialog.stop-text": "The tablet will be stopped. Do you want to proceed?",
21
- "dialog.resume-text": "The tablet will be resumed. Do you want to proceed?",
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
- dialogWarning={i18n('dialog.kill-text')}
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 restarted. Do you want to proceed?",
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 (deduped via the same cache key); the database
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={renderDrawerContent}
104
+ renderDrawerContent={renderContentWithExtension}
90
105
  drawerId={drawerId}
91
106
  storageKey={storageKey}
92
107
  detectClickOutside
@@ -237,10 +237,10 @@ const prepareStorageNodeData = (
237
237
  }).length || 0;
238
238
 
239
239
  const pDisks = PDisks?.map((pDisk) => {
240
- return {
241
- ...prepareWhiteboardPDiskData(pDisk),
240
+ return prepareWhiteboardPDiskData({
241
+ ...pDisk,
242
242
  NodeId,
243
- };
243
+ });
244
244
  });
245
245
  const vDisks = VDisks?.map((vDisk) => {
246
246
  return {
@@ -53,6 +53,7 @@ export interface UIFactory<H extends string = CommonIssueCategory, T extends str
53
53
  renderNodeTooltipActions?: RenderNodeTooltipActions;
54
54
  clusterOrDatabaseAccessError?: Partial<EmptyStateProps>;
55
55
 
56
+ /** Defaults to true. Undefined preserves the current value when configuring the UI. */
56
57
  enableMultiTabQueryEditor?: boolean;
57
58
 
58
59
  /** Creates a fresh computation-graph layout worker for each layout run. */
@@ -64,6 +65,11 @@ export interface UIFactory<H extends string = CommonIssueCategory, T extends str
64
65
  getHealthckechViewTitles: GetHealthcheckViewTitles<H>;
65
66
  getHealthcheckViewsOrder: GetHealthcheckViewsOrder<H>;
66
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;
67
73
  };
68
74
  hasAccess: HasAccess;
69
75
  hideGrantAccess?: boolean;
@@ -30,7 +30,7 @@ const uiFactoryBase: ResolvedUIFactory = {
30
30
  useDatabaseId: false,
31
31
  settingsBackend: undefined,
32
32
  docs: undefined,
33
- enableMultiTabQueryEditor: false,
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 {healthcheck, hasAccess, maxVDisksInStorageGroup, ...restOverrides} = overrides;
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.