From 52af6f5b4b8a483faee2a84074773947e6401b30 Mon Sep 17 00:00:00 2001 From: the-wunmi Date: Thu, 7 Aug 2025 03:25:19 +0100 Subject: [PATCH 1/6] Add compression options to backup service and UI components --- public/app/percona/backup/Backup.service.ts | 18 +- public/app/percona/backup/Backup.types.ts | 11 + .../AddBackupPage/AddBackupPage.constants.ts | 37 ++- .../AddBackupPage/AddBackupPage.messages.ts | 4 + .../AddBackupPage/AddBackupPage.test.tsx | 20 ++ .../AddBackupPage/AddBackupPage.tsx | 297 +++++++++--------- .../AddBackupPage/AddBackupPage.types.ts | 1 + .../AddBackupPage/AddBackupPage.utils.ts | 5 +- .../BackupInventory.service.ts | 2 + .../BackupInventory/BackupInventory.tsx | 1 + .../BackupInventory/BackupInventory.types.ts | 2 + .../BackupInventoryDetails.messages.ts | 1 + .../BackupInventoryDetails.test.tsx | 2 + .../BackupInventoryDetails.tsx | 7 +- .../BackupInventoryDetails.types.ts | 1 + .../RestoreBackupModal.test.tsx | 3 +- .../__mocks__/BackupInventory.service.ts | 4 +- .../RestoreHistory/RestoreHistory.types.ts | 2 +- .../ScheduledBackups.service.ts | 2 + .../ScheduledBackups/ScheduledBackups.tsx | 5 +- .../ScheduledBackups.types.ts | 2 + .../ScheduledBackupsDetails.messages.ts | 1 + .../ScheduledBackupsDetails.test.tsx | 2 + .../ScheduledBackupsDetails.tsx | 6 + .../ScheduledBackupsDetails.types.ts | 1 + .../__mocks__/ScheduledBackups.service.ts | 4 +- 26 files changed, 288 insertions(+), 153 deletions(-) diff --git a/public/app/percona/backup/Backup.service.ts b/public/app/percona/backup/Backup.service.ts index 8dcf7859860a9..363cc46430514 100644 --- a/public/app/percona/backup/Backup.service.ts +++ b/public/app/percona/backup/Backup.service.ts @@ -32,6 +32,7 @@ export const BackupService = { type, dataModel, folder, + compression, } = values; const strRetryInterval = `${retryInterval}s`; const resultRetryTimes = retryMode === RetryMode.MANUAL ? 0 : retryTimes; @@ -46,6 +47,7 @@ export const BackupService = { resultRetryTimes!, dataModel, folder, + compression, token ); } else { @@ -66,7 +68,8 @@ export const BackupService = { description ?? '', strRetryInterval, resultRetryTimes!, - retention! + retention!, + compression ); } else { return this.scheduleBackup( @@ -81,7 +84,8 @@ export const BackupService = { active!, mode, dataModel, - folder + folder, + compression ); } } @@ -95,6 +99,7 @@ export const BackupService = { retryTimes: number, dataModel: DataModel, folder: string, + compression: string, token?: CancelToken ) { return api.post( @@ -108,6 +113,7 @@ export const BackupService = { retries: retryTimes, data_model: dataModel, folder, + compression, }, false, token @@ -125,7 +131,8 @@ export const BackupService = { enabled: boolean, mode: BackupMode, dataModel: DataModel, - folder: string + folder: string, + compression: string ) { return api.post(`${BASE_URL}:schedule`, { service_id: serviceId, @@ -140,6 +147,7 @@ export const BackupService = { mode, data_model: dataModel, folder, + compression, }); }, async changeScheduleBackup( @@ -150,7 +158,8 @@ export const BackupService = { description: string, retryInterval: string, retryTimes: number, - retention: number + retention: number, + compression: string ) { return api.put(`${BASE_URL}:changeScheduled`, { scheduled_backup_id: id, @@ -161,6 +170,7 @@ export const BackupService = { retry_interval: retryInterval, retries: retryTimes, retention, + compression, }); }, }; diff --git a/public/app/percona/backup/Backup.types.ts b/public/app/percona/backup/Backup.types.ts index b30b9d5943d7f..02b1b7fbb5af5 100644 --- a/public/app/percona/backup/Backup.types.ts +++ b/public/app/percona/backup/Backup.types.ts @@ -40,6 +40,17 @@ export enum BackupType { SCHEDULED = 'SCHEDULED', } +export enum Compression { + NONE = 'NONE', + QUICKLZ = 'QUICKLZ', + ZSTD = 'ZSTD', + LZ4 = 'LZ4', + S2 = 'S2', + GZIP = 'GZIP', + SNAPPY = 'SNAPPY', + PGZIP = 'PGZIP', +} + export interface RawBackupLog { chunk_id: number; data: string; diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts index 57349465b45ff..2425f2b19c508 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts @@ -1,5 +1,5 @@ import { SelectableValue } from '@grafana/data'; -import { DataModel, RetryMode } from 'app/percona/backup/Backup.types'; +import { DataModel, RetryMode, Compression } from 'app/percona/backup/Backup.types'; import { Databases, DATABASE_LABELS } from 'app/percona/shared/core'; import { capitalizeText } from 'app/percona/shared/helpers/capitalizeText'; import { MONTHS, WEEKDAYS } from 'app/percona/shared/helpers/cron/constants'; @@ -87,3 +87,38 @@ export const MIN_RETENTION = 0; export const MAX_RETENTION = 99; export const MAX_BACKUP_NAME = 100; + +export const COMPRESSION_OPTIONS: Array> = [ + { + value: Compression.NONE, + label: 'No compression', + }, + { + value: Compression.QUICKLZ, + label: 'QuickLZ compression', + }, + { + value: Compression.ZSTD, + label: 'Zstandard compression', + }, + { + value: Compression.LZ4, + label: 'LZ4 compression', + }, + { + value: Compression.S2, + label: 'S2 compression', + }, + { + value: Compression.GZIP, + label: 'Gzip compression', + }, + { + value: Compression.SNAPPY, + label: 'Snappy compression', + }, + { + value: Compression.PGZIP, + label: 'Parallel Gzip compression', + }, +]; diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.messages.ts b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.messages.ts index 9dfb45e2e45b1..13aa26cb5c2d5 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.messages.ts +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.messages.ts @@ -13,6 +13,10 @@ export const Messages = { folder: 'Folder', location: 'Location', retryMode: 'Retry mode', + compression: 'Compression', + compressionTooltip: + 'Choose the compression algorithm for the backup. Different algorithms offer different trade-offs between compression ratio and speed.', + selectCompression: 'Select compression type', cancelAction: 'Cancel', retryTimes: 'Retry, times', retryInterval: 'Retry interval, seconds', diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx index 4064a753296d2..c6b167f02d33e 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx @@ -154,4 +154,24 @@ describe('AddBackupPage', () => { await fireEvent.click(button); expect(screen.getByText('Create Backup on demand')).toBeInTheDocument(); }); + + it('should render compression field in advanced settings', async () => { + render( + + + + ); + + await waitFor(() => expect(screen.getAllByText('Choose')).toHaveLength(2)); + + const advancedSettingsButton = screen.getByTestId('add-backup-advanced-settings'); + fireEvent.click(advancedSettingsButton); + + expect(screen.getByTestId('compression-select-input')).toBeInTheDocument(); + expect(screen.getByText(Messages.compression)).toBeInTheDocument(); + }); }); diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx index c61f88222e492..1d6fecf6924c2 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx @@ -42,7 +42,7 @@ import { ScheduledBackupsService } from '../ScheduledBackups/ScheduledBackups.se import { ScheduledBackup } from '../ScheduledBackups/ScheduledBackups.types'; import { LocationType } from '../StorageLocations/StorageLocations.types'; -import { DATA_MODEL_OPTIONS, MAX_BACKUP_NAME } from './AddBackupPage.constants'; +import { DATA_MODEL_OPTIONS, MAX_BACKUP_NAME, COMPRESSION_OPTIONS } from './AddBackupPage.constants'; import { Messages } from './AddBackupPage.messages'; import { AddBackupPageService } from './AddBackupPage.service'; import { getStyles } from './AddBackupPage.styles'; @@ -220,163 +220,178 @@ const AddBackupPage: FC = () => { setAdvancedSectionOpen(true); } - tools.changeValue(state, 'folder', () => cluster); - }, - }} - render={({ handleSubmit, valid, pristine, submitting, values, form }) => ( -
- - - {Messages.cancelAction} - - - {Messages.getSubmitButtonText(values.type === BackupType.SCHEDULED, editing)} - - -
- -
-
- {!editing && } -

{Messages.backupInfo}

-
- - - - - - {({ input }) => ( - cluster); + }, + }} + render={({ handleSubmit, valid, pristine, submitting, values, form }) => ( + + + + {Messages.cancelAction} + + + {Messages.getSubmitButtonText(values.type === BackupType.SCHEDULED, editing)} + + +
+ +
+
+ {!editing && } +

{Messages.backupInfo}

+
+ + + + + + {({ input }) => ( + ) => { + input.onChange(service); + form.mutators.changeVendor(service.value!.vendor); + form.mutators.changeFolder(service.value!.cluster); + }} + className={styles.selectField} + data-testid="service-select-input" + /> + )} + + + + + + + DATABASE_LABELS[vendor as Databases] || ''} + /> + + + + {({ input }) => ( +
+ ) => { - input.onChange(service); - form.mutators.changeVendor(service.value!.vendor); - form.mutators.changeFolder(service.value!.cluster); - }} className={styles.selectField} - data-testid="service-select-input" + data-testid="location-select-input" /> - )} - +
+ )} +
+
+ {scheduleMode && ( + + - + )} + {values.type === BackupType.SCHEDULED && ( + ) => + form.mutators.changeDataModel(e.target.labels), + }} /> - - DATABASE_LABELS[vendor as Databases] || ''} - /> - - - - {({ input }) => ( -
+ )} +
+
+ {values.type === BackupType.SCHEDULED && } +
+ + + + + {({ input }) => ( -
- )} - - - {scheduleMode && ( - - - - )} - {values.type === BackupType.SCHEDULED && ( - - ) => - form.mutators.changeDataModel(e.target.labels), - }} - /> + )} + - )} -
-
- {values.type === BackupType.SCHEDULED && } -
- - - - - {!!backupErrors.length && } -
+ + + {!!backupErrors.length && }
- -
- - )} - /> - - +
+ +
+ + )} + /> + ); }; diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.types.ts b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.types.ts index 6990036de9e6d..f8ce881b7fcec 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.types.ts +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.types.ts @@ -39,4 +39,5 @@ export interface AddBackupFormProps extends ScheduledSectionFieldsValuesProps { mode: BackupMode; type: BackupType; folder: string; + compression: string; } diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts index 9f7a3c7b175a0..2a34f51cecaa6 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/consistent-type-assertions */ import { SelectableValue } from '@grafana/data'; -import { BackupMode, BackupType, DataModel, RetryMode } from 'app/percona/backup/Backup.types'; +import { BackupMode, BackupType, DataModel, RetryMode, Compression } from 'app/percona/backup/Backup.types'; import { Databases } from 'app/percona/shared/core'; import { getPeriodFromCronparts, parseCronString } from 'app/percona/shared/helpers/cron/cron'; import { PeriodType } from 'app/percona/shared/helpers/cron/types'; @@ -79,6 +79,7 @@ export const toFormBackup = (backup: Backup | ScheduledBackup | null, scheduleMo mode: BackupMode.SNAPSHOT, type: scheduleMode ? BackupType.SCHEDULED : getBackupType(backup), folder: '', + compression: Compression.NONE, }; } @@ -130,6 +131,7 @@ export const toFormBackup = (backup: Backup | ScheduledBackup | null, scheduleMo mode, type: BackupType.SCHEDULED, folder, + compression: backup.compression || Compression.NONE, }; } else { return { @@ -146,6 +148,7 @@ export const toFormBackup = (backup: Backup | ScheduledBackup | null, scheduleMo retryInterval: 30, type: BackupType.DEMAND, folder, + compression: backup.compression || Compression.NONE, }; } }; diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts b/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts index 29c4de04f9ad0..91edc377bd993 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts +++ b/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts @@ -28,6 +28,7 @@ export const BackupInventoryService = { vendor, mode, folder, + compression, }): Backup => ({ id: artifact_id, name, @@ -41,6 +42,7 @@ export const BackupInventoryService = { vendor, mode, folder, + compression, }) ); }, diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventory.tsx b/public/app/percona/backup/components/BackupInventory/BackupInventory.tsx index 562a17cafd191..7c37035f0aa45 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventory.tsx +++ b/public/app/percona/backup/components/BackupInventory/BackupInventory.tsx @@ -280,6 +280,7 @@ export const BackupInventory: FC = () => { status={row.original.status} dataModel={row.original.dataModel} folder={row.original.folder} + compression={row.original.compression} /> ), [] diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts b/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts index abe3ee75fb232..c07906b71628e 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts +++ b/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts @@ -17,6 +17,7 @@ export interface Backup { mode: BackupMode; folder: string; type?: Databases | 'external'; + compression: string; } export interface BackupRow extends Backup { @@ -36,6 +37,7 @@ export interface RawBackup { vendor: Databases; mode: BackupMode; folder: string; + compression: string; } export interface BackupResponse { diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.messages.ts b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.messages.ts index 0a40c7935e4a6..2576f17b67ada 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.messages.ts +++ b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.messages.ts @@ -3,4 +3,5 @@ export const Messages = { testResuts: 'Test results', dataModel: 'Data model', folder: 'Folder', + compression: 'Compression', }; diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.test.tsx b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.test.tsx index 36e4549dc35f3..df1441b8209b3 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.test.tsx +++ b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.test.tsx @@ -12,10 +12,12 @@ describe('BackupInventoryDetails', () => { status={BackupStatus.BACKUP_STATUS_PAUSED} dataModel={DataModel.LOGICAL} folder="folder1" + compression="NONE" /> ); expect(screen.getByTestId('backup-artifact-details-name')).toBeInTheDocument(); expect(screen.getByTestId('backup-artifact-details-data-model')).toBeInTheDocument(); expect(screen.getByTestId('backup-artifact-details-folder')).toBeInTheDocument(); + expect(screen.getByTestId('backup-artifact-details-compression')).toBeInTheDocument(); }); }); diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.tsx b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.tsx index a7cc6810f23e8..c3f9db24839b5 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.tsx +++ b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.tsx @@ -7,7 +7,7 @@ import { Messages } from './BackupInventoryDetails.messages'; import { getStyles } from './BackupInventoryDetails.styles'; import { BackupInventoryDetailsProps } from './BackupInventoryDetails.types'; -export const BackupInventoryDetails: FC = ({ name, folder, dataModel }) => { +export const BackupInventoryDetails: FC = ({ name, folder, dataModel, compression }) => { const styles = useStyles(getStyles); const dataModelMsg = formatDataModel(dataModel); @@ -24,6 +24,11 @@ export const BackupInventoryDetails: FC = ({ name, {Messages.folder} {folder} )} + {compression && ( + + {Messages.compression} {compression} + + )}
); }; diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.types.ts b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.types.ts index 1e8f5b563ebc4..e1f95b65ffb76 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.types.ts +++ b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.types.ts @@ -5,4 +5,5 @@ export interface BackupInventoryDetailsProps { status: BackupStatus | RestoreStatus; dataModel: DataModel; folder: string; + compression: string; } diff --git a/public/app/percona/backup/components/BackupInventory/RestoreBackupModal/RestoreBackupModal.test.tsx b/public/app/percona/backup/components/BackupInventory/RestoreBackupModal/RestoreBackupModal.test.tsx index 42b812651f5b8..c472ea319a4d7 100644 --- a/public/app/percona/backup/components/BackupInventory/RestoreBackupModal/RestoreBackupModal.test.tsx +++ b/public/app/percona/backup/components/BackupInventory/RestoreBackupModal/RestoreBackupModal.test.tsx @@ -1,6 +1,6 @@ import { fireEvent, render, screen } from '@testing-library/react'; -import { BackupMode, BackupStatus, DataModel } from 'app/percona/backup/Backup.types'; +import { BackupMode, BackupStatus, DataModel, Compression } from 'app/percona/backup/Backup.types'; import { Databases } from 'app/percona/shared/core'; import { Backup } from '../BackupInventory.types'; @@ -21,6 +21,7 @@ describe('RestoreBackupModal', () => { vendor: Databases.mongodb, mode: BackupMode.SNAPSHOT, folder: 'folder1', + compression: Compression.NONE, }; it('should render', () => { diff --git a/public/app/percona/backup/components/BackupInventory/__mocks__/BackupInventory.service.ts b/public/app/percona/backup/components/BackupInventory/__mocks__/BackupInventory.service.ts index 1b2a954ffb9f4..1ca63836d94ba 100644 --- a/public/app/percona/backup/components/BackupInventory/__mocks__/BackupInventory.service.ts +++ b/public/app/percona/backup/components/BackupInventory/__mocks__/BackupInventory.service.ts @@ -1,4 +1,4 @@ -import { DataModel, BackupStatus, BackupMode } from 'app/percona/backup/Backup.types'; +import { DataModel, BackupStatus, BackupMode, Compression } from 'app/percona/backup/Backup.types'; import { Databases } from 'app/percona/shared/core'; import * as service from '../BackupInventory.service'; @@ -18,6 +18,7 @@ export const stubs: Backup[] = [ vendor: Databases.mysql, mode: BackupMode.SNAPSHOT, folder: 'folder1', + compression: Compression.NONE, }, { id: 'backup_2', @@ -32,6 +33,7 @@ export const stubs: Backup[] = [ vendor: Databases.mysql, mode: BackupMode.SNAPSHOT, folder: 'folder1', + compression: Compression.NONE, }, ]; diff --git a/public/app/percona/backup/components/RestoreHistory/RestoreHistory.types.ts b/public/app/percona/backup/components/RestoreHistory/RestoreHistory.types.ts index 9fbd123399f40..1ae6e361a8fff 100644 --- a/public/app/percona/backup/components/RestoreHistory/RestoreHistory.types.ts +++ b/public/app/percona/backup/components/RestoreHistory/RestoreHistory.types.ts @@ -13,7 +13,7 @@ export interface RestoreResponse { items: RawRestore[]; } -export interface Restore extends Omit { +export interface Restore extends Omit { id: string; artifactId: string; started: number; diff --git a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.service.ts b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.service.ts index 37c270f25781f..64e7e418314d0 100644 --- a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.service.ts +++ b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.service.ts @@ -34,6 +34,7 @@ export const ScheduledBackupsService = { retention = 0, mode, folder, + compression, }) => ({ id: scheduled_backup_id, name, @@ -53,6 +54,7 @@ export const ScheduledBackupsService = { retryInterval: retry_interval, enabled: !!enabled, folder, + compression, }) ); }, diff --git a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.tsx b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.tsx index 78a6e40a797c9..5d661a822b53b 100644 --- a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.tsx +++ b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.tsx @@ -87,6 +87,7 @@ export const ScheduledBackups: FC = () => { mode, dataModel, folder, + compression, } = backup; const newName = `${Messages.scheduledBackups.copyOf}${name}`; setActionPending(true); @@ -103,7 +104,8 @@ export const ScheduledBackups: FC = () => { false, mode, dataModel, - folder + folder, + compression ); getData(); } catch (e) { @@ -216,6 +218,7 @@ export const ScheduledBackups: FC = () => { description={row.original.description} cronExpression={row.original.cronExpression} folder={row.original.folder} + compression={row.original.compression} /> ), [] diff --git a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.types.ts b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.types.ts index 035be76a5edb1..fb703690b059a 100644 --- a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.types.ts +++ b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.types.ts @@ -21,6 +21,7 @@ export interface RawScheduledBackup { retention: number; mode: BackupMode; folder: string; + compression: string; } export interface ScheduledBackupResponse { @@ -46,4 +47,5 @@ export interface ScheduledBackup { mode: BackupMode; enabled: boolean; folder: string; + compression: string; } diff --git a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.messages.ts b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.messages.ts index 2032ee15697ed..3a0b0b920a72d 100644 --- a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.messages.ts +++ b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.messages.ts @@ -4,4 +4,5 @@ export const Messages = { dataModel: 'Data model', cronExpression: 'Cron expression', folder: 'Folder', + compression: 'Compression', }; diff --git a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.test.tsx b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.test.tsx index a30e632d7b8d4..1b3f820644e7a 100644 --- a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.test.tsx +++ b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.test.tsx @@ -13,6 +13,7 @@ describe('ScheduledBackupsDetails', () => { dataModel={DataModel.PHYSICAL} cronExpression=" * * * 1,3 0" folder="folder1" + compression="NONE" /> ); expect(screen.getByTestId('scheduled-backup-details-wrapper')).toBeInTheDocument(); @@ -21,5 +22,6 @@ describe('ScheduledBackupsDetails', () => { expect(screen.getByTestId('scheduled-backup-details-cron')).toBeInTheDocument(); expect(screen.getByTestId('scheduled-backup-details-data-model')).toBeInTheDocument(); expect(screen.getByTestId('scheduled-backup-details-folder')).toBeInTheDocument(); + expect(screen.getByTestId('scheduled-backup-details-compression')).toBeInTheDocument(); }); }); diff --git a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.tsx b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.tsx index 4af9cd9753081..b59d4cf06e541 100644 --- a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.tsx +++ b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.tsx @@ -15,6 +15,7 @@ export const ScheduledBackupDetails: FC = ({ dataModel, cronExpression, folder, + compression, }) => { const styles = useStyles(getStyles); const dataModelMsg = formatDataModel(dataModel); @@ -38,6 +39,11 @@ export const ScheduledBackupDetails: FC = ({ {Messages.folder} {folder} )} + {compression && ( + + {Messages.compression} {compression} + + )}
); }; diff --git a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.types.ts b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.types.ts index d92c5f53ffb96..1eef23b412837 100644 --- a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.types.ts +++ b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.types.ts @@ -6,4 +6,5 @@ export interface ScheduledBackupDetailsProps { dataModel: DataModel; cronExpression: string; folder: string; + compression: string; } diff --git a/public/app/percona/backup/components/ScheduledBackups/__mocks__/ScheduledBackups.service.ts b/public/app/percona/backup/components/ScheduledBackups/__mocks__/ScheduledBackups.service.ts index 29af28d3fd4d7..390d7101b4ac2 100644 --- a/public/app/percona/backup/components/ScheduledBackups/__mocks__/ScheduledBackups.service.ts +++ b/public/app/percona/backup/components/ScheduledBackups/__mocks__/ScheduledBackups.service.ts @@ -1,4 +1,4 @@ -import { BackupMode, DataModel } from 'app/percona/backup/Backup.types'; +import { BackupMode, DataModel, Compression } from 'app/percona/backup/Backup.types'; import { Databases } from 'app/percona/shared/core'; import * as service from '../ScheduledBackups.service'; @@ -24,6 +24,7 @@ export const stubs: ScheduledBackup[] = [ retryInterval: '10s', retryTimes: 1, folder: 'folder1', + compression: Compression.NONE, }, { id: 'backup_2', @@ -44,6 +45,7 @@ export const stubs: ScheduledBackup[] = [ retryInterval: '0s', retryTimes: 1, folder: 'folder1', + compression: Compression.NONE, }, ]; From ffba6a10252301cf9991fdbbf9e89c4e65cd89a4 Mon Sep 17 00:00:00 2001 From: the-wunmi Date: Thu, 7 Aug 2025 04:40:21 +0100 Subject: [PATCH 2/6] bug fix. --- public/app/percona/backup/Backup.service.ts | 6 +++--- .../backup/components/AddBackupPage/AddBackupPage.types.ts | 2 +- .../backup/components/AddBackupPage/AddBackupPage.utils.ts | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/public/app/percona/backup/Backup.service.ts b/public/app/percona/backup/Backup.service.ts index 363cc46430514..56775b208ba8c 100644 --- a/public/app/percona/backup/Backup.service.ts +++ b/public/app/percona/backup/Backup.service.ts @@ -47,7 +47,7 @@ export const BackupService = { resultRetryTimes!, dataModel, folder, - compression, + compression.value!, token ); } else { @@ -69,7 +69,7 @@ export const BackupService = { strRetryInterval, resultRetryTimes!, retention!, - compression + compression.value! ); } else { return this.scheduleBackup( @@ -85,7 +85,7 @@ export const BackupService = { mode, dataModel, folder, - compression + compression.value! ); } } diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.types.ts b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.types.ts index f8ce881b7fcec..15374cd12b21a 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.types.ts +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.types.ts @@ -39,5 +39,5 @@ export interface AddBackupFormProps extends ScheduledSectionFieldsValuesProps { mode: BackupMode; type: BackupType; folder: string; - compression: string; + compression: SelectableValue; } diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts index 2a34f51cecaa6..7a50fbba4a127 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts @@ -10,6 +10,7 @@ import { Backup } from '../BackupInventory/BackupInventory.types'; import { ScheduledBackup } from '../ScheduledBackups/ScheduledBackups.types'; import { LocationType } from '../StorageLocations/StorageLocations.types'; +import { COMPRESSION_OPTIONS } from './AddBackupPage.constants'; import { AddBackupFormProps } from './AddBackupPage.types'; import { ScheduleSectionFields as ScheduleSectionFieldsEnum, @@ -79,7 +80,7 @@ export const toFormBackup = (backup: Backup | ScheduledBackup | null, scheduleMo mode: BackupMode.SNAPSHOT, type: scheduleMode ? BackupType.SCHEDULED : getBackupType(backup), folder: '', - compression: Compression.NONE, + compression: COMPRESSION_OPTIONS.find((option) => option.value === Compression.NONE)!, }; } @@ -131,7 +132,7 @@ export const toFormBackup = (backup: Backup | ScheduledBackup | null, scheduleMo mode, type: BackupType.SCHEDULED, folder, - compression: backup.compression || Compression.NONE, + compression: COMPRESSION_OPTIONS.find((option) => option.value === backup.compression)!, }; } else { return { @@ -148,7 +149,7 @@ export const toFormBackup = (backup: Backup | ScheduledBackup | null, scheduleMo retryInterval: 30, type: BackupType.DEMAND, folder, - compression: backup.compression || Compression.NONE, + compression: COMPRESSION_OPTIONS.find((option) => option.value === backup.compression)!, }; } }; From 7573f439bcbbf9c320665846c98d475e97c04abf Mon Sep 17 00:00:00 2001 From: the-wunmi Date: Fri, 8 Aug 2025 06:58:18 +0100 Subject: [PATCH 3/6] fix merge bug. --- .../AddBackupPage/AddBackupPage.tsx | 293 +++++++++--------- 1 file changed, 147 insertions(+), 146 deletions(-) diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx index 1d6fecf6924c2..7b5fca887c885 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx @@ -42,7 +42,7 @@ import { ScheduledBackupsService } from '../ScheduledBackups/ScheduledBackups.se import { ScheduledBackup } from '../ScheduledBackups/ScheduledBackups.types'; import { LocationType } from '../StorageLocations/StorageLocations.types'; -import { DATA_MODEL_OPTIONS, MAX_BACKUP_NAME, COMPRESSION_OPTIONS } from './AddBackupPage.constants'; +import { COMPRESSION_OPTIONS, DATA_MODEL_OPTIONS, MAX_BACKUP_NAME } from './AddBackupPage.constants'; import { Messages } from './AddBackupPage.messages'; import { AddBackupPageService } from './AddBackupPage.service'; import { getStyles } from './AddBackupPage.styles'; @@ -220,143 +220,143 @@ const AddBackupPage: FC = () => { setAdvancedSectionOpen(true); } - tools.changeValue(state, 'folder', () => cluster); - }, - }} - render={({ handleSubmit, valid, pristine, submitting, values, form }) => ( -
- - - {Messages.cancelAction} - - - {Messages.getSubmitButtonText(values.type === BackupType.SCHEDULED, editing)} - - -
- -
-
- {!editing && } -

