);
};
@@ -148,10 +174,11 @@ export function PDiskPage() {
{pDiskPageKeyset('restart-pdisk-button')}
+
);
};
diff --git a/src/containers/PDiskPage/i18n/en.json b/src/containers/PDiskPage/i18n/en.json
index 05f5c2415..336060762 100644
--- a/src/containers/PDiskPage/i18n/en.json
+++ b/src/containers/PDiskPage/i18n/en.json
@@ -17,6 +17,25 @@
"restart-pdisk-button": "Restart PDisk",
"force-restart-pdisk-button": "Restart anyway",
- "restart-pdisk-dialog": "PDisk will be restarted. Do you want to proceed?",
- "restart-pdisk-not-allowed": "You don't have enough rights to restart PDisk"
+ "restart-pdisk-not-allowed": "You don't have enough rights to restart PDisk",
+
+ "restart-pdisk-dialog-header": "Restart PDisk",
+ "restart-pdisk-dialog-text": "PDisk will be restarted. Do you want to proceed?",
+
+ "decommission-none": "None",
+ "decommission-imminent": "Imminent",
+ "decommission-pending": "Pending",
+ "decommission-rejected": "Rejected",
+
+ "decommission-label": "{{decommission}} decommission",
+
+ "decommission-button": "Decommission",
+ "decommission-change-not-allowed": "You don't have enough rights to change PDisk decommission",
+ "decommission-dialog-title": "Change decommission status",
+ "decommission-dialog-force-change": "Change anyway",
+
+ "decommission-dialog-imminent-warning": "This will start imminent decommission. Existing slots will be moved from the disk",
+ "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",
+ "decommission-dialog-rejected-warning": "This will start rejected decommission. No slots from other disks are placed on this disk in the process of decommission",
+ "decommission-dialog-none-warning": "This will reset decommission mode, allowing the disk to be used by the storage"
}
diff --git a/src/containers/Tablet/components/TabletControls/TabletControls.tsx b/src/containers/Tablet/components/TabletControls/TabletControls.tsx
index f975148f8..31aeea630 100644
--- a/src/containers/Tablet/components/TabletControls/TabletControls.tsx
+++ b/src/containers/Tablet/components/TabletControls/TabletControls.tsx
@@ -42,7 +42,8 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
return (
killTablet({id: TabletId}).unwrap()}
buttonDisabled={isDisabledRestart || !isUserAllowedToMakeChanges}
withPopover
@@ -57,7 +58,8 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
{hasHiveId && (
stopTablet({id: TabletId, hiveId: HiveId}).unwrap()}
buttonDisabled={isDisabledStop || !isUserAllowedToMakeChanges}
withPopover
@@ -70,7 +72,8 @@ export const TabletControls = ({tablet}: TabletControlsProps) => {
{i18n('controls.stop')}
resumeTablet({id: TabletId, hiveId: HiveId}).unwrap()
}
diff --git a/src/containers/Tablet/i18n/en.json b/src/containers/Tablet/i18n/en.json
index d24385939..c1d530f72 100644
--- a/src/containers/Tablet/i18n/en.json
+++ b/src/containers/Tablet/i18n/en.json
@@ -12,9 +12,13 @@
"controls.stop-not-allowed": "You don't have enough rights to stop tablet",
"controls.resume-not-allowed": "You don't have enough rights to resume tablet",
- "dialog.kill": "The tablet will be restarted. Do you want to proceed?",
- "dialog.stop": "The tablet will be stopped. Do you want to proceed?",
- "dialog.resume": "The tablet will be resumed. Do you want to proceed?",
+ "dialog.kill-header": "Restart tablet",
+ "dialog.stop-header": "Stop tablet",
+ "dialog.resume-header": "Resume tablet",
+
+ "dialog.kill-text": "The tablet will be restarted. Do you want to proceed?",
+ "dialog.stop-text": "The tablet will be stopped. Do you want to proceed?",
+ "dialog.resume-text": "The tablet will be resumed. Do you want to proceed?",
"emptyState": "The tablet was not found",
diff --git a/src/containers/Tablets/Tablets.tsx b/src/containers/Tablets/Tablets.tsx
index 337eed190..7c5ba2aca 100644
--- a/src/containers/Tablets/Tablets.tsx
+++ b/src/containers/Tablets/Tablets.tsx
@@ -154,7 +154,8 @@ function TabletActions(tablet: TTabletStateInfo) {
return (
{
return killTablet({id}).unwrap();
}}
diff --git a/src/containers/Tablets/i18n/en.json b/src/containers/Tablets/i18n/en.json
index 5065f7357..3af77871a 100644
--- a/src/containers/Tablets/i18n/en.json
+++ b/src/containers/Tablets/i18n/en.json
@@ -7,6 +7,7 @@
"Node FQDN": "Node FQDN",
"Generation": "Generation",
"Uptime": "Uptime",
- "dialog.kill": "The tablet will be restarted. Do you want to proceed?",
+ "dialog.kill-header": "Restart tablet",
+ "dialog.kill-text": "The tablet will be restarted. Do you want to proceed?",
"controls.kill-not-allowed": "You don't have enough rights to restart tablet"
}
diff --git a/src/containers/VDiskPage/VDiskPage.tsx b/src/containers/VDiskPage/VDiskPage.tsx
index 833e96509..61d71dfd8 100644
--- a/src/containers/VDiskPage/VDiskPage.tsx
+++ b/src/containers/VDiskPage/VDiskPage.tsx
@@ -147,7 +147,8 @@ export function VDiskPage() {
onConfirmActionSuccess={handleAfterEvictVDisk}
buttonDisabled={!vDiskIdParamsDefined || !isUserAllowedToMakeChanges}
buttonView="normal"
- dialogContent={vDiskPageKeyset('evict-vdisk-dialog')}
+ dialogHeader={vDiskPageKeyset('evict-vdisk-dialog-header')}
+ dialogText={vDiskPageKeyset('evict-vdisk-dialog-text')}
retryButtonText={vDiskPageKeyset('force-evict-vdisk-button')}
withPopover
popoverContent={vDiskPageKeyset('evict-vdisk-not-allowed')}
diff --git a/src/containers/VDiskPage/i18n/en.json b/src/containers/VDiskPage/i18n/en.json
index d5201532f..b88fbba32 100644
--- a/src/containers/VDiskPage/i18n/en.json
+++ b/src/containers/VDiskPage/i18n/en.json
@@ -7,6 +7,7 @@
"evict-vdisk-button": "Evict VDisk",
"force-evict-vdisk-button": "Evict anyway",
- "evict-vdisk-dialog": "VDisk will be evicted. Do you want to proceed?",
+ "evict-vdisk-dialog-header": "Evict VDisk",
+ "evict-vdisk-dialog-text": "VDisk will be evicted. Do you want to proceed?",
"evict-vdisk-not-allowed": "You don't have enough rights to evict VDisk"
}
diff --git a/src/services/api.ts b/src/services/api.ts
index 867c7a574..ef0e45dae 100644
--- a/src/services/api.ts
+++ b/src/services/api.ts
@@ -2,7 +2,6 @@ import AxiosWrapper from '@gravity-ui/axios-wrapper';
import type {AxiosWrapperOptions} from '@gravity-ui/axios-wrapper';
import type {AxiosRequestConfig} from 'axios';
import axiosRetry from 'axios-retry';
-import qs from 'qs';
import {backend as BACKEND, metaBackend as META_BACKEND} from '../store';
import type {ComputeApiRequestParams, NodesApiRequestParams} from '../store/reducers/nodes/types';
@@ -20,7 +19,7 @@ import type {ModifyDiskResponse} from '../types/api/modifyDisk';
import type {TNetInfo} from '../types/api/netInfo';
import type {TNodesInfo} from '../types/api/nodes';
import type {TEvNodesInfo} from '../types/api/nodesList';
-import type {TEvPDiskStateResponse, TPDiskInfoResponse} from '../types/api/pdisk';
+import type {EDecommitStatus, TEvPDiskStateResponse, TPDiskInfoResponse} from '../types/api/pdisk';
import type {
Actions,
ErrorResponse,
@@ -599,24 +598,18 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
vDiskIdx: string | number;
force?: boolean;
}) {
- const params = {
- group_id: groupId,
- group_generation_id: groupGeneration,
- fail_realm_idx: failRealmIdx,
- fail_domain_idx: failDomainIdx,
- vdisk_idx: vDiskIdx,
-
- force,
- };
-
- const paramsString = qs.stringify(params);
-
- const path = this.getPath(`/vdisk/evict?${paramsString}`);
-
return this.post(
- path,
- {},
+ this.getPath('/vdisk/evict'),
{},
+ {
+ group_id: groupId,
+ group_generation_id: groupGeneration,
+ fail_realm_idx: failRealmIdx,
+ fail_domain_idx: failDomainIdx,
+ vdisk_idx: vDiskIdx,
+
+ force,
+ },
{
requestConfig: {'axios-retry': {retries: 0}},
},
@@ -632,9 +625,39 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
force?: boolean;
}) {
return this.post(
- this.getPath(`/pdisk/restart?node_id=${nodeId}&pdisk_id=${pDiskId}&force=${force}`),
- {},
+ this.getPath('/pdisk/restart'),
{},
+ {
+ node_id: nodeId,
+ pdisk_id: pDiskId,
+ force,
+ },
+ {
+ requestConfig: {'axios-retry': {retries: 0}},
+ },
+ );
+ }
+ changePDiskStatus({
+ nodeId,
+ pDiskId,
+ force,
+ decommissionStatus,
+ }: {
+ nodeId: number | string;
+ pDiskId: number | string;
+ force?: boolean;
+ decommissionStatus?: EDecommitStatus;
+ }) {
+ return this.post(
+ this.getPath('/pdisk/status'),
+ {
+ decommit_status: decommissionStatus,
+ },
+ {
+ node_id: nodeId,
+ pdisk_id: pDiskId,
+ force,
+ },
{
requestConfig: {'axios-retry': {retries: 0}},
},
diff --git a/src/types/api/modifyDisk.ts b/src/types/api/modifyDisk.ts
index e24e78f71..21ad58e0c 100644
--- a/src/types/api/modifyDisk.ts
+++ b/src/types/api/modifyDisk.ts
@@ -2,6 +2,7 @@
* endpoints: pdisk/restart and vdiks/evict
*/
export interface ModifyDiskResponse {
+ debugMessage?: string;
// true if successful, false if not
result?: boolean;
// Error message
diff --git a/src/types/api/pdisk.ts b/src/types/api/pdisk.ts
index 18aadd534..99c639af2 100644
--- a/src/types/api/pdisk.ts
+++ b/src/types/api/pdisk.ts
@@ -131,9 +131,9 @@ type EDriveStatus =
| 'FAULTY' // drive is expected to become BROKEN soon, new groups are not created, old groups are asynchronously moved out from this drive
| 'TO_BE_REMOVED'; // same as INACTIVE, but drive is counted in fault model as not working
-type EDecommitStatus =
+export type EDecommitStatus =
| 'DECOMMIT_UNSET'
- | 'DECOMMIT_NONE' // no decomission
+ | 'DECOMMIT_NONE' // no decommission
| 'DECOMMIT_PENDING' // drive is going to be removed soon, but SelfHeal logic would not remove it automatically
| 'DECOMMIT_IMMINENT' // drive is going to be settled automatically
| 'DECOMMIT_REJECTED'; // drive is working as usual, but decommitted slots are not placed here
diff --git a/src/utils/index.ts b/src/utils/index.ts
index 4d231399f..308dce79e 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -5,3 +5,9 @@ export const getArray = (arrayLength: number) => {
export function valueIsDefined(value: T | null | undefined): value is T {
return value !== null && value !== undefined;
}
+
+export async function wait(time: number) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, time);
+ });
+}