feat(admin): add H2 database backup & restore management to admin UI (#5528)

# Description of Changes

This PR introduces comprehensive database backup and restore management
for embedded H2 databases directly within the admin UI, along with a
corrected backend condition for H2 detection.

### What was changed
- Fixed `H2SQLCondition` logic so embedded H2 is correctly detected when
custom databases are disabled.
- Updated and expanded unit tests to reflect the corrected H2 enablement
behavior.
- Added a new **Backups & Restore** section to the Admin Database
settings UI.
- Implemented UI features to:
  - Create H2 database backups
  - List available backup files with metadata
  - Download, import, and delete existing backups
- Upload and import `.sql` backup files with a confirmation code safety
step
- Added a new frontend service (`databaseManagementService`) to
encapsulate database management API calls.
- Extended English (en-GB) translations for all new database backup and
restore UI elements.

### Why the change was made
- Embedded H2 is the default database when no custom database is
configured, but this was not consistently reflected in backend
conditions.
- Administrators need a safe, UI-driven way to manage H2 backups without
manual filesystem access.
- The new UI improves operability, safety (confirmation code on import),
and transparency (version and status badges).

<img width="1920" height="1080" alt="image"
src="https://github.com/user-attachments/assets/15869b9c-fa86-4b31-ac9b-8e6424138b73"
/>
<img width="1920" height="1032" alt="image"
src="https://github.com/user-attachments/assets/8668dc07-0384-40f0-91e1-c6973c1ce535"
/>


Closes #5515

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
This commit is contained in:
Ludy
2026-01-22 19:16:30 +00:00
committed by GitHub
parent df1295059a
commit 56f788957a
5 changed files with 727 additions and 127 deletions
@@ -12,8 +12,9 @@ public class H2SQLCondition implements Condition {
boolean enableCustomDatabase =
env.getProperty("system.datasource.enableCustomDatabase", Boolean.class, false);
if (enableCustomDatabase) {
return false;
// If custom database is not enabled, H2 is used by default
if (!enableCustomDatabase) {
return true;
}
String dataSourceType = env.getProperty("system.datasource.type", String.class, "");
@@ -36,12 +36,12 @@ class H2SQLConditionTest {
@Test
void returnsFalse_whenEnableCustomDatabase_true_regardlessOfType() {
// Flag=true, Typ=h2 -> false
// Flag=true, Typ=h2 -> true
MockEnvironment envTrueH2 =
new MockEnvironment()
.withProperty("system.datasource.enableCustomDatabase", "true")
.withProperty("system.datasource.type", "h2");
assertFalse(eval(envTrueH2));
assertTrue(eval(envTrueH2));
// Flag=true, Typ=postgres -> false
MockEnvironment envTrueOther =
@@ -57,20 +57,6 @@ class H2SQLConditionTest {
assertFalse(eval(envTrueMissingType));
}
@Test
void returnsFalse_whenTypeNotH2_orMissing_andFlagNotEnabled() {
// Flag fehlt, Typ=postgres -> false
MockEnvironment envNotH2 =
new MockEnvironment().withProperty("system.datasource.type", "postgresql");
assertFalse(eval(envNotH2));
// Flag=false, Typ fehlt -> false (Default: "")
MockEnvironment envMissingType =
new MockEnvironment()
.withProperty("system.datasource.enableCustomDatabase", "false");
assertFalse(eval(envMissingType));
}
@Test
void returnsFalse_whenEnabled_but_type_not_h2_or_missing() {
MockEnvironment envNotH2 =
@@ -84,4 +70,18 @@ class H2SQLConditionTest {
.withProperty("system.datasource.enableCustomDatabase", "true");
assertFalse(eval(envMissingType));
}
@Test
void returnsTrue_whenTypeNotH2_andCustomDatabaseDisabled() {
MockEnvironment envNotH2 =
new MockEnvironment()
.withProperty("system.datasource.enableCustomDatabase", "false")
.withProperty("system.datasource.type", "postgresql");
assertTrue(eval(envNotH2));
MockEnvironment envMissingType =
new MockEnvironment()
.withProperty("system.datasource.enableCustomDatabase", "false");
assertTrue(eval(envMissingType));
}
}