{Messages.backupInfo}

-
- - - - - - {({ input }) => ( - ) => { - input.onChange(service); - form.mutators.changeVendor(service.value!.vendor); - form.mutators.changeFolder(service.value!.cluster); - }} - className={styles.selectField} - data-testid="service-select-input" - /> - )} - - - - - - - DATABASE_LABELS[vendor as Databases] || ''} - /> - - - - {({ input }) => ( -
- cluster); + }, + }} + render={({ handleSubmit, valid, pristine, submitting, values, form }) => ( + + + + {Messages.cancelAction} + + + {Messages.getSubmitButtonText(values.type === BackupType.SCHEDULED, editing)} + + +
+ +
+
+ {!editing && } +

{Messages.backupInfo}

+
+ + + + + + {({ input }) => ( + ) => { + input.onChange(service); + form.mutators.changeVendor(service.value!.vendor); + form.mutators.changeFolder(service.value!.cluster); + }} className={styles.selectField} - data-testid="location-select-input" + data-testid="service-select-input" /> -
- )} - - - {scheduleMode && ( - - + )} + - )} - {values.type === BackupType.SCHEDULED && ( - + ) => - form.mutators.changeDataModel(e.target.labels), - }} /> - )} -
-
- {values.type === BackupType.SCHEDULED && } -
- - - + + DATABASE_LABELS[vendor as Databases] || ''} + /> + + + + {({ input }) => ( +
+ +
+ )} +
+
+ {scheduleMode && ( + + + + )} + {values.type === BackupType.SCHEDULED && ( + + ) => + form.mutators.changeDataModel(e.target.labels), + }} + /> + + )} +
+
+ {values.type === BackupType.SCHEDULED && } +
+ + + {({ input }) => ( { )} - - - {!!backupErrors.length && } + + + {!!backupErrors.length && } +
-
- -
- - )} - /> - + +
+ + )} + /> + + ); }; From 5e850159e60bc79883f4eb3965d73fc90d025f07 Mon Sep 17 00:00:00 2001 From: the-wunmi Date: Sun, 10 Aug 2025 04:09:49 +0100 Subject: [PATCH 4/6] Update backup compression options and improve AddBackupPage tests --- public/app/percona/backup/Backup.types.ts | 17 +++++++++-------- .../AddBackupPage/AddBackupPage.constants.ts | 4 ++++ .../AddBackupPage/AddBackupPage.test.tsx | 8 +++----- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/public/app/percona/backup/Backup.types.ts b/public/app/percona/backup/Backup.types.ts index 02b1b7fbb5af5..5c2db43e7d87a 100644 --- a/public/app/percona/backup/Backup.types.ts +++ b/public/app/percona/backup/Backup.types.ts @@ -41,14 +41,15 @@ export enum BackupType { } export enum Compression { - NONE = 'NONE', - QUICKLZ = 'QUICKLZ', - ZSTD = 'ZSTD', - LZ4 = 'LZ4', - S2 = 'S2', - GZIP = 'GZIP', - SNAPPY = 'SNAPPY', - PGZIP = 'PGZIP', + DEFAULT = 'BACKUP_COMPRESSION_DEFAULT', + NONE = 'BACKUP_COMPRESSION_NONE', + QUICKLZ = 'BACKUP_COMPRESSION_QUICKLZ', + ZSTD = 'BACKUP_COMPRESSION_ZSTD', + LZ4 = 'BACKUP_COMPRESSION_LZ4', + S2 = 'BACKUP_COMPRESSION_S2', + GZIP = 'BACKUP_COMPRESSION_GZIP', + SNAPPY = 'BACKUP_COMPRESSION_SNAPPY', + PGZIP = 'BACKUP_COMPRESSION_PGZIP', } export interface RawBackupLog { diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts index 2425f2b19c508..299554a1ba01f 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts @@ -89,6 +89,10 @@ export const MAX_RETENTION = 99; export const MAX_BACKUP_NAME = 100; export const COMPRESSION_OPTIONS: Array> = [ + { + value: Compression.DEFAULT, + label: 'Default', + }, { value: Compression.NONE, label: 'No compression', diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx index c6b167f02d33e..005e661527e1b 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx @@ -158,11 +158,9 @@ describe('AddBackupPage', () => { it('should render compression field in advanced settings', async () => { render( - + + + ); From 4a067226837e9e07347c414433a2c21e2bae44e9 Mon Sep 17 00:00:00 2001 From: the-wunmi Date: Sun, 10 Aug 2025 05:40:39 +0100 Subject: [PATCH 5/6] Refactor backup service to use Compression type and update AddBackupPage to load compression options dynamically --- public/app/percona/backup/Backup.service.ts | 8 ++-- .../AddBackupPage/AddBackupPage.constants.ts | 40 +---------------- .../AddBackupPage/AddBackupPage.test.tsx | 14 +++--- .../AddBackupPage/AddBackupPage.tsx | 44 ++++++++++++------- .../AddBackupPage/AddBackupPage.types.ts | 4 +- .../AddBackupPage/AddBackupPage.utils.ts | 17 +++++-- .../BackupInventory.service.ts | 8 +++- .../BackupInventory/BackupInventory.types.ts | 6 +-- .../BackupInventoryDetails.test.tsx | 4 +- .../BackupInventoryDetails.types.ts | 4 +- .../ScheduledBackups.types.ts | 6 +-- .../ScheduledBackupsDetails.test.tsx | 4 +- .../ScheduledBackupsDetails.types.ts | 4 +- 13 files changed, 77 insertions(+), 86 deletions(-) diff --git a/public/app/percona/backup/Backup.service.ts b/public/app/percona/backup/Backup.service.ts index 56775b208ba8c..e0ece5ce7ea44 100644 --- a/public/app/percona/backup/Backup.service.ts +++ b/public/app/percona/backup/Backup.service.ts @@ -4,7 +4,7 @@ import { api } from 'app/percona/shared/helpers/api'; import { getCronStringFromValues } from '../shared/helpers/cron/cron'; -import { BackupMode, BackupType, DataModel, RetryMode } from './Backup.types'; +import { BackupMode, BackupType, Compression, DataModel, RetryMode } from './Backup.types'; import { AddBackupFormProps } from './components/AddBackupPage/AddBackupPage.types'; const BASE_URL = '/v1/backups'; @@ -99,7 +99,7 @@ export const BackupService = { retryTimes: number, dataModel: DataModel, folder: string, - compression: string, + compression: Compression, token?: CancelToken ) { return api.post( @@ -132,7 +132,7 @@ export const BackupService = { mode: BackupMode, dataModel: DataModel, folder: string, - compression: string + compression: Compression ) { return api.post(`${BASE_URL}:schedule`, { service_id: serviceId, @@ -159,7 +159,7 @@ export const BackupService = { retryInterval: string, retryTimes: number, retention: number, - compression: string + compression: Compression ) { return api.put(`${BASE_URL}:changeScheduled`, { scheduled_backup_id: id, diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts index 299554a1ba01f..089736ed93f3f 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.constants.ts @@ -1,5 +1,5 @@ import { SelectableValue } from '@grafana/data'; -import { DataModel, RetryMode, Compression } from 'app/percona/backup/Backup.types'; +import { DataModel, RetryMode } from 'app/percona/backup/Backup.types'; import { Databases, DATABASE_LABELS } from 'app/percona/shared/core'; import { capitalizeText } from 'app/percona/shared/helpers/capitalizeText'; import { MONTHS, WEEKDAYS } from 'app/percona/shared/helpers/cron/constants'; @@ -88,41 +88,3 @@ export const MAX_RETENTION = 99; export const MAX_BACKUP_NAME = 100; -export const COMPRESSION_OPTIONS: Array> = [ - { - value: Compression.DEFAULT, - label: 'Default', - }, - { - value: Compression.NONE, - label: 'No compression', - }, - { - value: Compression.QUICKLZ, - label: 'QuickLZ compression', - }, - { - value: Compression.ZSTD, - label: 'Zstandard compression', - }, - { - value: Compression.LZ4, - label: 'LZ4 compression', - }, - { - value: Compression.S2, - label: 'S2 compression', - }, - { - value: Compression.GZIP, - label: 'Gzip compression', - }, - { - value: Compression.SNAPPY, - label: 'Snappy compression', - }, - { - value: Compression.PGZIP, - label: 'Parallel Gzip compression', - }, -]; diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx index 005e661527e1b..6650529053e26 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.test.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react'; -import { FC, PropsWithChildren } from 'react'; +import { act, FC, PropsWithChildren } from 'react'; import { Provider } from 'react-redux'; import { MemoryRouter } from 'react-router-dom-v5-compat'; @@ -167,9 +167,13 @@ describe('AddBackupPage', () => { await waitFor(() => expect(screen.getAllByText('Choose')).toHaveLength(2)); const advancedSettingsButton = screen.getByTestId('add-backup-advanced-settings'); - fireEvent.click(advancedSettingsButton); - - expect(screen.getByTestId('compression-select-input')).toBeInTheDocument(); - expect(screen.getByText(Messages.compression)).toBeInTheDocument(); + act(() => { + fireEvent.click(advancedSettingsButton); + }); + + await waitFor(() => { + expect(screen.getByTestId('compression-select-input')).toBeInTheDocument(); + expect(screen.getByText(Messages.compression)).toBeInTheDocument(); + }); }); }); diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx index 7b5fca887c885..5228c0dec367a 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.tsx @@ -32,7 +32,7 @@ import { PageSwitcherCard } from '../../../shared/components/Elements/PageSwitch import { BACKUP_INVENTORY_URL, BACKUP_SCHEDULED_URL } from '../../Backup.constants'; import { Messages as MessagesBackup } from '../../Backup.messages'; import { BackupService } from '../../Backup.service'; -import { BackupMode, BackupType, DataModel } from '../../Backup.types'; +import { BackupMode, BackupType, Compression, DataModel } from '../../Backup.types'; import { BackupErrorSection } from '../BackupErrorSection/BackupErrorSection'; import { BACKUP_CANCEL_TOKEN, LIST_ARTIFACTS_CANCEL_TOKEN } from '../BackupInventory/BackupInventory.constants'; import { BackupInventoryService } from '../BackupInventory/BackupInventory.service'; @@ -42,13 +42,14 @@ import { ScheduledBackupsService } from '../ScheduledBackups/ScheduledBackups.se import { ScheduledBackup } from '../ScheduledBackups/ScheduledBackups.types'; import { LocationType } from '../StorageLocations/StorageLocations.types'; -import { COMPRESSION_OPTIONS, DATA_MODEL_OPTIONS, MAX_BACKUP_NAME } from './AddBackupPage.constants'; +import { DATA_MODEL_OPTIONS, MAX_BACKUP_NAME } from './AddBackupPage.constants'; import { Messages } from './AddBackupPage.messages'; import { AddBackupPageService } from './AddBackupPage.service'; import { getStyles } from './AddBackupPage.styles'; import { AddBackupFormProps, SelectableService } from './AddBackupPage.types'; import { getBackupModeOptions, + getCompressionOptionFromValue, getDataModelFromVendor, getLabelForStorageOption, isDataModelDisabled, @@ -113,6 +114,14 @@ const AddBackupPage: FC = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + const loadCompressionOptions = useCallback(async (serviceId?: string) => { + if (!serviceId) { + return [getCompressionOptionFromValue(Compression.DEFAULT)]; + } + const methods = await BackupInventoryService.listServiceCompressions(serviceId); + return methods.map((m) => getCompressionOptionFromValue(m)); + }, []); + const handleBackup = async (values: AddBackupFormProps) => { try { await BackupService.backup(values, generateToken(BACKUP_CANCEL_TOKEN)); @@ -357,21 +366,22 @@ const AddBackupPage: FC = () => { > - - {({ input }) => ( - - )} - - + + {({ input }) => ( + loadCompressionOptions(values.service?.value?.id)} + className={styles.selectField} + data-testid="compression-select-input" + {...input} + /> + )} + + ; + compression: SelectableValue; } diff --git a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts index 7a50fbba4a127..578b8bd5b101f 100644 --- a/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts +++ b/public/app/percona/backup/components/AddBackupPage/AddBackupPage.utils.ts @@ -10,7 +10,6 @@ import { Backup } from '../BackupInventory/BackupInventory.types'; import { ScheduledBackup } from '../ScheduledBackups/ScheduledBackups.types'; import { LocationType } from '../StorageLocations/StorageLocations.types'; -import { COMPRESSION_OPTIONS } from './AddBackupPage.constants'; import { AddBackupFormProps } from './AddBackupPage.types'; import { ScheduleSectionFields as ScheduleSectionFieldsEnum, @@ -55,6 +54,16 @@ const getBackupType = (backup: Backup | ScheduledBackup | null): BackupType => { return BackupType.DEMAND; }; +const compressionValueToKeyMap: Record = Object.fromEntries( + Object.entries(Compression).map(([key, val]) => [val, key]) +); + +export const getCompressionOptionFromValue = (value: Compression): SelectableValue => ({ + value, + label: compressionValueToKeyMap[value] ?? value, +}); + + export const toFormBackup = (backup: Backup | ScheduledBackup | null, scheduleMode?: boolean): AddBackupFormProps => { if (!backup) { return { @@ -80,7 +89,7 @@ export const toFormBackup = (backup: Backup | ScheduledBackup | null, scheduleMo mode: BackupMode.SNAPSHOT, type: scheduleMode ? BackupType.SCHEDULED : getBackupType(backup), folder: '', - compression: COMPRESSION_OPTIONS.find((option) => option.value === Compression.NONE)!, + compression: getCompressionOptionFromValue(Compression.DEFAULT), }; } @@ -132,7 +141,7 @@ export const toFormBackup = (backup: Backup | ScheduledBackup | null, scheduleMo mode, type: BackupType.SCHEDULED, folder, - compression: COMPRESSION_OPTIONS.find((option) => option.value === backup.compression)!, + compression: getCompressionOptionFromValue(backup.compression), }; } else { return { @@ -149,7 +158,7 @@ export const toFormBackup = (backup: Backup | ScheduledBackup | null, scheduleMo retryInterval: 30, type: BackupType.DEMAND, folder, - compression: COMPRESSION_OPTIONS.find((option) => option.value === backup.compression)!, + compression: getCompressionOptionFromValue(backup.compression), }; } }; diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts b/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts index 91edc377bd993..181ce06056811 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts +++ b/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts @@ -4,7 +4,7 @@ import { SelectableValue } from '@grafana/data'; import { DBServiceList, CompatibleServiceListPayload } from 'app/percona/inventory/Inventory.types'; import { api } from 'app/percona/shared/helpers/api'; -import { BackupLogResponse, BackupLogs, DataModel } from '../../Backup.types'; +import { BackupLogResponse, BackupLogs, Compression, DataModel } from '../../Backup.types'; import { Backup, BackupResponse, Timeranges, TimerangesResponse } from './BackupInventory.types'; import { formatDate } from './BackupInventory.utils'; @@ -124,4 +124,10 @@ export const BackupInventoryService = { return result; }, + async listServiceCompressions(serviceId: string): Promise { + const { compression_methods = [] } = await api.get<{ compression_methods?: Compression[] }, void>( + `${BASE_URL}/services/${serviceId}/compression` + ); + return compression_methods; + }, }; diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts b/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts index c07906b71628e..2ea19782658dc 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts +++ b/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts @@ -1,6 +1,6 @@ import { Databases } from 'app/percona/shared/core'; -import { DataModel, BackupStatus, BackupMode } from '../../Backup.types'; +import { DataModel, BackupStatus, BackupMode, Compression } from '../../Backup.types'; import { StorageLocation } from '../StorageLocations/StorageLocations.types'; export interface Backup { @@ -17,7 +17,7 @@ export interface Backup { mode: BackupMode; folder: string; type?: Databases | 'external'; - compression: string; + compression: Compression; } export interface BackupRow extends Backup { @@ -37,7 +37,7 @@ export interface RawBackup { vendor: Databases; mode: BackupMode; folder: string; - compression: string; + compression: Compression; } export interface BackupResponse { diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.test.tsx b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.test.tsx index df1441b8209b3..2531d560062ab 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.test.tsx +++ b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.test.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react'; -import { DataModel, BackupStatus } from 'app/percona/backup/Backup.types'; +import { Compression, DataModel, BackupStatus } from 'app/percona/backup/Backup.types'; import { BackupInventoryDetails } from './BackupInventoryDetails'; @@ -12,7 +12,7 @@ describe('BackupInventoryDetails', () => { status={BackupStatus.BACKUP_STATUS_PAUSED} dataModel={DataModel.LOGICAL} folder="folder1" - compression="NONE" + compression={Compression.NONE} /> ); expect(screen.getByTestId('backup-artifact-details-name')).toBeInTheDocument(); diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.types.ts b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.types.ts index e1f95b65ffb76..5d8a9f4503b2a 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.types.ts +++ b/public/app/percona/backup/components/BackupInventory/BackupInventoryDetails/BackupInventoryDetails.types.ts @@ -1,9 +1,9 @@ -import { BackupStatus, DataModel, RestoreStatus } from 'app/percona/backup/Backup.types'; +import { BackupStatus, Compression, DataModel, RestoreStatus } from 'app/percona/backup/Backup.types'; export interface BackupInventoryDetailsProps { name: string; status: BackupStatus | RestoreStatus; dataModel: DataModel; folder: string; - compression: string; + compression: Compression; } diff --git a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.types.ts b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.types.ts index fb703690b059a..74a8e6c5bb992 100644 --- a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.types.ts +++ b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackups.types.ts @@ -1,6 +1,6 @@ import { Databases } from 'app/percona/shared/core'; -import { BackupMode, DataModel } from '../../Backup.types'; +import { BackupMode, Compression, DataModel } from '../../Backup.types'; export interface RawScheduledBackup { scheduled_backup_id: string; @@ -21,7 +21,7 @@ export interface RawScheduledBackup { retention: number; mode: BackupMode; folder: string; - compression: string; + compression: Compression; } export interface ScheduledBackupResponse { @@ -47,5 +47,5 @@ export interface ScheduledBackup { mode: BackupMode; enabled: boolean; folder: string; - compression: string; + compression: Compression; } diff --git a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.test.tsx b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.test.tsx index 1b3f820644e7a..c7905cb4817d6 100644 --- a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.test.tsx +++ b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.test.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react'; -import { DataModel } from 'app/percona/backup/Backup.types'; +import { Compression, DataModel } from 'app/percona/backup/Backup.types'; import { ScheduledBackupDetails } from './ScheduledBackupsDetails'; @@ -13,7 +13,7 @@ describe('ScheduledBackupsDetails', () => { dataModel={DataModel.PHYSICAL} cronExpression=" * * * 1,3 0" folder="folder1" - compression="NONE" + compression={Compression.NONE} /> ); expect(screen.getByTestId('scheduled-backup-details-wrapper')).toBeInTheDocument(); diff --git a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.types.ts b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.types.ts index 1eef23b412837..d3f07ae35f784 100644 --- a/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.types.ts +++ b/public/app/percona/backup/components/ScheduledBackups/ScheduledBackupsDetails/ScheduledBackupsDetails.types.ts @@ -1,4 +1,4 @@ -import { DataModel } from 'app/percona/backup/Backup.types'; +import { Compression, DataModel } from 'app/percona/backup/Backup.types'; export interface ScheduledBackupDetailsProps { name: string; @@ -6,5 +6,5 @@ export interface ScheduledBackupDetailsProps { dataModel: DataModel; cronExpression: string; folder: string; - compression: string; + compression: Compression; } From 7bf6249ad05e8321d30457cc7765e3049d2f7df2 Mon Sep 17 00:00:00 2001 From: the-wunmi Date: Thu, 28 Aug 2025 22:04:00 +0100 Subject: [PATCH 6/6] Update BackupInventory service to utilize CompressionResponse type and add CompressionResponse interface for improved type safety --- .../components/BackupInventory/BackupInventory.service.ts | 4 ++-- .../components/BackupInventory/BackupInventory.types.ts | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts b/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts index 181ce06056811..8520f30950b30 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts +++ b/public/app/percona/backup/components/BackupInventory/BackupInventory.service.ts @@ -6,7 +6,7 @@ import { api } from 'app/percona/shared/helpers/api'; import { BackupLogResponse, BackupLogs, Compression, DataModel } from '../../Backup.types'; -import { Backup, BackupResponse, Timeranges, TimerangesResponse } from './BackupInventory.types'; +import { Backup, BackupResponse, CompressionResponse, Timeranges, TimerangesResponse } from './BackupInventory.types'; import { formatDate } from './BackupInventory.utils'; const BASE_URL = '/v1/backups'; @@ -125,7 +125,7 @@ export const BackupInventoryService = { return result; }, async listServiceCompressions(serviceId: string): Promise { - const { compression_methods = [] } = await api.get<{ compression_methods?: Compression[] }, void>( + const { compression_methods = [] } = await api.get( `${BASE_URL}/services/${serviceId}/compression` ); return compression_methods; diff --git a/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts b/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts index 2ea19782658dc..ee944d2aaed70 100644 --- a/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts +++ b/public/app/percona/backup/components/BackupInventory/BackupInventory.types.ts @@ -57,3 +57,7 @@ export interface Timeranges { export interface TimerangesResponse { timeranges: RawTimeranges[]; } + +export interface CompressionResponse { + compression_methods: Compression[]; +}