diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4c2a7238..a3a4bc29 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,51 +1,47 @@ { - "name": "Go", - "build": { - "dockerfile": "Dockerfile", - "args": { - // Update the VARIANT arg to pick a version of Go: 1, 1.16, 1.17 - // Append -bullseye or -buster to pin to an OS version. - // Use -bullseye variants on local arm64/Apple Silicon. - "VARIANT": "1-1.21-bookworm", - // Options - "NODE_VERSION": "lts/*" - } - }, - "runArgs": [ - "--cap-add=SYS_PTRACE", - "--security-opt", - "seccomp=unconfined" - ], - "customizations": { - "vscode": { - // Set *default* container specific settings.json values on container create. - "settings": { - "go.toolsManagement.checkForUpdates": "local", - "go.useLanguageServer": true, - "go.gopath": "/go", - "go.goroot": "/usr/local/go", - "typescript.tsdk": "webui/node_modules/typescript/lib", - "typescript.enablePromptUseWorkspaceTsdk": true, - "gitlens.telemetry.enabled": false - }, - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "golang.Go", - "ms-azuretools.vscode-docker", - "mhutchie.git-graph", - "eamodio.gitlens", - "donjayamanne.githistory", - "esbenp.prettier-vscode", - "iulian-radu-at.vscode-tasks-sidebar" - ] - } - }, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], + "name": "Go", + "build": { + "dockerfile": "Dockerfile", + "args": { + // Update the VARIANT arg to pick a version of Go: 1, 1.16, 1.17 + // Append -bullseye or -buster to pin to an OS version. + // Use -bullseye variants on local arm64/Apple Silicon. + "VARIANT": "1-1.21-bookworm", + // Options + "NODE_VERSION": "lts/*" + } + }, + "runArgs": ["--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"], + "customizations": { + "vscode": { + // Set *default* container specific settings.json values on container create. + "settings": { + "go.toolsManagement.checkForUpdates": "local", + "go.useLanguageServer": true, + "go.gopath": "/go", + "go.goroot": "/usr/local/go", + "typescript.tsdk": "webui/node_modules/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true, + "gitlens.telemetry.enabled": false + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "golang.Go", + "ms-azuretools.vscode-docker", + "mhutchie.git-graph", + "eamodio.gitlens", + "donjayamanne.githistory", + "esbenp.prettier-vscode", + "iulian-radu-at.vscode-tasks-sidebar" + ] + } + }, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "go version", - - // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - "remoteUser": "vscode" -} \ No newline at end of file + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "go version", + + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" +} diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index be30ec61..fcc8ade0 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,10 +1,9 @@ --- name: Bug report about: Report an issue with Backrest -title: '' +title: "" labels: bug -assignees: '' - +assignees: "" --- Note: if you have a question or need support please post in the [discussions area](https://github.com/garethgeorge/backrest/discussions). @@ -14,6 +13,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -26,8 +26,9 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Platform Info** - - OS and Architecture [e.g. Windows 10 x64, Darwin arm64] - - Backrest Version [e.g. 0.0.0] + +- OS and Architecture [e.g. Windows 10 x64, Darwin arm64] +- Backrest Version [e.g. 0.0.0] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index f3194856..7c4af7e1 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,10 +1,9 @@ --- name: Feature request about: Suggest an idea for this project -title: '' +title: "" labels: enhancement -assignees: '' - +assignees: "" --- Note: if you have a question or want discussion please post in the [discussions area](https://github.com/garethgeorge/backrest/discussions). diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 18587a72..ccf5148e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,6 +32,8 @@ jobs: with: node-version: "20" + - name: Check Formatting + - name: Generate run: go generate ./... diff --git a/.vscode/launch.json b/.vscode/launch.json index bad15f0b..6893fe39 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,36 +1,33 @@ { - "version": "0.2.0", - "configurations": [ - { - "name": "Debug Go backend", - "type": "go", - "request": "launch", - "mode": "debug", - "program": "${workspaceFolder}/backrest.go", - "output": "__debug_bin", - "preLaunchTask": "Build Webui", - }, - { - "type": "chrome", - "request": "launch", - "preLaunchTask": "Parcel", - "postDebugTask": "Terminate Parcel", - "name": "Debug TS frontend", - "url": "http://localhost:1234", - "webRoot": "${workspaceFolder}/webui/src/", - "sourceMapPathOverrides": { - "../*": "${webRoot}/*" - } - } - ], - "compounds": [ - { - "name": "Debug Backrest (backend+frontend)", - "configurations": [ - "Debug Go backend", - "Debug TS frontend" - ], - "stopAll": true - } - ] -} \ No newline at end of file + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Go backend", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${workspaceFolder}/backrest.go", + "output": "__debug_bin", + "preLaunchTask": "Build Webui" + }, + { + "type": "chrome", + "request": "launch", + "preLaunchTask": "Parcel", + "postDebugTask": "Terminate Parcel", + "name": "Debug TS frontend", + "url": "http://localhost:1234", + "webRoot": "${workspaceFolder}/webui/src/", + "sourceMapPathOverrides": { + "../*": "${webRoot}/*" + } + } + ], + "compounds": [ + { + "name": "Debug Backrest (backend+frontend)", + "configurations": ["Debug Go backend", "Debug TS frontend"], + "stopAll": true + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a012b73f..7301b866 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,51 +1,51 @@ { - "version": "2.0.0", - "tasks": [ - { - "label": "npm i", - "type": "shell", - "command": "cd webui && npm i", + "version": "2.0.0", + "tasks": [ + { + "label": "npm i", + "type": "shell", + "command": "cd webui && npm i" + }, + { + "label": "Parcel", + "type": "npm", + "script": "start", + "dependsOn": "npm i", + "isBackground": true, + "problemMatcher": { + "background": { + "activeOnStart": true, + "beginsPattern": "parcel serve", + "endsPattern": "Built in" }, - { - "label": "Parcel", - "type": "npm", - "script": "start", - "dependsOn": "npm i", - "isBackground": true, - "problemMatcher": { - "background": { - "activeOnStart": true, - "beginsPattern": "parcel serve", - "endsPattern": "Built in" - }, - "pattern": { - "regexp": ".*" - } - }, - "path": "webui" - }, - { - "label": "Build Webui", - "type": "npm", - "script": "build", - "path": "webui", - "group": "build", - "problemMatcher": [], - "dependsOn": "npm i" - }, - { - "label": "Terminate Parcel", - "command": "echo ${input:terminate}", - "type": "shell", - "problemMatcher": [] - } - ], - "inputs": [ - { - "id": "terminate", - "type": "command", - "command": "workbench.action.tasks.terminate", - "args": "Parcel" + "pattern": { + "regexp": ".*" } - ] -} \ No newline at end of file + }, + "path": "webui" + }, + { + "label": "Build Webui", + "type": "npm", + "script": "build", + "path": "webui", + "group": "build", + "problemMatcher": [], + "dependsOn": "npm i" + }, + { + "label": "Terminate Parcel", + "command": "echo ${input:terminate}", + "type": "shell", + "problemMatcher": [] + } + ], + "inputs": [ + { + "id": "terminate", + "type": "command", + "command": "workbench.action.tasks.terminate", + "args": "Parcel" + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 7070cf1e..2343dc9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,494 +2,453 @@ ## [0.17.2](https://github.com/garethgeorge/backrest/compare/v0.17.1...v0.17.2) (2024-04-18) - ### Bug Fixes -* add tini to docker images to reap rclone processes left behind by restic ([6408518](https://github.com/garethgeorge/backrest/commit/6408518582fb2a1b529f5c9fb0c595df230f3df6)) -* armv7 support for docker releases ([ec39533](https://github.com/garethgeorge/backrest/commit/ec39533e4cddf2f0354ec3fcb4c52ba37a9b00ec)) -* bug in new task queue implementation ([5d6074e](https://github.com/garethgeorge/backrest/commit/5d6074eb296e6737f1959fba913c67e09e60ef47)) -* improve restic pkg's output handling and buffering ([aacdf9b](https://github.com/garethgeorge/backrest/commit/aacdf9b7cd529a6f677cd7f1d9ed2fbbcadc9b8a)) -* Linux ./install.sh script fails when used for updating backrest ([#226](https://github.com/garethgeorge/backrest/issues/226)) ([be09303](https://github.com/garethgeorge/backrest/commit/be0930368b83ba8f159b28bc286300c56bd6a3a3)) -* use new orchestrator queue ([4a81889](https://github.com/garethgeorge/backrest/commit/4a81889d810d409ed42fcf07a0fa6a4ac97db72b)) +- add tini to docker images to reap rclone processes left behind by restic ([6408518](https://github.com/garethgeorge/backrest/commit/6408518582fb2a1b529f5c9fb0c595df230f3df6)) +- armv7 support for docker releases ([ec39533](https://github.com/garethgeorge/backrest/commit/ec39533e4cddf2f0354ec3fcb4c52ba37a9b00ec)) +- bug in new task queue implementation ([5d6074e](https://github.com/garethgeorge/backrest/commit/5d6074eb296e6737f1959fba913c67e09e60ef47)) +- improve restic pkg's output handling and buffering ([aacdf9b](https://github.com/garethgeorge/backrest/commit/aacdf9b7cd529a6f677cd7f1d9ed2fbbcadc9b8a)) +- Linux ./install.sh script fails when used for updating backrest ([#226](https://github.com/garethgeorge/backrest/issues/226)) ([be09303](https://github.com/garethgeorge/backrest/commit/be0930368b83ba8f159b28bc286300c56bd6a3a3)) +- use new orchestrator queue ([4a81889](https://github.com/garethgeorge/backrest/commit/4a81889d810d409ed42fcf07a0fa6a4ac97db72b)) ## [0.17.1](https://github.com/garethgeorge/backrest/compare/v0.17.0...v0.17.1) (2024-04-12) - ### Bug Fixes -* revert orchestrator changes ([07cffcb](https://github.com/garethgeorge/backrest/commit/07cffcb5d8dc018631fcd0d1f98cc01553a6574e)) +- revert orchestrator changes ([07cffcb](https://github.com/garethgeorge/backrest/commit/07cffcb5d8dc018631fcd0d1f98cc01553a6574e)) ## [0.17.0](https://github.com/garethgeorge/backrest/compare/v0.16.0...v0.17.0) (2024-04-12) - ### Features -* add a Bash script to help Linux user manage Backrest ([#187](https://github.com/garethgeorge/backrest/issues/187)) ([d78bcfa](https://github.com/garethgeorge/backrest/commit/d78bcfab845a86523868a91fe200b2a3c4c07e07)) -* allow hook exit codes to control backup execution (e.g fail, skip, etc) ([c4ae5b3](https://github.com/garethgeorge/backrest/commit/c4ae5b3f2257d6c04ed08188cfc509023137b460)) -* release backrest as a homebrew tap ([16a7d0e](https://github.com/garethgeorge/backrest/commit/16a7d0e95ae51c9f86e2d38e2c494b324245a9db)) -* use amd64 restic for arm64 Windows ([#201](https://github.com/garethgeorge/backrest/issues/201)) ([3770966](https://github.com/garethgeorge/backrest/commit/3770966111f096c84b4702e6639397e8efab93a7)) -* use new task queue implementation in orchestrator ([1d04898](https://github.com/garethgeorge/backrest/commit/1d0489847e6fee5baed807117379738aceca4a2d)) - +- add a Bash script to help Linux user manage Backrest ([#187](https://github.com/garethgeorge/backrest/issues/187)) ([d78bcfa](https://github.com/garethgeorge/backrest/commit/d78bcfab845a86523868a91fe200b2a3c4c07e07)) +- allow hook exit codes to control backup execution (e.g fail, skip, etc) ([c4ae5b3](https://github.com/garethgeorge/backrest/commit/c4ae5b3f2257d6c04ed08188cfc509023137b460)) +- release backrest as a homebrew tap ([16a7d0e](https://github.com/garethgeorge/backrest/commit/16a7d0e95ae51c9f86e2d38e2c494b324245a9db)) +- use amd64 restic for arm64 Windows ([#201](https://github.com/garethgeorge/backrest/issues/201)) ([3770966](https://github.com/garethgeorge/backrest/commit/3770966111f096c84b4702e6639397e8efab93a7)) +- use new task queue implementation in orchestrator ([1d04898](https://github.com/garethgeorge/backrest/commit/1d0489847e6fee5baed807117379738aceca4a2d)) ### Bug Fixes -* address minor data race in command output handling and enable --race in coverage ([3223138](https://github.com/garethgeorge/backrest/commit/32231385ed20c0dccda12361eaac7cc088ec15a0)) -* bugs in refactored task queue and improved coverage ([834b74f](https://github.com/garethgeorge/backrest/commit/834b74f0f3eec42055d1af6ecfe34d448f71d97b)) -* cannot set retention policy buckets to 0 ([7e9bf15](https://github.com/garethgeorge/backrest/commit/7e9bf15976006c7f3ff96948d2b2c291737c9e88)) -* **css:** fixing overflow issue ([#191](https://github.com/garethgeorge/backrest/issues/191)) ([1d9e43e](https://github.com/garethgeorge/backrest/commit/1d9e43e49b21adc4ed8ce1ec96199084981d709a)) -* default BACKREST_PORT to 127.0.0.1:9898 (localhost only) when using install.sh ([eb07230](https://github.com/garethgeorge/backrest/commit/eb07230cc0843643406fa44ca21c3a138baced77)) -* handle backpressure correctly in event stream ([4e2bf1f](https://github.com/garethgeorge/backrest/commit/4e2bf1f76c4d35d61fc48111baaa33b7b7a8c133)) -* improve tooltips on AddRepoModal ([e2be189](https://github.com/garethgeorge/backrest/commit/e2be189f9e4bb617a69e4b9c15da3d1920549349)) -* include ioutil helpers ([88a926b](https://github.com/garethgeorge/backrest/commit/88a926b0a3a52efb82da5df3423a001ed140639c)) -* limit cmd log length to 32KB per operation ([92d52be](https://github.com/garethgeorge/backrest/commit/92d52bed8e84d6cd8dd331a1fa52a6e2d30cb7a7)) -* misc UI and backend bug fixes ([e96f403](https://github.com/garethgeorge/backrest/commit/e96f4036df6849650d6e378c9a175fef86b2962b)) -* refactor priority ordered task queue implementation ([8b9280e](https://github.com/garethgeorge/backrest/commit/8b9280ed57b84b7da814e285542c57b7c14209ae)) -* spawn goroutine to update oplog with progress during backup/restore ([eab1c1b](https://github.com/garethgeorge/backrest/commit/eab1c1bffe2a1aec6afa9e054278ff98ca3047cf)) -* use C:\Program Files\backrest on both x64 and 32-bit ([#200](https://github.com/garethgeorge/backrest/issues/200)) ([7b0d3aa](https://github.com/garethgeorge/backrest/commit/7b0d3aa1be7bc93363b00154d09502b4e4e63ba5)) +- address minor data race in command output handling and enable --race in coverage ([3223138](https://github.com/garethgeorge/backrest/commit/32231385ed20c0dccda12361eaac7cc088ec15a0)) +- bugs in refactored task queue and improved coverage ([834b74f](https://github.com/garethgeorge/backrest/commit/834b74f0f3eec42055d1af6ecfe34d448f71d97b)) +- cannot set retention policy buckets to 0 ([7e9bf15](https://github.com/garethgeorge/backrest/commit/7e9bf15976006c7f3ff96948d2b2c291737c9e88)) +- **css:** fixing overflow issue ([#191](https://github.com/garethgeorge/backrest/issues/191)) ([1d9e43e](https://github.com/garethgeorge/backrest/commit/1d9e43e49b21adc4ed8ce1ec96199084981d709a)) +- default BACKREST_PORT to 127.0.0.1:9898 (localhost only) when using install.sh ([eb07230](https://github.com/garethgeorge/backrest/commit/eb07230cc0843643406fa44ca21c3a138baced77)) +- handle backpressure correctly in event stream ([4e2bf1f](https://github.com/garethgeorge/backrest/commit/4e2bf1f76c4d35d61fc48111baaa33b7b7a8c133)) +- improve tooltips on AddRepoModal ([e2be189](https://github.com/garethgeorge/backrest/commit/e2be189f9e4bb617a69e4b9c15da3d1920549349)) +- include ioutil helpers ([88a926b](https://github.com/garethgeorge/backrest/commit/88a926b0a3a52efb82da5df3423a001ed140639c)) +- limit cmd log length to 32KB per operation ([92d52be](https://github.com/garethgeorge/backrest/commit/92d52bed8e84d6cd8dd331a1fa52a6e2d30cb7a7)) +- misc UI and backend bug fixes ([e96f403](https://github.com/garethgeorge/backrest/commit/e96f4036df6849650d6e378c9a175fef86b2962b)) +- refactor priority ordered task queue implementation ([8b9280e](https://github.com/garethgeorge/backrest/commit/8b9280ed57b84b7da814e285542c57b7c14209ae)) +- spawn goroutine to update oplog with progress during backup/restore ([eab1c1b](https://github.com/garethgeorge/backrest/commit/eab1c1bffe2a1aec6afa9e054278ff98ca3047cf)) +- use C:\Program Files\backrest on both x64 and 32-bit ([#200](https://github.com/garethgeorge/backrest/issues/200)) ([7b0d3aa](https://github.com/garethgeorge/backrest/commit/7b0d3aa1be7bc93363b00154d09502b4e4e63ba5)) ## [0.16.0](https://github.com/garethgeorge/backrest/compare/v0.15.1...v0.16.0) (2024-03-30) - ### Features -* allow disabling authentication ([8429174](https://github.com/garethgeorge/backrest/commit/84291746af5fc863f90bcf7ae9ba5a2d3ca26cdd)) -* improve consistency of restic command execution and output capture ([16e22aa](https://github.com/garethgeorge/backrest/commit/16e22aa623c5a0a6e6b0e6df12a8e3d09c2ff31f)) -* improve observability by exposing restic command logs in UI ([eeb8c8e](https://github.com/garethgeorge/backrest/commit/eeb8c8e6b377f96c0c39bd2b169b86986933d570)) -* make hostname configurable in settings panel ([2e4e3cf](https://github.com/garethgeorge/backrest/commit/2e4e3cf9c78cac587a3a40635ec068726b3f4d2d)) -* sort lists in configuration ([6f330ac](https://github.com/garethgeorge/backrest/commit/6f330ac37b8ce621fbe82594c41d6f5091f03dfd)) -* support shoutrrr notification service ([fa6407c](https://github.com/garethgeorge/backrest/commit/fa6407cac25ed8f0a32cc9ed5fdd8454bc9abbe5)) -* switch alpine as the default base image for docker releases ([7425c9b](https://github.com/garethgeorge/backrest/commit/7425c9bb0e08cf650e596ae43a736507313e3f2f)) -* update macos install script to set PATH env var for use with rclone ([8cf43f2](https://github.com/garethgeorge/backrest/commit/8cf43f28921ef7182f1c655fa82470e74698d3ce)) - +- allow disabling authentication ([8429174](https://github.com/garethgeorge/backrest/commit/84291746af5fc863f90bcf7ae9ba5a2d3ca26cdd)) +- improve consistency of restic command execution and output capture ([16e22aa](https://github.com/garethgeorge/backrest/commit/16e22aa623c5a0a6e6b0e6df12a8e3d09c2ff31f)) +- improve observability by exposing restic command logs in UI ([eeb8c8e](https://github.com/garethgeorge/backrest/commit/eeb8c8e6b377f96c0c39bd2b169b86986933d570)) +- make hostname configurable in settings panel ([2e4e3cf](https://github.com/garethgeorge/backrest/commit/2e4e3cf9c78cac587a3a40635ec068726b3f4d2d)) +- sort lists in configuration ([6f330ac](https://github.com/garethgeorge/backrest/commit/6f330ac37b8ce621fbe82594c41d6f5091f03dfd)) +- support shoutrrr notification service ([fa6407c](https://github.com/garethgeorge/backrest/commit/fa6407cac25ed8f0a32cc9ed5fdd8454bc9abbe5)) +- switch alpine as the default base image for docker releases ([7425c9b](https://github.com/garethgeorge/backrest/commit/7425c9bb0e08cf650e596ae43a736507313e3f2f)) +- update macos install script to set PATH env var for use with rclone ([8cf43f2](https://github.com/garethgeorge/backrest/commit/8cf43f28921ef7182f1c655fa82470e74698d3ce)) ### Bug Fixes -* add new logs to orchestrator and increase clock change polling to every 5 minutes ([5b7e2b0](https://github.com/garethgeorge/backrest/commit/5b7e2b080d31a2f77a5f9b6737dfbb84cfb63cce)) -* api path relative to UI serving location to support reverse proxies with prefix stripping ([ac7f24e](https://github.com/garethgeorge/backrest/commit/ac7f24ed04679ed6cc3ea779325c0e0b49c9f526)) -* cleanup spacing and hook titles in AddRepoModal and AddPlanModal ([c32874c](https://github.com/garethgeorge/backrest/commit/c32874c1d6fc8292a2fb91f0b22c7146083bc468)) -* correctly auto-expand first 5 backups when opening plan/repo ([d7ca35b](https://github.com/garethgeorge/backrest/commit/d7ca35b66f61c12360905e98b775e3256210176e)) -* include error messages in restic logs ([b68f7c6](https://github.com/garethgeorge/backrest/commit/b68f7c69138d516f84f9fca3040003604bff24e6)) -* include restic binary in alpine and scratch docker images ([f7bd9f7](https://github.com/garethgeorge/backrest/commit/f7bd9f7d0a9c62baedd1a341eb76e836fb00cfa5)) -* incorrectly indicate AM/PM in formatted date strings ([5d34e0b](https://github.com/garethgeorge/backrest/commit/5d34e0bfb5cffd44d971b0e1052574fe640049e7)) -* make notification title optional on discord notifications ([e8bbe2c](https://github.com/garethgeorge/backrest/commit/e8bbe2c8f509de67181750f8451fae841b3fa195)) -* make tree view the default panel for repo overview ([3f9c9f4](https://github.com/garethgeorge/backrest/commit/3f9c9f4ff8bea0f79b03222609d7c302e241bab2)) -* tasks duplicated when config is updated during a running operation ([035684c](https://github.com/garethgeorge/backrest/commit/035684ca343b47dfb3f131c89e15f06e8155f550)) +- add new logs to orchestrator and increase clock change polling to every 5 minutes ([5b7e2b0](https://github.com/garethgeorge/backrest/commit/5b7e2b080d31a2f77a5f9b6737dfbb84cfb63cce)) +- api path relative to UI serving location to support reverse proxies with prefix stripping ([ac7f24e](https://github.com/garethgeorge/backrest/commit/ac7f24ed04679ed6cc3ea779325c0e0b49c9f526)) +- cleanup spacing and hook titles in AddRepoModal and AddPlanModal ([c32874c](https://github.com/garethgeorge/backrest/commit/c32874c1d6fc8292a2fb91f0b22c7146083bc468)) +- correctly auto-expand first 5 backups when opening plan/repo ([d7ca35b](https://github.com/garethgeorge/backrest/commit/d7ca35b66f61c12360905e98b775e3256210176e)) +- include error messages in restic logs ([b68f7c6](https://github.com/garethgeorge/backrest/commit/b68f7c69138d516f84f9fca3040003604bff24e6)) +- include restic binary in alpine and scratch docker images ([f7bd9f7](https://github.com/garethgeorge/backrest/commit/f7bd9f7d0a9c62baedd1a341eb76e836fb00cfa5)) +- incorrectly indicate AM/PM in formatted date strings ([5d34e0b](https://github.com/garethgeorge/backrest/commit/5d34e0bfb5cffd44d971b0e1052574fe640049e7)) +- make notification title optional on discord notifications ([e8bbe2c](https://github.com/garethgeorge/backrest/commit/e8bbe2c8f509de67181750f8451fae841b3fa195)) +- make tree view the default panel for repo overview ([3f9c9f4](https://github.com/garethgeorge/backrest/commit/3f9c9f4ff8bea0f79b03222609d7c302e241bab2)) +- tasks duplicated when config is updated during a running operation ([035684c](https://github.com/garethgeorge/backrest/commit/035684ca343b47dfb3f131c89e15f06e8155f550)) ## [0.15.1](https://github.com/garethgeorge/backrest/compare/v0.15.0...v0.15.1) (2024-03-19) - ### Bug Fixes -* forget operations failing with new retention policy format ([0a059bb](https://github.com/garethgeorge/backrest/commit/0a059bbb39ea6d5f6f989cc4a4541ec8aedbc071)) +- forget operations failing with new retention policy format ([0a059bb](https://github.com/garethgeorge/backrest/commit/0a059bbb39ea6d5f6f989cc4a4541ec8aedbc071)) ## [0.15.0](https://github.com/garethgeorge/backrest/compare/v0.13.0...v0.15.0) (2024-03-19) - ### Features -* add 'compute stats' button to refresh stats on repo view ([1f42b6a](https://github.com/garethgeorge/backrest/commit/1f42b6ab4e0313bbb12e6bc22b561d7544504644)) -* add option to disable scheduled execution of a plan ([aea74c5](https://github.com/garethgeorge/backrest/commit/aea74c51c0fb3908ece57f813c9ae6190e1fd46b)) -* add release artifacts for arm32 ([a737371](https://github.com/garethgeorge/backrest/commit/a737371ed559f5b65e734b0d97c44dcb2749ce53)) -* automatically remove Apples quarantine flag ([#155](https://github.com/garethgeorge/backrest/issues/155)) ([3e76beb](https://github.com/garethgeorge/backrest/commit/3e76bebd054eb7bfc9f8da4681459b863ae50c55)) -* check for basic auth ([#110](https://github.com/garethgeorge/backrest/issues/110)) ([#129](https://github.com/garethgeorge/backrest/issues/129)) ([871c54f](https://github.com/garethgeorge/backrest/commit/871c54f35f8651632714ca7d3a3ab0e809549b51)) -* improved stats visualization with graphs and cleanup operation filtering ([5b362cc](https://github.com/garethgeorge/backrest/commit/5b362ccbb45e59954dad574b93848195d45b55ef)) -* pass through all env variables from parent process to restic ([24afd51](https://github.com/garethgeorge/backrest/commit/24afd514ad80f542e6e1862d1c42195c6fbe1b47)) -* support flag overrides for 'restic backup' in plan configuration ([56f5e40](https://github.com/garethgeorge/backrest/commit/56f5e405037a6309a3d1299356b363cd84281aef)) -* use disambiguated retention policy format ([5a5a229](https://github.com/garethgeorge/backrest/commit/5a5a229f456bf3d4d34cb4751c2a2ff3b6907511)) - +- add 'compute stats' button to refresh stats on repo view ([1f42b6a](https://github.com/garethgeorge/backrest/commit/1f42b6ab4e0313bbb12e6bc22b561d7544504644)) +- add option to disable scheduled execution of a plan ([aea74c5](https://github.com/garethgeorge/backrest/commit/aea74c51c0fb3908ece57f813c9ae6190e1fd46b)) +- add release artifacts for arm32 ([a737371](https://github.com/garethgeorge/backrest/commit/a737371ed559f5b65e734b0d97c44dcb2749ce53)) +- automatically remove Apples quarantine flag ([#155](https://github.com/garethgeorge/backrest/issues/155)) ([3e76beb](https://github.com/garethgeorge/backrest/commit/3e76bebd054eb7bfc9f8da4681459b863ae50c55)) +- check for basic auth ([#110](https://github.com/garethgeorge/backrest/issues/110)) ([#129](https://github.com/garethgeorge/backrest/issues/129)) ([871c54f](https://github.com/garethgeorge/backrest/commit/871c54f35f8651632714ca7d3a3ab0e809549b51)) +- improved stats visualization with graphs and cleanup operation filtering ([5b362cc](https://github.com/garethgeorge/backrest/commit/5b362ccbb45e59954dad574b93848195d45b55ef)) +- pass through all env variables from parent process to restic ([24afd51](https://github.com/garethgeorge/backrest/commit/24afd514ad80f542e6e1862d1c42195c6fbe1b47)) +- support flag overrides for 'restic backup' in plan configuration ([56f5e40](https://github.com/garethgeorge/backrest/commit/56f5e405037a6309a3d1299356b363cd84281aef)) +- use disambiguated retention policy format ([5a5a229](https://github.com/garethgeorge/backrest/commit/5a5a229f456bf3d4d34cb4751c2a2ff3b6907511)) ### Bug Fixes -* alpine linux Dockerfile and add openssh ([3cb9d27](https://github.com/garethgeorge/backrest/commit/3cb9d2717c1bda7bb7ed4e029ac938c851b9f664)) -* backrest shows hidden operations in list view ([c013f06](https://github.com/garethgeorge/backrest/commit/c013f069ff5eab6177d2bde373f23efe34b1aa8d)) -* BackupInfoCollector handling of filtered events ([f1e4619](https://github.com/garethgeorge/backrest/commit/f1e4619e9d98416289fb0ee51d56ff48e163b85d)) -* bugs in env var validation and form field handling ([7e909c4](https://github.com/garethgeorge/backrest/commit/7e909c4a96b053e8093f3b4f3d26c46b1c618947)) -* compression progress ratio should be float64 ([1759b5d](https://github.com/garethgeorge/backrest/commit/1759b5dc55ab17a1c76d47adee7f4e21f7ef09f5)) -* handle timezone correctly with tzdata package on alpine ([0e94f30](https://github.com/garethgeorge/backrest/commit/0e94f308cde40059f9c4104ed21f8c701a349c57)) -* install rclone with apk for alpine image ([#138](https://github.com/garethgeorge/backrest/issues/138)) ([79715a9](https://github.com/garethgeorge/backrest/commit/79715a97b34af60ca90894065d89c9ae603f0a59)) -* proper display of retention policy ([38ff5fe](https://github.com/garethgeorge/backrest/commit/38ff5fecee3ff3cdff5c7ccecb48e600eb714511)) -* properly parse repo flags ([348ec46](https://github.com/garethgeorge/backrest/commit/348ec4690cab74c3089f2be33d889df3002a5a97)) -* stat operation interval for long running repos ([f2477ab](https://github.com/garethgeorge/backrest/commit/f2477ab06cbe571723cd7290e06e8890747f81aa)) -* stats chart titles invisible on light color theme ([746fd9c](https://github.com/garethgeorge/backrest/commit/746fd9cf768f0c87a25f0015bd20289716b08604)) - +- alpine linux Dockerfile and add openssh ([3cb9d27](https://github.com/garethgeorge/backrest/commit/3cb9d2717c1bda7bb7ed4e029ac938c851b9f664)) +- backrest shows hidden operations in list view ([c013f06](https://github.com/garethgeorge/backrest/commit/c013f069ff5eab6177d2bde373f23efe34b1aa8d)) +- BackupInfoCollector handling of filtered events ([f1e4619](https://github.com/garethgeorge/backrest/commit/f1e4619e9d98416289fb0ee51d56ff48e163b85d)) +- bugs in env var validation and form field handling ([7e909c4](https://github.com/garethgeorge/backrest/commit/7e909c4a96b053e8093f3b4f3d26c46b1c618947)) +- compression progress ratio should be float64 ([1759b5d](https://github.com/garethgeorge/backrest/commit/1759b5dc55ab17a1c76d47adee7f4e21f7ef09f5)) +- handle timezone correctly with tzdata package on alpine ([0e94f30](https://github.com/garethgeorge/backrest/commit/0e94f308cde40059f9c4104ed21f8c701a349c57)) +- install rclone with apk for alpine image ([#138](https://github.com/garethgeorge/backrest/issues/138)) ([79715a9](https://github.com/garethgeorge/backrest/commit/79715a97b34af60ca90894065d89c9ae603f0a59)) +- proper display of retention policy ([38ff5fe](https://github.com/garethgeorge/backrest/commit/38ff5fecee3ff3cdff5c7ccecb48e600eb714511)) +- properly parse repo flags ([348ec46](https://github.com/garethgeorge/backrest/commit/348ec4690cab74c3089f2be33d889df3002a5a97)) +- stat operation interval for long running repos ([f2477ab](https://github.com/garethgeorge/backrest/commit/f2477ab06cbe571723cd7290e06e8890747f81aa)) +- stats chart titles invisible on light color theme ([746fd9c](https://github.com/garethgeorge/backrest/commit/746fd9cf768f0c87a25f0015bd20289716b08604)) ### Miscellaneous Chores -* bump version to 0.15.0 ([db4b76d](https://github.com/garethgeorge/backrest/commit/db4b76de8ed09c9eda6216e8dfe041518f5bbfc5)) +- bump version to 0.15.0 ([db4b76d](https://github.com/garethgeorge/backrest/commit/db4b76de8ed09c9eda6216e8dfe041518f5bbfc5)) ## [0.13.0](https://github.com/garethgeorge/backrest/compare/v0.12.2...v0.13.0) (2024-02-21) - ### Features -* add case insensitive excludes (iexcludes) ([#108](https://github.com/garethgeorge/backrest/issues/108)) ([bf6fb7e](https://github.com/garethgeorge/backrest/commit/bf6fb7e71402590961271e91ad6da63db27ff5ad)) -* add flags to configure backrest options e.g. --config-file, --data-dir, --restic-cmd, --bind-address ([41ddc8e](https://github.com/garethgeorge/backrest/commit/41ddc8e1a9d5501a92498c8cf3c72625bd181f8a)) -* add opt-in auto-unlock feature to remove locks on forget and prune ([#107](https://github.com/garethgeorge/backrest/issues/107)) ([c1ee33f](https://github.com/garethgeorge/backrest/commit/c1ee33f0cd65a23ec0090852ee0fc5fa50e72b64)) -* add rclone binary to docker image and arm64 support ([#105](https://github.com/garethgeorge/backrest/issues/105)) ([5a49f2f](https://github.com/garethgeorge/backrest/commit/5a49f2f063e887cba85bba0347ebce3efe15753e)) -* bundle rclone, busybox commands, and bash in default backrest docker image ([cec04f8](https://github.com/garethgeorge/backrest/commit/cec04f8f745d4bcfd49829c43367c61cb9778174)) -* display non-fatal errors in backup operations (e.g. unreadable files) in UI ([#100](https://github.com/garethgeorge/backrest/issues/100)) ([caac35a](https://github.com/garethgeorge/backrest/commit/caac35a5402d056b626b59d19084d6a699d4346d)) - +- add case insensitive excludes (iexcludes) ([#108](https://github.com/garethgeorge/backrest/issues/108)) ([bf6fb7e](https://github.com/garethgeorge/backrest/commit/bf6fb7e71402590961271e91ad6da63db27ff5ad)) +- add flags to configure backrest options e.g. --config-file, --data-dir, --restic-cmd, --bind-address ([41ddc8e](https://github.com/garethgeorge/backrest/commit/41ddc8e1a9d5501a92498c8cf3c72625bd181f8a)) +- add opt-in auto-unlock feature to remove locks on forget and prune ([#107](https://github.com/garethgeorge/backrest/issues/107)) ([c1ee33f](https://github.com/garethgeorge/backrest/commit/c1ee33f0cd65a23ec0090852ee0fc5fa50e72b64)) +- add rclone binary to docker image and arm64 support ([#105](https://github.com/garethgeorge/backrest/issues/105)) ([5a49f2f](https://github.com/garethgeorge/backrest/commit/5a49f2f063e887cba85bba0347ebce3efe15753e)) +- bundle rclone, busybox commands, and bash in default backrest docker image ([cec04f8](https://github.com/garethgeorge/backrest/commit/cec04f8f745d4bcfd49829c43367c61cb9778174)) +- display non-fatal errors in backup operations (e.g. unreadable files) in UI ([#100](https://github.com/garethgeorge/backrest/issues/100)) ([caac35a](https://github.com/garethgeorge/backrest/commit/caac35a5402d056b626b59d19084d6a699d4346d)) ### Bug Fixes -* improve error message when rclone config is missing ([663b430](https://github.com/garethgeorge/backrest/commit/663b430598e0890df74989af12ae81fae7922251)) -* improved sidebar status refresh interval during live operations ([3d192fd](https://github.com/garethgeorge/backrest/commit/3d192fd59d98c242ed583d00eeec37e68a4a2ff5)) -* live backup progress updates with partial-backup errors ([97a4948](https://github.com/garethgeorge/backrest/commit/97a494847ac5031866c31db0bb32219e6b2a0038)) -* migrate prune policy options to oneof ([ef41d34](https://github.com/garethgeorge/backrest/commit/ef41d34d5312b6a3bcc4af536f64275cd20da657)) -* restore operations should succeed for unassociated snapshots ([448107d](https://github.com/garethgeorge/backrest/commit/448107d22612f040fd45493246088277a4a72f63)) -* separate docker images for scratch and alpine linux base ([#106](https://github.com/garethgeorge/backrest/issues/106)) ([40e3e04](https://github.com/garethgeorge/backrest/commit/40e3e04a686f0a1749fa39e15821e6310e0ccf52)) +- improve error message when rclone config is missing ([663b430](https://github.com/garethgeorge/backrest/commit/663b430598e0890df74989af12ae81fae7922251)) +- improved sidebar status refresh interval during live operations ([3d192fd](https://github.com/garethgeorge/backrest/commit/3d192fd59d98c242ed583d00eeec37e68a4a2ff5)) +- live backup progress updates with partial-backup errors ([97a4948](https://github.com/garethgeorge/backrest/commit/97a494847ac5031866c31db0bb32219e6b2a0038)) +- migrate prune policy options to oneof ([ef41d34](https://github.com/garethgeorge/backrest/commit/ef41d34d5312b6a3bcc4af536f64275cd20da657)) +- restore operations should succeed for unassociated snapshots ([448107d](https://github.com/garethgeorge/backrest/commit/448107d22612f040fd45493246088277a4a72f63)) +- separate docker images for scratch and alpine linux base ([#106](https://github.com/garethgeorge/backrest/issues/106)) ([40e3e04](https://github.com/garethgeorge/backrest/commit/40e3e04a686f0a1749fa39e15821e6310e0ccf52)) ## [0.12.2](https://github.com/garethgeorge/backrest/compare/v0.12.1...v0.12.2) (2024-02-16) - ### Bug Fixes -* release-please automation ([63ddf15](https://github.com/garethgeorge/backrest/commit/63ddf15bf9799de30bda8548421e11e1bcd9ed05)) +- release-please automation ([63ddf15](https://github.com/garethgeorge/backrest/commit/63ddf15bf9799de30bda8548421e11e1bcd9ed05)) ## [0.12.1](https://github.com/garethgeorge/backrest/compare/v0.12.0...v0.12.1) (2024-02-16) - ### Bug Fixes -* delete event button in UI is hard to see on light theme ([8a05df8](https://github.com/garethgeorge/backrest/commit/8a05df87fcc44699c890f0cbe1065d79f49e1cc2)) -* use 'embed' to package WebUI sources instead of go.rice ([e3ba5cf](https://github.com/garethgeorge/backrest/commit/e3ba5cf12ebfedafaa2125687bd7522f29ccab51)) +- delete event button in UI is hard to see on light theme ([8a05df8](https://github.com/garethgeorge/backrest/commit/8a05df87fcc44699c890f0cbe1065d79f49e1cc2)) +- use 'embed' to package WebUI sources instead of go.rice ([e3ba5cf](https://github.com/garethgeorge/backrest/commit/e3ba5cf12ebfedafaa2125687bd7522f29ccab51)) ## [0.12.0](https://github.com/garethgeorge/backrest/compare/v0.11.1...v0.12.0) (2024-02-15) - ### Features -* add button to forget individual snapshots ([276b1d2](https://github.com/garethgeorge/backrest/commit/276b1d2c602ad0f787958452070771af3e69f073)) -* add slack webhook ([8fa90ab](https://github.com/garethgeorge/backrest/commit/8fa90ab9ca48f0888ed0a5d263cb697758063188)) -* Add support for multiple sets of expected env vars per repo scheme ([#90](https://github.com/garethgeorge/backrest/issues/90)) ([da0551c](https://github.com/garethgeorge/backrest/commit/da0551c19a98fe675d278e34f8e3cc58ac9edaf5)) -* clear operations from history ([dc7a3a5](https://github.com/garethgeorge/backrest/commit/dc7a3a59a2400f97dd6b8140c6e70a34105496f9)) -* Windows WebUI uses correct path separator ([f5521e7](https://github.com/garethgeorge/backrest/commit/f5521e7b56e446fa2062a95560f315621b77d3e6)) - +- add button to forget individual snapshots ([276b1d2](https://github.com/garethgeorge/backrest/commit/276b1d2c602ad0f787958452070771af3e69f073)) +- add slack webhook ([8fa90ab](https://github.com/garethgeorge/backrest/commit/8fa90ab9ca48f0888ed0a5d263cb697758063188)) +- Add support for multiple sets of expected env vars per repo scheme ([#90](https://github.com/garethgeorge/backrest/issues/90)) ([da0551c](https://github.com/garethgeorge/backrest/commit/da0551c19a98fe675d278e34f8e3cc58ac9edaf5)) +- clear operations from history ([dc7a3a5](https://github.com/garethgeorge/backrest/commit/dc7a3a59a2400f97dd6b8140c6e70a34105496f9)) +- Windows WebUI uses correct path separator ([f5521e7](https://github.com/garethgeorge/backrest/commit/f5521e7b56e446fa2062a95560f315621b77d3e6)) ### Bug Fixes -* cleanup old versions of restic when upgrading ([79f529f](https://github.com/garethgeorge/backrest/commit/79f529f8edfb9bf893e74f7b1355bd7f2d7bdc3f)) -* hide delete operation button if operation is in progress or pending ([08c8762](https://github.com/garethgeorge/backrest/commit/08c876243febb99a68740c449055e850f37d740e)) -* retention policy configuration in add plan view ([dd24d90](https://github.com/garethgeorge/backrest/commit/dd24d9024f5ade62535956b1449dae75627ce493)) -* stats operations running at wrong interval ([05e5ae0](https://github.com/garethgeorge/backrest/commit/05e5ae0c455680bf9fbc9b4b2a9fbf96bcfdfc3b)) +- cleanup old versions of restic when upgrading ([79f529f](https://github.com/garethgeorge/backrest/commit/79f529f8edfb9bf893e74f7b1355bd7f2d7bdc3f)) +- hide delete operation button if operation is in progress or pending ([08c8762](https://github.com/garethgeorge/backrest/commit/08c876243febb99a68740c449055e850f37d740e)) +- retention policy configuration in add plan view ([dd24d90](https://github.com/garethgeorge/backrest/commit/dd24d9024f5ade62535956b1449dae75627ce493)) +- stats operations running at wrong interval ([05e5ae0](https://github.com/garethgeorge/backrest/commit/05e5ae0c455680bf9fbc9b4b2a9fbf96bcfdfc3b)) ## [0.11.1](https://github.com/garethgeorge/backrest/compare/v0.11.0...v0.11.1) (2024-02-08) - ### Bug Fixes -* backrest fails to create directory for jwt secrets ([0067edf](https://github.com/garethgeorge/backrest/commit/0067edf378b01147f0041c225994098cb9c452ab)) -* form bugs in UI e.g. awkward behavior when modifying hooks ([4fcf526](https://github.com/garethgeorge/backrest/commit/4fcf52602c114e2c639fc4302a9b8e8d51180a4d)) -* update restic version to 1.16.4 ([668a7cb](https://github.com/garethgeorge/backrest/commit/668a7cb5bb5c0955a0e3186b2dd9329cedddd96f)) -* wrong field names in hooks form ([3540904](https://github.com/garethgeorge/backrest/commit/354090497b73d40d8a9e705d1aa0c4662ffc4b0e)) -* wrong value passed to --max-unused when providing a custom prune policy ([34175f2](https://github.com/garethgeorge/backrest/commit/34175f273630f7d2324a4d6b5f9f2f7576dd6608)) +- backrest fails to create directory for jwt secrets ([0067edf](https://github.com/garethgeorge/backrest/commit/0067edf378b01147f0041c225994098cb9c452ab)) +- form bugs in UI e.g. awkward behavior when modifying hooks ([4fcf526](https://github.com/garethgeorge/backrest/commit/4fcf52602c114e2c639fc4302a9b8e8d51180a4d)) +- update restic version to 1.16.4 ([668a7cb](https://github.com/garethgeorge/backrest/commit/668a7cb5bb5c0955a0e3186b2dd9329cedddd96f)) +- wrong field names in hooks form ([3540904](https://github.com/garethgeorge/backrest/commit/354090497b73d40d8a9e705d1aa0c4662ffc4b0e)) +- wrong value passed to --max-unused when providing a custom prune policy ([34175f2](https://github.com/garethgeorge/backrest/commit/34175f273630f7d2324a4d6b5f9f2f7576dd6608)) ## [0.11.0](https://github.com/garethgeorge/backrest/compare/v0.10.1...v0.11.0) (2024-02-04) - ### Features -* add user configurable command hooks for backup lifecycle events ([#60](https://github.com/garethgeorge/backrest/issues/60)) ([9be413b](https://github.com/garethgeorge/backrest/commit/9be413bbcca796862f161a769991ab695a50b464)) -* authentication for WebUI ([#62](https://github.com/garethgeorge/backrest/issues/62)) ([4a1f326](https://github.com/garethgeorge/backrest/commit/4a1f3268a7de0533e0a979b9e97a7117b028358e)) -* implement discord hook type ([25924b6](https://github.com/garethgeorge/backrest/commit/25924b6197c870f9dfc1e04f5be39377251e7f2d)) -* implement gotify hook type ([e0ce655](https://github.com/garethgeorge/backrest/commit/e0ce6558c047f3aff068ee5d475fa1bdba380c4d)) -* support keep-all retention policy for append-only backups ([f163c02](https://github.com/garethgeorge/backrest/commit/f163c02d7d2c798b4057037a996de44e34de9f2b)) - +- add user configurable command hooks for backup lifecycle events ([#60](https://github.com/garethgeorge/backrest/issues/60)) ([9be413b](https://github.com/garethgeorge/backrest/commit/9be413bbcca796862f161a769991ab695a50b464)) +- authentication for WebUI ([#62](https://github.com/garethgeorge/backrest/issues/62)) ([4a1f326](https://github.com/garethgeorge/backrest/commit/4a1f3268a7de0533e0a979b9e97a7117b028358e)) +- implement discord hook type ([25924b6](https://github.com/garethgeorge/backrest/commit/25924b6197c870f9dfc1e04f5be39377251e7f2d)) +- implement gotify hook type ([e0ce655](https://github.com/garethgeorge/backrest/commit/e0ce6558c047f3aff068ee5d475fa1bdba380c4d)) +- support keep-all retention policy for append-only backups ([f163c02](https://github.com/garethgeorge/backrest/commit/f163c02d7d2c798b4057037a996de44e34de9f2b)) ### Bug Fixes -* add API test coverage and fix minor bugs ([f5bb74b](https://github.com/garethgeorge/backrest/commit/f5bb74bf246fcd5712dbbc85f4233169f7db4aa7)) -* add first time setup hint for user authentication ([4a565f2](https://github.com/garethgeorge/backrest/commit/4a565f2cdcd091e0eabc302ab91e53012f53eb26)) -* add test coverage for log rotation ([f1084ca](https://github.com/garethgeorge/backrest/commit/f1084cab4894751ba4a92f9be6b6b70d9084d0e6)) -* bugfixes for auth flow ([427792c](https://github.com/garethgeorge/backrest/commit/427792c7244fb712bbea0557d4a6c7ee07052534)) -* stats not displaying on long running repos ([f1ba1d9](https://github.com/garethgeorge/backrest/commit/f1ba1d91f37234f24ae5202d27114a33432366da)) -* store large log outputs in tar bundles of logs ([0cf01e0](https://github.com/garethgeorge/backrest/commit/0cf01e020640b0145bcd0d25a38cde1fce940aff)) -* windows install errors on decompressing zip archive ([5323b9f](https://github.com/garethgeorge/backrest/commit/5323b9ffc065bc3b28171575cdccc4358b69750b)) +- add API test coverage and fix minor bugs ([f5bb74b](https://github.com/garethgeorge/backrest/commit/f5bb74bf246fcd5712dbbc85f4233169f7db4aa7)) +- add first time setup hint for user authentication ([4a565f2](https://github.com/garethgeorge/backrest/commit/4a565f2cdcd091e0eabc302ab91e53012f53eb26)) +- add test coverage for log rotation ([f1084ca](https://github.com/garethgeorge/backrest/commit/f1084cab4894751ba4a92f9be6b6b70d9084d0e6)) +- bugfixes for auth flow ([427792c](https://github.com/garethgeorge/backrest/commit/427792c7244fb712bbea0557d4a6c7ee07052534)) +- stats not displaying on long running repos ([f1ba1d9](https://github.com/garethgeorge/backrest/commit/f1ba1d91f37234f24ae5202d27114a33432366da)) +- store large log outputs in tar bundles of logs ([0cf01e0](https://github.com/garethgeorge/backrest/commit/0cf01e020640b0145bcd0d25a38cde1fce940aff)) +- windows install errors on decompressing zip archive ([5323b9f](https://github.com/garethgeorge/backrest/commit/5323b9ffc065bc3b28171575cdccc4358b69750b)) ## [0.10.1](https://github.com/garethgeorge/backrest/compare/v0.10.0...v0.10.1) (2024-01-25) - ### Bug Fixes -* chmod config 0600 such that only the creating user can read ([ecff0e5](https://github.com/garethgeorge/backrest/commit/ecff0e57c1fa4d65f35774d227a27222af8e7921)) -* install scripts handle working dir correctly ([dcff2ad](https://github.com/garethgeorge/backrest/commit/dcff2adf60222030043d7a227d27e74f555ab376)) -* relax name regex for plans and repos ([ee6134a](https://github.com/garethgeorge/backrest/commit/ee6134af76c3e90f542f67b89b2571f060db5590)) -* sftp support using public key authentication ([bedb302](https://github.com/garethgeorge/backrest/commit/bedb302a025438a58309f26b046c9b6d49316414)) -* typos in validation error messages in addrepomodel ([3b79afb](https://github.com/garethgeorge/backrest/commit/3b79afb2b18530deaa10cca08a60941a64c6fd9b)) +- chmod config 0600 such that only the creating user can read ([ecff0e5](https://github.com/garethgeorge/backrest/commit/ecff0e57c1fa4d65f35774d227a27222af8e7921)) +- install scripts handle working dir correctly ([dcff2ad](https://github.com/garethgeorge/backrest/commit/dcff2adf60222030043d7a227d27e74f555ab376)) +- relax name regex for plans and repos ([ee6134a](https://github.com/garethgeorge/backrest/commit/ee6134af76c3e90f542f67b89b2571f060db5590)) +- sftp support using public key authentication ([bedb302](https://github.com/garethgeorge/backrest/commit/bedb302a025438a58309f26b046c9b6d49316414)) +- typos in validation error messages in addrepomodel ([3b79afb](https://github.com/garethgeorge/backrest/commit/3b79afb2b18530deaa10cca08a60941a64c6fd9b)) ## [0.10.0](https://github.com/garethgeorge/backrest/compare/v0.9.3...v0.10.0) (2024-01-15) - ### Features -* make prune policy configurable in the addrepoview in the UI ([3fd08eb](https://github.com/garethgeorge/backrest/commit/3fd08eb8e4b455db656a0680318851824fdad2db)) -* update restic dependency to v0.16.3 ([ac8db31](https://github.com/garethgeorge/backrest/commit/ac8db31713d4db3c2240b7f7c006e518e9e0726c)) -* verify gpg signature when downloading and installing restic binary ([04106d1](https://github.com/garethgeorge/backrest/commit/04106d15d5ad73db6e670e84340ac1f9be200a23)) +- make prune policy configurable in the addrepoview in the UI ([3fd08eb](https://github.com/garethgeorge/backrest/commit/3fd08eb8e4b455db656a0680318851824fdad2db)) +- update restic dependency to v0.16.3 ([ac8db31](https://github.com/garethgeorge/backrest/commit/ac8db31713d4db3c2240b7f7c006e518e9e0726c)) +- verify gpg signature when downloading and installing restic binary ([04106d1](https://github.com/garethgeorge/backrest/commit/04106d15d5ad73db6e670e84340ac1f9be200a23)) ## [0.9.3](https://github.com/garethgeorge/backrest/compare/v0.9.2...v0.9.3) (2024-01-05) - ### Bug Fixes -* correctly mark tasks as inprogress before execution ([b19438a](https://github.com/garethgeorge/backrest/commit/b19438afbd7b83dc964774347e64491143a3a5d2)) -* correctly select light/dark mode based on system colortheme ([b64199c](https://github.com/garethgeorge/backrest/commit/b64199c140db7d2a77b58219cee088d22ec81954)) +- correctly mark tasks as inprogress before execution ([b19438a](https://github.com/garethgeorge/backrest/commit/b19438afbd7b83dc964774347e64491143a3a5d2)) +- correctly select light/dark mode based on system colortheme ([b64199c](https://github.com/garethgeorge/backrest/commit/b64199c140db7d2a77b58219cee088d22ec81954)) ## [0.9.2](https://github.com/garethgeorge/backrest/compare/v0.9.1...v0.9.2) (2024-01-01) - ### Bug Fixes -* possible race condition in scheduled task heap ([30874c9](https://github.com/garethgeorge/backrest/commit/30874c9150f32a0fba5f1ea99bc77bcc978d8b03)) +- possible race condition in scheduled task heap ([30874c9](https://github.com/garethgeorge/backrest/commit/30874c9150f32a0fba5f1ea99bc77bcc978d8b03)) ## [0.9.1](https://github.com/garethgeorge/backrest/compare/v0.9.0...v0.9.1) (2024-01-01) - ### Bug Fixes -* failed forget operations are hidden in the UI ([9896446](https://github.com/garethgeorge/backrest/commit/9896446ccfbcb8475a21b5fb565ebb73cb6bac2c)) -* UI buttons spin while waiting for tasks to complete ([c767fa7](https://github.com/garethgeorge/backrest/commit/c767fa7476d76f1b4eb49443a19ee1cedb4eb70a)) +- failed forget operations are hidden in the UI ([9896446](https://github.com/garethgeorge/backrest/commit/9896446ccfbcb8475a21b5fb565ebb73cb6bac2c)) +- UI buttons spin while waiting for tasks to complete ([c767fa7](https://github.com/garethgeorge/backrest/commit/c767fa7476d76f1b4eb49443a19ee1cedb4eb70a)) ## [0.9.0](https://github.com/garethgeorge/backrest/compare/v0.8.1...v0.9.0) (2023-12-31) - ### Features -* add backrest logo ([5add0d8](https://github.com/garethgeorge/backrest/commit/5add0d8ffa829a71103520c94eacae17966f2a9f)) -* add mobile layout ([9c7f227](https://github.com/garethgeorge/backrest/commit/9c7f227ad0f5df34d66390c94b64e9f5181d24f0)) -* index snapshots created outside of backrest ([7711297](https://github.com/garethgeorge/backrest/commit/7711297a84170a733c5ccdb3e89617efc878cf69)) -* schedule index operations and stats refresh from repo view ([851bd12](https://github.com/garethgeorge/backrest/commit/851bd125b640e65a5b98b67d28d2f29e94411646)) - +- add backrest logo ([5add0d8](https://github.com/garethgeorge/backrest/commit/5add0d8ffa829a71103520c94eacae17966f2a9f)) +- add mobile layout ([9c7f227](https://github.com/garethgeorge/backrest/commit/9c7f227ad0f5df34d66390c94b64e9f5181d24f0)) +- index snapshots created outside of backrest ([7711297](https://github.com/garethgeorge/backrest/commit/7711297a84170a733c5ccdb3e89617efc878cf69)) +- schedule index operations and stats refresh from repo view ([851bd12](https://github.com/garethgeorge/backrest/commit/851bd125b640e65a5b98b67d28d2f29e94411646)) ### Bug Fixes -* operations associated with incorrect ID when tasks are rescheduled ([25871c9](https://github.com/garethgeorge/backrest/commit/25871c99920d8717e91bf1a921109b9df82a59a1)) -* reduce stats refresh frequency ([adbe005](https://github.com/garethgeorge/backrest/commit/adbe0056d82a5d9f890ce79b1120f5084bdc7124)) -* stat never runs ([3f3252d](https://github.com/garethgeorge/backrest/commit/3f3252d47951270fbf5f21b0831effb121d3ba3f)) -* stats task priority ([6bfe769](https://github.com/garethgeorge/backrest/commit/6bfe769fe037a5f2d35947574a5ed7e26ba981a8)) -* tasks run late when laptops resume from sleep ([cb78298](https://github.com/garethgeorge/backrest/commit/cb78298cffb492560717d5f8bdcd5941f7976f2e)) -* UI and code quality improvements ([c5e435d](https://github.com/garethgeorge/backrest/commit/c5e435d640bc8e79ceacf7f64d4cf75644859204)) +- operations associated with incorrect ID when tasks are rescheduled ([25871c9](https://github.com/garethgeorge/backrest/commit/25871c99920d8717e91bf1a921109b9df82a59a1)) +- reduce stats refresh frequency ([adbe005](https://github.com/garethgeorge/backrest/commit/adbe0056d82a5d9f890ce79b1120f5084bdc7124)) +- stat never runs ([3f3252d](https://github.com/garethgeorge/backrest/commit/3f3252d47951270fbf5f21b0831effb121d3ba3f)) +- stats task priority ([6bfe769](https://github.com/garethgeorge/backrest/commit/6bfe769fe037a5f2d35947574a5ed7e26ba981a8)) +- tasks run late when laptops resume from sleep ([cb78298](https://github.com/garethgeorge/backrest/commit/cb78298cffb492560717d5f8bdcd5941f7976f2e)) +- UI and code quality improvements ([c5e435d](https://github.com/garethgeorge/backrest/commit/c5e435d640bc8e79ceacf7f64d4cf75644859204)) ## [0.8.0](https://github.com/garethgeorge/backrest/compare/v0.7.0...v0.8.0) (2023-12-25) - ### Features -* add repo stats to restic package ([26d4724](https://github.com/garethgeorge/backrest/commit/26d47243c1e31f17c4d8adc6227325551854ce1f)) -* add stats to repo view e.g. total size in storage ([adb0e3f](https://github.com/garethgeorge/backrest/commit/adb0e3f23050a86cd1c507d374e9d45f5eb5ee27)) -* display last operation status for each plan and repo in UI ([cc11197](https://github.com/garethgeorge/backrest/commit/cc111970ca2e61cf39804378808aa5b5f77f9581)) - +- add repo stats to restic package ([26d4724](https://github.com/garethgeorge/backrest/commit/26d47243c1e31f17c4d8adc6227325551854ce1f)) +- add stats to repo view e.g. total size in storage ([adb0e3f](https://github.com/garethgeorge/backrest/commit/adb0e3f23050a86cd1c507d374e9d45f5eb5ee27)) +- display last operation status for each plan and repo in UI ([cc11197](https://github.com/garethgeorge/backrest/commit/cc111970ca2e61cf39804378808aa5b5f77f9581)) ### Bug Fixes -* crashing bug on partial backup ([#39](https://github.com/garethgeorge/backrest/issues/39)) ([fba6c8d](https://github.com/garethgeorge/backrest/commit/fba6c8da869d66b7b44f87a0dc1e3779924c31b7)) -* install scripts and improved asset compression ([b8c2e81](https://github.com/garethgeorge/backrest/commit/b8c2e813586f2b48c78d70e09a29c5052621caf1)) +- crashing bug on partial backup ([#39](https://github.com/garethgeorge/backrest/issues/39)) ([fba6c8d](https://github.com/garethgeorge/backrest/commit/fba6c8da869d66b7b44f87a0dc1e3779924c31b7)) +- install scripts and improved asset compression ([b8c2e81](https://github.com/garethgeorge/backrest/commit/b8c2e813586f2b48c78d70e09a29c5052621caf1)) ## [0.7.0](https://github.com/garethgeorge/backrest/compare/v0.6.0...v0.7.0) (2023-12-22) - ### Features -* add activity bar to UI heading ([f5c3e76](https://github.com/garethgeorge/backrest/commit/f5c3e762ed4ed3c908e843d74985fb6c7b253db7)) -* add clear error history button ([48d80b9](https://github.com/garethgeorge/backrest/commit/48d80b9473db6619518924d0849b0eda78e62afa)) -* add repo view ([9522ac1](https://github.com/garethgeorge/backrest/commit/9522ac18deedc15311d3d464ee36c20e7f72e39f)) -* autoinstall required restic version ([b385c01](https://github.com/garethgeorge/backrest/commit/b385c011210087e6d6992a4e4b279fec4b22ab89)) -* basic forget support in backend and UI ([d22d9d1](https://github.com/garethgeorge/backrest/commit/d22d9d1a05831fae94ce397c0c73c6292d378cf5)) -* begin UI integration with backend ([cccdd29](https://github.com/garethgeorge/backrest/commit/cccdd297c15cd47268b2a1903e9624bdbca3dc68)) -* display queued operations ([0c818bb](https://github.com/garethgeorge/backrest/commit/0c818bb9452a944d8b1127e553142e1e60ed90af)) -* forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) -* forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) -* implement add plan UI ([9288589](https://github.com/garethgeorge/backrest/commit/92885898cf551a2dcb4bb315f130138cd7a8cc67)) -* implement backup scheduling in orchestrator ([eadb1a8](https://github.com/garethgeorge/backrest/commit/eadb1a82019f0cfc82edf8559adbad7730a4e86a)) -* implement basic plan view ([4c6f042](https://github.com/garethgeorge/backrest/commit/4c6f042250946a036e46225e669ee39e2433b198)) -* implement delete button for plan and repo UIs ([ffb0d85](https://github.com/garethgeorge/backrest/commit/ffb0d859f19f4af66a7521768dab083995f9672a)) -* implement forget and prune support in restic pkg ([ffb4573](https://github.com/garethgeorge/backrest/commit/ffb4573737a73cc32f325bc0b9c3feed764b7879)) -* implement forget operation ([ebccf3b](https://github.com/garethgeorge/backrest/commit/ebccf3bc3b78083aee635de7c6ae23b52ee88284)) -* implement garbage collection of old operations ([46456a8](https://github.com/garethgeorge/backrest/commit/46456a88870934506ede4b67c3dfaa2f2afcee14)) -* implement prune support ([#25](https://github.com/garethgeorge/backrest/issues/25)) ([a311b0a](https://github.com/garethgeorge/backrest/commit/a311b0a3fb5315f17d66361a3e72fa10b8a744a1)) -* implement repo unlocking and operation list implementation ([6665ad9](https://github.com/garethgeorge/backrest/commit/6665ad98d7f54bea30ea532932a8a3409717c913)) -* implement repo, edit, and supporting RPCs ([d282c32](https://github.com/garethgeorge/backrest/commit/d282c32c8bd3d8f5747e934d4af6a84faca1ec86)) -* implement restore operation through snapshot browser UI ([#27](https://github.com/garethgeorge/backrest/issues/27)) ([d758509](https://github.com/garethgeorge/backrest/commit/d758509797e21e3ec4bc67eff4d974604e4a5476)) -* implement snapshot browsing ([8ffffa0](https://github.com/garethgeorge/backrest/commit/8ffffa05e41ca31e2d38fde5427dae34ac4a1abb)) -* implement snapshot indexing ([a90b30e](https://github.com/garethgeorge/backrest/commit/a90b30e19f7107874bbfe244451b07f72c437213)) -* improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/backrest/issues/22)) ([51b4921](https://github.com/garethgeorge/backrest/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19)) -* initial oplog implementation ([dd9142c](https://github.com/garethgeorge/backrest/commit/dd9142c0e97e1175ff12f2861220af0e0d68b7d9)) -* initial optree implementation ([ba390a2](https://github.com/garethgeorge/backrest/commit/ba390a2ca1b5e9adaab36a7db0d988f54f5a6cdd)) -* initial Windows OS support ([f048cbf](https://github.com/garethgeorge/backrest/commit/f048cbf10dc60da51cd7f5aee4614a8750fd85b2)) -* match system color theme (darkmode support) ([a8762dc](https://github.com/garethgeorge/backrest/commit/a8762dca329927b93db40b01cc011c00e12891f0)) -* operations IDs are ordered by operation timestamp ([a1ed6f9](https://github.com/garethgeorge/backrest/commit/a1ed6f90ba1d608e00c53221db45b67251085aa7)) -* present list of operations on plan view ([6491dbe](https://github.com/garethgeorge/backrest/commit/6491dbed146967c0e12eee4392d1d12843dc7c5e)) -* repo can be created through UI ([9ccade5](https://github.com/garethgeorge/backrest/commit/9ccade5ccd97f4e485d52ad5c675be6b0a4a1049)) -* scaffolding basic UI structure ([1273f81](https://github.com/garethgeorge/backrest/commit/1273f8105a2549b0ccd0c7a588eb60646b66366e)) -* show snapshots in sidenav ([1a9a5b6](https://github.com/garethgeorge/backrest/commit/1a9a5b60d24dd75752e5a3f84dd87af3e38422bb)) -* snapshot items are viewable in the UI and minor element ordering fixes ([a333001](https://github.com/garethgeorge/backrest/commit/a33300175c645f31b95b3038de02821a1f3d5559)) -* support ImportSnapshotOperation in oplog ([89f95b3](https://github.com/garethgeorge/backrest/commit/89f95b351fe250534cd39ac27ff34b2b148256e1)) -* support task cancellation ([fc9c06d](https://github.com/garethgeorge/backrest/commit/fc9c06df00409b73dda23f4be031746f492b1a24)) -* update getting started guide ([2c421d6](https://github.com/garethgeorge/backrest/commit/2c421d661501fa4a3120aa3f39937cd58b29c2dc)) - +- add activity bar to UI heading ([f5c3e76](https://github.com/garethgeorge/backrest/commit/f5c3e762ed4ed3c908e843d74985fb6c7b253db7)) +- add clear error history button ([48d80b9](https://github.com/garethgeorge/backrest/commit/48d80b9473db6619518924d0849b0eda78e62afa)) +- add repo view ([9522ac1](https://github.com/garethgeorge/backrest/commit/9522ac18deedc15311d3d464ee36c20e7f72e39f)) +- autoinstall required restic version ([b385c01](https://github.com/garethgeorge/backrest/commit/b385c011210087e6d6992a4e4b279fec4b22ab89)) +- basic forget support in backend and UI ([d22d9d1](https://github.com/garethgeorge/backrest/commit/d22d9d1a05831fae94ce397c0c73c6292d378cf5)) +- begin UI integration with backend ([cccdd29](https://github.com/garethgeorge/backrest/commit/cccdd297c15cd47268b2a1903e9624bdbca3dc68)) +- display queued operations ([0c818bb](https://github.com/garethgeorge/backrest/commit/0c818bb9452a944d8b1127e553142e1e60ed90af)) +- forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) +- forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) +- implement add plan UI ([9288589](https://github.com/garethgeorge/backrest/commit/92885898cf551a2dcb4bb315f130138cd7a8cc67)) +- implement backup scheduling in orchestrator ([eadb1a8](https://github.com/garethgeorge/backrest/commit/eadb1a82019f0cfc82edf8559adbad7730a4e86a)) +- implement basic plan view ([4c6f042](https://github.com/garethgeorge/backrest/commit/4c6f042250946a036e46225e669ee39e2433b198)) +- implement delete button for plan and repo UIs ([ffb0d85](https://github.com/garethgeorge/backrest/commit/ffb0d859f19f4af66a7521768dab083995f9672a)) +- implement forget and prune support in restic pkg ([ffb4573](https://github.com/garethgeorge/backrest/commit/ffb4573737a73cc32f325bc0b9c3feed764b7879)) +- implement forget operation ([ebccf3b](https://github.com/garethgeorge/backrest/commit/ebccf3bc3b78083aee635de7c6ae23b52ee88284)) +- implement garbage collection of old operations ([46456a8](https://github.com/garethgeorge/backrest/commit/46456a88870934506ede4b67c3dfaa2f2afcee14)) +- implement prune support ([#25](https://github.com/garethgeorge/backrest/issues/25)) ([a311b0a](https://github.com/garethgeorge/backrest/commit/a311b0a3fb5315f17d66361a3e72fa10b8a744a1)) +- implement repo unlocking and operation list implementation ([6665ad9](https://github.com/garethgeorge/backrest/commit/6665ad98d7f54bea30ea532932a8a3409717c913)) +- implement repo, edit, and supporting RPCs ([d282c32](https://github.com/garethgeorge/backrest/commit/d282c32c8bd3d8f5747e934d4af6a84faca1ec86)) +- implement restore operation through snapshot browser UI ([#27](https://github.com/garethgeorge/backrest/issues/27)) ([d758509](https://github.com/garethgeorge/backrest/commit/d758509797e21e3ec4bc67eff4d974604e4a5476)) +- implement snapshot browsing ([8ffffa0](https://github.com/garethgeorge/backrest/commit/8ffffa05e41ca31e2d38fde5427dae34ac4a1abb)) +- implement snapshot indexing ([a90b30e](https://github.com/garethgeorge/backrest/commit/a90b30e19f7107874bbfe244451b07f72c437213)) +- improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/backrest/issues/22)) ([51b4921](https://github.com/garethgeorge/backrest/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19)) +- initial oplog implementation ([dd9142c](https://github.com/garethgeorge/backrest/commit/dd9142c0e97e1175ff12f2861220af0e0d68b7d9)) +- initial optree implementation ([ba390a2](https://github.com/garethgeorge/backrest/commit/ba390a2ca1b5e9adaab36a7db0d988f54f5a6cdd)) +- initial Windows OS support ([f048cbf](https://github.com/garethgeorge/backrest/commit/f048cbf10dc60da51cd7f5aee4614a8750fd85b2)) +- match system color theme (darkmode support) ([a8762dc](https://github.com/garethgeorge/backrest/commit/a8762dca329927b93db40b01cc011c00e12891f0)) +- operations IDs are ordered by operation timestamp ([a1ed6f9](https://github.com/garethgeorge/backrest/commit/a1ed6f90ba1d608e00c53221db45b67251085aa7)) +- present list of operations on plan view ([6491dbe](https://github.com/garethgeorge/backrest/commit/6491dbed146967c0e12eee4392d1d12843dc7c5e)) +- repo can be created through UI ([9ccade5](https://github.com/garethgeorge/backrest/commit/9ccade5ccd97f4e485d52ad5c675be6b0a4a1049)) +- scaffolding basic UI structure ([1273f81](https://github.com/garethgeorge/backrest/commit/1273f8105a2549b0ccd0c7a588eb60646b66366e)) +- show snapshots in sidenav ([1a9a5b6](https://github.com/garethgeorge/backrest/commit/1a9a5b60d24dd75752e5a3f84dd87af3e38422bb)) +- snapshot items are viewable in the UI and minor element ordering fixes ([a333001](https://github.com/garethgeorge/backrest/commit/a33300175c645f31b95b3038de02821a1f3d5559)) +- support ImportSnapshotOperation in oplog ([89f95b3](https://github.com/garethgeorge/backrest/commit/89f95b351fe250534cd39ac27ff34b2b148256e1)) +- support task cancellation ([fc9c06d](https://github.com/garethgeorge/backrest/commit/fc9c06df00409b73dda23f4be031746f492b1a24)) +- update getting started guide ([2c421d6](https://github.com/garethgeorge/backrest/commit/2c421d661501fa4a3120aa3f39937cd58b29c2dc)) ### Bug Fixes -* backup ordering in tree view ([b9c8b3e](https://github.com/garethgeorge/backrest/commit/b9c8b3e378e88a0feff4d477d9d97eb5db075382)) -* build and test fixes ([4957496](https://github.com/garethgeorge/backrest/commit/49574967871494dcb5095e5699610097466f57f9)) -* connectivity issues with embedded server ([482cc8e](https://github.com/garethgeorge/backrest/commit/482cc8ebbc93b919991f6566b212247c5874f70f)) -* deadlock in snapshots ([93b2120](https://github.com/garethgeorge/backrest/commit/93b2120f74ea348e5084ab430573368bf4066eec)) -* forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) -* hide no-op prune operations ([20dd78c](https://github.com/garethgeorge/backrest/commit/20dd78cac4bdd6385cb7a0ea9ff0be75fde9135b)) -* improve error message formatting ([ae33b01](https://github.com/garethgeorge/backrest/commit/ae33b01de408af3b1d711a369298a2782a24ad1e)) -* improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) -* improve output detail collection for command failures ([c492f9b](https://github.com/garethgeorge/backrest/commit/c492f9ba63169942509349797ebe951879b53635)) -* improve UI performance ([8488d46](https://github.com/garethgeorge/backrest/commit/8488d461bd7ffec2e8171d67f83093c32c79073f)) -* improve Windows path handling ([426aad4](https://github.com/garethgeorge/backrest/commit/426aad4890d2de5d70cd2e0232c0d11c42606c92)) -* incorrrect handling of oplog events in UI ([95ca96a](https://github.com/garethgeorge/backrest/commit/95ca96a31f2e1ead2702164ec8675e4b4f54cf1d)) -* operation ordering in tree view ([2b4e1a2](https://github.com/garethgeorge/backrest/commit/2b4e1a2fdbf11b010ddbcd0b6fd2640d01e4dbc8)) -* operations marked as 'warn' rather than 'error' for partial backups ([fe92b62](https://github.com/garethgeorge/backrest/commit/fe92b625780481193e0ab63fbbdddb889bbda2a8)) -* ordering of operations when viewed from backup tree ([063f086](https://github.com/garethgeorge/backrest/commit/063f086a6e31df250dd9be42cdb5fa549307106f)) -* race condition in snapshot browser ([f239b91](https://github.com/garethgeorge/backrest/commit/f239b9170415e063ec8d60a5b5e14ae3610b9bad)) -* relax output parsing to skip over warnings ([8f85b74](https://github.com/garethgeorge/backrest/commit/8f85b747f57844bbc898668723eec50a1666aa39)) -* repo orchestrator tests ([d077fc8](https://github.com/garethgeorge/backrest/commit/d077fc83c97b7fbdbeda9702828c8780182b2616)) -* restic fails to detect summary event for very short backups ([46b2a85](https://github.com/garethgeorge/backrest/commit/46b2a8567706ddb21cfcf3e18b57e16d50809b56)) -* restic should initialize repo on backup operation ([e57abbd](https://github.com/garethgeorge/backrest/commit/e57abbdcb1864c362e6ae3c22850c0380671cb34)) -* restora should not init repos added manually e.g. without the UI ([68b50e1](https://github.com/garethgeorge/backrest/commit/68b50e1eb5a2ebd861c869f71f49d196cb5214f8)) -* snapshots out of order in UI ([b9bcc7e](https://github.com/garethgeorge/backrest/commit/b9bcc7e7c758abafa4878b6ef895adf2d2d0bc42)) -* standardize on fully qualified snapshot_id and decouple protobufs from restic package ([e6031bf](https://github.com/garethgeorge/backrest/commit/e6031bfa543a7300e622c1b0f56efc6320e7611e)) -* support more versions of restic ([0cdfd11](https://github.com/garethgeorge/backrest/commit/0cdfd115e29a0b08d5814e71c0f4a8f2baf52e90)) -* task cancellation ([d49b729](https://github.com/garethgeorge/backrest/commit/d49b72996ea7fd0543d55db3fc8e1127fe5a2476)) -* task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) -* time formatting in operation list ([53c7f12](https://github.com/garethgeorge/backrest/commit/53c7f1248f5284080fff872ac79b3996474412b3)) -* UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/backrest/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9)) -* unexpected config location on MacOS ([8d40576](https://github.com/garethgeorge/backrest/commit/8d40576c6526d6f180c96fbeb81d7f59f56b51b8)) -* use timezone offset when grouping operations in OperationTree ([06240bd](https://github.com/garethgeorge/backrest/commit/06240bd7adabd76424025030cfde2fb5e54c219f)) +- backup ordering in tree view ([b9c8b3e](https://github.com/garethgeorge/backrest/commit/b9c8b3e378e88a0feff4d477d9d97eb5db075382)) +- build and test fixes ([4957496](https://github.com/garethgeorge/backrest/commit/49574967871494dcb5095e5699610097466f57f9)) +- connectivity issues with embedded server ([482cc8e](https://github.com/garethgeorge/backrest/commit/482cc8ebbc93b919991f6566b212247c5874f70f)) +- deadlock in snapshots ([93b2120](https://github.com/garethgeorge/backrest/commit/93b2120f74ea348e5084ab430573368bf4066eec)) +- forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) +- hide no-op prune operations ([20dd78c](https://github.com/garethgeorge/backrest/commit/20dd78cac4bdd6385cb7a0ea9ff0be75fde9135b)) +- improve error message formatting ([ae33b01](https://github.com/garethgeorge/backrest/commit/ae33b01de408af3b1d711a369298a2782a24ad1e)) +- improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) +- improve output detail collection for command failures ([c492f9b](https://github.com/garethgeorge/backrest/commit/c492f9ba63169942509349797ebe951879b53635)) +- improve UI performance ([8488d46](https://github.com/garethgeorge/backrest/commit/8488d461bd7ffec2e8171d67f83093c32c79073f)) +- improve Windows path handling ([426aad4](https://github.com/garethgeorge/backrest/commit/426aad4890d2de5d70cd2e0232c0d11c42606c92)) +- incorrrect handling of oplog events in UI ([95ca96a](https://github.com/garethgeorge/backrest/commit/95ca96a31f2e1ead2702164ec8675e4b4f54cf1d)) +- operation ordering in tree view ([2b4e1a2](https://github.com/garethgeorge/backrest/commit/2b4e1a2fdbf11b010ddbcd0b6fd2640d01e4dbc8)) +- operations marked as 'warn' rather than 'error' for partial backups ([fe92b62](https://github.com/garethgeorge/backrest/commit/fe92b625780481193e0ab63fbbdddb889bbda2a8)) +- ordering of operations when viewed from backup tree ([063f086](https://github.com/garethgeorge/backrest/commit/063f086a6e31df250dd9be42cdb5fa549307106f)) +- race condition in snapshot browser ([f239b91](https://github.com/garethgeorge/backrest/commit/f239b9170415e063ec8d60a5b5e14ae3610b9bad)) +- relax output parsing to skip over warnings ([8f85b74](https://github.com/garethgeorge/backrest/commit/8f85b747f57844bbc898668723eec50a1666aa39)) +- repo orchestrator tests ([d077fc8](https://github.com/garethgeorge/backrest/commit/d077fc83c97b7fbdbeda9702828c8780182b2616)) +- restic fails to detect summary event for very short backups ([46b2a85](https://github.com/garethgeorge/backrest/commit/46b2a8567706ddb21cfcf3e18b57e16d50809b56)) +- restic should initialize repo on backup operation ([e57abbd](https://github.com/garethgeorge/backrest/commit/e57abbdcb1864c362e6ae3c22850c0380671cb34)) +- restora should not init repos added manually e.g. without the UI ([68b50e1](https://github.com/garethgeorge/backrest/commit/68b50e1eb5a2ebd861c869f71f49d196cb5214f8)) +- snapshots out of order in UI ([b9bcc7e](https://github.com/garethgeorge/backrest/commit/b9bcc7e7c758abafa4878b6ef895adf2d2d0bc42)) +- standardize on fully qualified snapshot_id and decouple protobufs from restic package ([e6031bf](https://github.com/garethgeorge/backrest/commit/e6031bfa543a7300e622c1b0f56efc6320e7611e)) +- support more versions of restic ([0cdfd11](https://github.com/garethgeorge/backrest/commit/0cdfd115e29a0b08d5814e71c0f4a8f2baf52e90)) +- task cancellation ([d49b729](https://github.com/garethgeorge/backrest/commit/d49b72996ea7fd0543d55db3fc8e1127fe5a2476)) +- task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) +- time formatting in operation list ([53c7f12](https://github.com/garethgeorge/backrest/commit/53c7f1248f5284080fff872ac79b3996474412b3)) +- UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/backrest/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9)) +- unexpected config location on MacOS ([8d40576](https://github.com/garethgeorge/backrest/commit/8d40576c6526d6f180c96fbeb81d7f59f56b51b8)) +- use timezone offset when grouping operations in OperationTree ([06240bd](https://github.com/garethgeorge/backrest/commit/06240bd7adabd76424025030cfde2fb5e54c219f)) ## [0.6.0](https://github.com/garethgeorge/backrest/compare/v0.5.0...v0.6.0) (2023-12-22) - ### Features -* add activity bar to UI heading ([f5c3e76](https://github.com/garethgeorge/backrest/commit/f5c3e762ed4ed3c908e843d74985fb6c7b253db7)) -* add clear error history button ([48d80b9](https://github.com/garethgeorge/backrest/commit/48d80b9473db6619518924d0849b0eda78e62afa)) -* add repo view ([9522ac1](https://github.com/garethgeorge/backrest/commit/9522ac18deedc15311d3d464ee36c20e7f72e39f)) -* implement garbage collection of old operations ([46456a8](https://github.com/garethgeorge/backrest/commit/46456a88870934506ede4b67c3dfaa2f2afcee14)) -* support task cancellation ([fc9c06d](https://github.com/garethgeorge/backrest/commit/fc9c06df00409b73dda23f4be031746f492b1a24)) - +- add activity bar to UI heading ([f5c3e76](https://github.com/garethgeorge/backrest/commit/f5c3e762ed4ed3c908e843d74985fb6c7b253db7)) +- add clear error history button ([48d80b9](https://github.com/garethgeorge/backrest/commit/48d80b9473db6619518924d0849b0eda78e62afa)) +- add repo view ([9522ac1](https://github.com/garethgeorge/backrest/commit/9522ac18deedc15311d3d464ee36c20e7f72e39f)) +- implement garbage collection of old operations ([46456a8](https://github.com/garethgeorge/backrest/commit/46456a88870934506ede4b67c3dfaa2f2afcee14)) +- support task cancellation ([fc9c06d](https://github.com/garethgeorge/backrest/commit/fc9c06df00409b73dda23f4be031746f492b1a24)) ### Bug Fixes -* backup ordering in tree view ([b9c8b3e](https://github.com/garethgeorge/backrest/commit/b9c8b3e378e88a0feff4d477d9d97eb5db075382)) -* hide no-op prune operations ([20dd78c](https://github.com/garethgeorge/backrest/commit/20dd78cac4bdd6385cb7a0ea9ff0be75fde9135b)) -* incorrrect handling of oplog events in UI ([95ca96a](https://github.com/garethgeorge/backrest/commit/95ca96a31f2e1ead2702164ec8675e4b4f54cf1d)) -* operation ordering in tree view ([2b4e1a2](https://github.com/garethgeorge/backrest/commit/2b4e1a2fdbf11b010ddbcd0b6fd2640d01e4dbc8)) -* operations marked as 'warn' rather than 'error' for partial backups ([fe92b62](https://github.com/garethgeorge/backrest/commit/fe92b625780481193e0ab63fbbdddb889bbda2a8)) -* race condition in snapshot browser ([f239b91](https://github.com/garethgeorge/backrest/commit/f239b9170415e063ec8d60a5b5e14ae3610b9bad)) -* restic should initialize repo on backup operation ([e57abbd](https://github.com/garethgeorge/backrest/commit/e57abbdcb1864c362e6ae3c22850c0380671cb34)) -* backrest should not init repos added manually e.g. without the UI ([68b50e1](https://github.com/garethgeorge/backrest/commit/68b50e1eb5a2ebd861c869f71f49d196cb5214f8)) -* task cancellation ([d49b729](https://github.com/garethgeorge/backrest/commit/d49b72996ea7fd0543d55db3fc8e1127fe5a2476)) -* use timezone offset when grouping operations in OperationTree ([06240bd](https://github.com/garethgeorge/backrest/commit/06240bd7adabd76424025030cfde2fb5e54c219f)) +- backup ordering in tree view ([b9c8b3e](https://github.com/garethgeorge/backrest/commit/b9c8b3e378e88a0feff4d477d9d97eb5db075382)) +- hide no-op prune operations ([20dd78c](https://github.com/garethgeorge/backrest/commit/20dd78cac4bdd6385cb7a0ea9ff0be75fde9135b)) +- incorrrect handling of oplog events in UI ([95ca96a](https://github.com/garethgeorge/backrest/commit/95ca96a31f2e1ead2702164ec8675e4b4f54cf1d)) +- operation ordering in tree view ([2b4e1a2](https://github.com/garethgeorge/backrest/commit/2b4e1a2fdbf11b010ddbcd0b6fd2640d01e4dbc8)) +- operations marked as 'warn' rather than 'error' for partial backups ([fe92b62](https://github.com/garethgeorge/backrest/commit/fe92b625780481193e0ab63fbbdddb889bbda2a8)) +- race condition in snapshot browser ([f239b91](https://github.com/garethgeorge/backrest/commit/f239b9170415e063ec8d60a5b5e14ae3610b9bad)) +- restic should initialize repo on backup operation ([e57abbd](https://github.com/garethgeorge/backrest/commit/e57abbdcb1864c362e6ae3c22850c0380671cb34)) +- backrest should not init repos added manually e.g. without the UI ([68b50e1](https://github.com/garethgeorge/backrest/commit/68b50e1eb5a2ebd861c869f71f49d196cb5214f8)) +- task cancellation ([d49b729](https://github.com/garethgeorge/backrest/commit/d49b72996ea7fd0543d55db3fc8e1127fe5a2476)) +- use timezone offset when grouping operations in OperationTree ([06240bd](https://github.com/garethgeorge/backrest/commit/06240bd7adabd76424025030cfde2fb5e54c219f)) ## [0.5.0](https://github.com/garethgeorge/backrest/compare/v0.4.0...v0.5.0) (2023-12-10) - ### Features -* implement repo unlocking and operation list implementation ([6665ad9](https://github.com/garethgeorge/backrest/commit/6665ad98d7f54bea30ea532932a8a3409717c913)) -* initial Windows OS support ([f048cbf](https://github.com/garethgeorge/backrest/commit/f048cbf10dc60da51cd7f5aee4614a8750fd85b2)) -* match system color theme (darkmode support) ([a8762dc](https://github.com/garethgeorge/backrest/commit/a8762dca329927b93db40b01cc011c00e12891f0)) - +- implement repo unlocking and operation list implementation ([6665ad9](https://github.com/garethgeorge/backrest/commit/6665ad98d7f54bea30ea532932a8a3409717c913)) +- initial Windows OS support ([f048cbf](https://github.com/garethgeorge/backrest/commit/f048cbf10dc60da51cd7f5aee4614a8750fd85b2)) +- match system color theme (darkmode support) ([a8762dc](https://github.com/garethgeorge/backrest/commit/a8762dca329927b93db40b01cc011c00e12891f0)) ### Bug Fixes -* improve output detail collection for command failures ([c492f9b](https://github.com/garethgeorge/backrest/commit/c492f9ba63169942509349797ebe951879b53635)) -* improve Windows path handling ([426aad4](https://github.com/garethgeorge/backrest/commit/426aad4890d2de5d70cd2e0232c0d11c42606c92)) -* ordering of operations when viewed from backup tree ([063f086](https://github.com/garethgeorge/backrest/commit/063f086a6e31df250dd9be42cdb5fa549307106f)) -* relax output parsing to skip over warnings ([8f85b74](https://github.com/garethgeorge/backrest/commit/8f85b747f57844bbc898668723eec50a1666aa39)) -* snapshots out of order in UI ([b9bcc7e](https://github.com/garethgeorge/backrest/commit/b9bcc7e7c758abafa4878b6ef895adf2d2d0bc42)) -* unexpected config location on MacOS ([8d40576](https://github.com/garethgeorge/backrest/commit/8d40576c6526d6f180c96fbeb81d7f59f56b51b8)) +- improve output detail collection for command failures ([c492f9b](https://github.com/garethgeorge/backrest/commit/c492f9ba63169942509349797ebe951879b53635)) +- improve Windows path handling ([426aad4](https://github.com/garethgeorge/backrest/commit/426aad4890d2de5d70cd2e0232c0d11c42606c92)) +- ordering of operations when viewed from backup tree ([063f086](https://github.com/garethgeorge/backrest/commit/063f086a6e31df250dd9be42cdb5fa549307106f)) +- relax output parsing to skip over warnings ([8f85b74](https://github.com/garethgeorge/backrest/commit/8f85b747f57844bbc898668723eec50a1666aa39)) +- snapshots out of order in UI ([b9bcc7e](https://github.com/garethgeorge/backrest/commit/b9bcc7e7c758abafa4878b6ef895adf2d2d0bc42)) +- unexpected config location on MacOS ([8d40576](https://github.com/garethgeorge/backrest/commit/8d40576c6526d6f180c96fbeb81d7f59f56b51b8)) ## [0.4.0](https://github.com/garethgeorge/backrest/compare/v0.3.0...v0.4.0) (2023-12-04) - ### Features -* implement prune support ([#25](https://github.com/garethgeorge/backrest/issues/25)) ([a311b0a](https://github.com/garethgeorge/backrest/commit/a311b0a3fb5315f17d66361a3e72fa10b8a744a1)) -* implement restore operation through snapshot browser UI ([#27](https://github.com/garethgeorge/backrest/issues/27)) ([d758509](https://github.com/garethgeorge/backrest/commit/d758509797e21e3ec4bc67eff4d974604e4a5476)) +- implement prune support ([#25](https://github.com/garethgeorge/backrest/issues/25)) ([a311b0a](https://github.com/garethgeorge/backrest/commit/a311b0a3fb5315f17d66361a3e72fa10b8a744a1)) +- implement restore operation through snapshot browser UI ([#27](https://github.com/garethgeorge/backrest/issues/27)) ([d758509](https://github.com/garethgeorge/backrest/commit/d758509797e21e3ec4bc67eff4d974604e4a5476)) ## [0.3.0](https://github.com/garethgeorge/backrest/compare/v0.2.0...v0.3.0) (2023-12-03) - ### Features -* autoinstall required restic version ([b385c01](https://github.com/garethgeorge/backrest/commit/b385c011210087e6d6992a4e4b279fec4b22ab89)) -* basic forget support in backend and UI ([d22d9d1](https://github.com/garethgeorge/backrest/commit/d22d9d1a05831fae94ce397c0c73c6292d378cf5)) -* begin UI integration with backend ([cccdd29](https://github.com/garethgeorge/backrest/commit/cccdd297c15cd47268b2a1903e9624bdbca3dc68)) -* display queued operations ([0c818bb](https://github.com/garethgeorge/backrest/commit/0c818bb9452a944d8b1127e553142e1e60ed90af)) -* forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) -* forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) -* implement add plan UI ([9288589](https://github.com/garethgeorge/backrest/commit/92885898cf551a2dcb4bb315f130138cd7a8cc67)) -* implement backup scheduling in orchestrator ([eadb1a8](https://github.com/garethgeorge/backrest/commit/eadb1a82019f0cfc82edf8559adbad7730a4e86a)) -* implement basic plan view ([4c6f042](https://github.com/garethgeorge/backrest/commit/4c6f042250946a036e46225e669ee39e2433b198)) -* implement delete button for plan and repo UIs ([ffb0d85](https://github.com/garethgeorge/backrest/commit/ffb0d859f19f4af66a7521768dab083995f9672a)) -* implement forget and prune support in restic pkg ([ffb4573](https://github.com/garethgeorge/backrest/commit/ffb4573737a73cc32f325bc0b9c3feed764b7879)) -* implement forget operation ([ebccf3b](https://github.com/garethgeorge/backrest/commit/ebccf3bc3b78083aee635de7c6ae23b52ee88284)) -* implement repo, edit, and supporting RPCs ([d282c32](https://github.com/garethgeorge/backrest/commit/d282c32c8bd3d8f5747e934d4af6a84faca1ec86)) -* implement snapshot browsing ([8ffffa0](https://github.com/garethgeorge/backrest/commit/8ffffa05e41ca31e2d38fde5427dae34ac4a1abb)) -* implement snapshot indexing ([a90b30e](https://github.com/garethgeorge/backrest/commit/a90b30e19f7107874bbfe244451b07f72c437213)) -* improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/backrest/issues/22)) ([51b4921](https://github.com/garethgeorge/backrest/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19)) -* initial oplog implementation ([dd9142c](https://github.com/garethgeorge/backrest/commit/dd9142c0e97e1175ff12f2861220af0e0d68b7d9)) -* initial optree implementation ([ba390a2](https://github.com/garethgeorge/backrest/commit/ba390a2ca1b5e9adaab36a7db0d988f54f5a6cdd)) -* operations IDs are ordered by operation timestamp ([a1ed6f9](https://github.com/garethgeorge/backrest/commit/a1ed6f90ba1d608e00c53221db45b67251085aa7)) -* present list of operations on plan view ([6491dbe](https://github.com/garethgeorge/backrest/commit/6491dbed146967c0e12eee4392d1d12843dc7c5e)) -* repo can be created through UI ([9ccade5](https://github.com/garethgeorge/backrest/commit/9ccade5ccd97f4e485d52ad5c675be6b0a4a1049)) -* scaffolding basic UI structure ([1273f81](https://github.com/garethgeorge/backrest/commit/1273f8105a2549b0ccd0c7a588eb60646b66366e)) -* show snapshots in sidenav ([1a9a5b6](https://github.com/garethgeorge/backrest/commit/1a9a5b60d24dd75752e5a3f84dd87af3e38422bb)) -* snapshot items are viewable in the UI and minor element ordering fixes ([a333001](https://github.com/garethgeorge/backrest/commit/a33300175c645f31b95b3038de02821a1f3d5559)) -* support ImportSnapshotOperation in oplog ([89f95b3](https://github.com/garethgeorge/backrest/commit/89f95b351fe250534cd39ac27ff34b2b148256e1)) -* update getting started guide ([2c421d6](https://github.com/garethgeorge/backrest/commit/2c421d661501fa4a3120aa3f39937cd58b29c2dc)) - +- autoinstall required restic version ([b385c01](https://github.com/garethgeorge/backrest/commit/b385c011210087e6d6992a4e4b279fec4b22ab89)) +- basic forget support in backend and UI ([d22d9d1](https://github.com/garethgeorge/backrest/commit/d22d9d1a05831fae94ce397c0c73c6292d378cf5)) +- begin UI integration with backend ([cccdd29](https://github.com/garethgeorge/backrest/commit/cccdd297c15cd47268b2a1903e9624bdbca3dc68)) +- display queued operations ([0c818bb](https://github.com/garethgeorge/backrest/commit/0c818bb9452a944d8b1127e553142e1e60ed90af)) +- forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) +- forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) +- implement add plan UI ([9288589](https://github.com/garethgeorge/backrest/commit/92885898cf551a2dcb4bb315f130138cd7a8cc67)) +- implement backup scheduling in orchestrator ([eadb1a8](https://github.com/garethgeorge/backrest/commit/eadb1a82019f0cfc82edf8559adbad7730a4e86a)) +- implement basic plan view ([4c6f042](https://github.com/garethgeorge/backrest/commit/4c6f042250946a036e46225e669ee39e2433b198)) +- implement delete button for plan and repo UIs ([ffb0d85](https://github.com/garethgeorge/backrest/commit/ffb0d859f19f4af66a7521768dab083995f9672a)) +- implement forget and prune support in restic pkg ([ffb4573](https://github.com/garethgeorge/backrest/commit/ffb4573737a73cc32f325bc0b9c3feed764b7879)) +- implement forget operation ([ebccf3b](https://github.com/garethgeorge/backrest/commit/ebccf3bc3b78083aee635de7c6ae23b52ee88284)) +- implement repo, edit, and supporting RPCs ([d282c32](https://github.com/garethgeorge/backrest/commit/d282c32c8bd3d8f5747e934d4af6a84faca1ec86)) +- implement snapshot browsing ([8ffffa0](https://github.com/garethgeorge/backrest/commit/8ffffa05e41ca31e2d38fde5427dae34ac4a1abb)) +- implement snapshot indexing ([a90b30e](https://github.com/garethgeorge/backrest/commit/a90b30e19f7107874bbfe244451b07f72c437213)) +- improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/backrest/issues/22)) ([51b4921](https://github.com/garethgeorge/backrest/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19)) +- initial oplog implementation ([dd9142c](https://github.com/garethgeorge/backrest/commit/dd9142c0e97e1175ff12f2861220af0e0d68b7d9)) +- initial optree implementation ([ba390a2](https://github.com/garethgeorge/backrest/commit/ba390a2ca1b5e9adaab36a7db0d988f54f5a6cdd)) +- operations IDs are ordered by operation timestamp ([a1ed6f9](https://github.com/garethgeorge/backrest/commit/a1ed6f90ba1d608e00c53221db45b67251085aa7)) +- present list of operations on plan view ([6491dbe](https://github.com/garethgeorge/backrest/commit/6491dbed146967c0e12eee4392d1d12843dc7c5e)) +- repo can be created through UI ([9ccade5](https://github.com/garethgeorge/backrest/commit/9ccade5ccd97f4e485d52ad5c675be6b0a4a1049)) +- scaffolding basic UI structure ([1273f81](https://github.com/garethgeorge/backrest/commit/1273f8105a2549b0ccd0c7a588eb60646b66366e)) +- show snapshots in sidenav ([1a9a5b6](https://github.com/garethgeorge/backrest/commit/1a9a5b60d24dd75752e5a3f84dd87af3e38422bb)) +- snapshot items are viewable in the UI and minor element ordering fixes ([a333001](https://github.com/garethgeorge/backrest/commit/a33300175c645f31b95b3038de02821a1f3d5559)) +- support ImportSnapshotOperation in oplog ([89f95b3](https://github.com/garethgeorge/backrest/commit/89f95b351fe250534cd39ac27ff34b2b148256e1)) +- update getting started guide ([2c421d6](https://github.com/garethgeorge/backrest/commit/2c421d661501fa4a3120aa3f39937cd58b29c2dc)) ### Bug Fixes -* build and test fixes ([4957496](https://github.com/garethgeorge/backrest/commit/49574967871494dcb5095e5699610097466f57f9)) -* connectivity issues with embedded server ([482cc8e](https://github.com/garethgeorge/backrest/commit/482cc8ebbc93b919991f6566b212247c5874f70f)) -* deadlock in snapshots ([93b2120](https://github.com/garethgeorge/backrest/commit/93b2120f74ea348e5084ab430573368bf4066eec)) -* forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) -* improve error message formatting ([ae33b01](https://github.com/garethgeorge/backrest/commit/ae33b01de408af3b1d711a369298a2782a24ad1e)) -* improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) -* improve UI performance ([8488d46](https://github.com/garethgeorge/backrest/commit/8488d461bd7ffec2e8171d67f83093c32c79073f)) -* repo orchestrator tests ([d077fc8](https://github.com/garethgeorge/backrest/commit/d077fc83c97b7fbdbeda9702828c8780182b2616)) -* restic fails to detect summary event for very short backups ([46b2a85](https://github.com/garethgeorge/backrest/commit/46b2a8567706ddb21cfcf3e18b57e16d50809b56)) -* standardize on fully qualified snapshot_id and decouple protobufs from restic package ([e6031bf](https://github.com/garethgeorge/backrest/commit/e6031bfa543a7300e622c1b0f56efc6320e7611e)) -* support more versions of restic ([0cdfd11](https://github.com/garethgeorge/backrest/commit/0cdfd115e29a0b08d5814e71c0f4a8f2baf52e90)) -* task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) -* time formatting in operation list ([53c7f12](https://github.com/garethgeorge/backrest/commit/53c7f1248f5284080fff872ac79b3996474412b3)) -* UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/backrest/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9)) +- build and test fixes ([4957496](https://github.com/garethgeorge/backrest/commit/49574967871494dcb5095e5699610097466f57f9)) +- connectivity issues with embedded server ([482cc8e](https://github.com/garethgeorge/backrest/commit/482cc8ebbc93b919991f6566b212247c5874f70f)) +- deadlock in snapshots ([93b2120](https://github.com/garethgeorge/backrest/commit/93b2120f74ea348e5084ab430573368bf4066eec)) +- forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) +- improve error message formatting ([ae33b01](https://github.com/garethgeorge/backrest/commit/ae33b01de408af3b1d711a369298a2782a24ad1e)) +- improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) +- improve UI performance ([8488d46](https://github.com/garethgeorge/backrest/commit/8488d461bd7ffec2e8171d67f83093c32c79073f)) +- repo orchestrator tests ([d077fc8](https://github.com/garethgeorge/backrest/commit/d077fc83c97b7fbdbeda9702828c8780182b2616)) +- restic fails to detect summary event for very short backups ([46b2a85](https://github.com/garethgeorge/backrest/commit/46b2a8567706ddb21cfcf3e18b57e16d50809b56)) +- standardize on fully qualified snapshot_id and decouple protobufs from restic package ([e6031bf](https://github.com/garethgeorge/backrest/commit/e6031bfa543a7300e622c1b0f56efc6320e7611e)) +- support more versions of restic ([0cdfd11](https://github.com/garethgeorge/backrest/commit/0cdfd115e29a0b08d5814e71c0f4a8f2baf52e90)) +- task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) +- time formatting in operation list ([53c7f12](https://github.com/garethgeorge/backrest/commit/53c7f1248f5284080fff872ac79b3996474412b3)) +- UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/backrest/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9)) ## [0.2.0](https://github.com/garethgeorge/backrest/compare/v0.1.3...v0.2.0) (2023-12-03) - ### Features -* forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) -* forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) -* improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/backrest/issues/22)) ([51b4921](https://github.com/garethgeorge/backrest/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19)) - +- forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) +- forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) +- improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/backrest/issues/22)) ([51b4921](https://github.com/garethgeorge/backrest/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19)) ### Bug Fixes -* forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) -* improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) -* task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) -* UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/backrest/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9)) +- forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) +- improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) +- task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) +- UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/backrest/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9)) ## [0.2.0](https://github.com/garethgeorge/backrest/compare/v0.1.3...v0.2.0) (2023-12-02) - ### Features -* forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) -* forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) - +- forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) +- forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) ### Bug Fixes -* forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) -* improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) -* task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) +- forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) +- improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) +- task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64f29bcd..6ec9f96e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,11 +8,12 @@ This repo uses [Conventional Commits](https://www.conventionalcommits.org/en/v1. **Build Dependencies** - * Node.JS for UI development - * Go 1.21 or greater for server development - * goreleaser `go install github.com/goreleaser/goreleaser@latest` +- Node.JS for UI development +- Go 1.21 or greater for server development +- goreleaser `go install github.com/goreleaser/goreleaser@latest` **To Edit Protobuffers** + ```sh apt install -y protobuf-compiler go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest @@ -22,6 +23,7 @@ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install connectrpc.com/connect/cmd/protoc-gen-connect-go@latest npm install -g @bufbuild/protoc-gen-es @connectrpc/protoc-gen-connect-es ``` + ## Building ```sh diff --git a/README.md b/README.md index 9ddff319..f92d088e 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@

------ +--- **Overview** Backrest is a web-accessible backup solution built on top of [restic](https://restic.net/). Backrest provides a WebUI which wraps the restic CLI and makes it easy to create repos, browse snapshots, and restore files. Additionally, Backrest can run in the background and take an opinionated approach to scheduling snapshots and orchestrating repo health operations. -By building on restic, Backrest leverages restic's mature feature set. Restic provides fast, reliable, and secure backup operations. +By building on restic, Backrest leverages restic's mature feature set. Restic provides fast, reliable, and secure backup operations. Backrest itself is built in Golang (matching restic's implementation) and is shipped as a self-contained and light weight binary with no dependecies other than restic. This project aims to be the easiest way to setup and get started with backups on any system. You can expect to be able to perform all operations from the web interface but should you ever need more control, you are free to browse your repo and perform operations using the [restic cli](https://restic.readthedocs.io/en/latest/manual_rest.html). Additionally, Backrest can safely detect and import your existing snapshots (or externally created snapshots on an ongoing basis). @@ -25,25 +25,25 @@ Backrest itself is built in Golang (matching restic's implementation) and is shi **Platform Support** - * [Docker](https://hub.docker.com/r/garethgeorge/backrest) - * Linux - * MacOS - * Windows - * FreeBSD +- [Docker](https://hub.docker.com/r/garethgeorge/backrest) +- Linux +- MacOS +- Windows +- FreeBSD **Features** - * WebUI supports local and remote access (e.g. run on a NAS and access from your desktop) - * Multi-platform support (Linux, MacOS, Windows, FreeBSD, [Docker](https://hub.docker.com/r/garethgeorge/backrest)) - * Import your existing restic repositories - * Cron scheduled backups and health operations (e.g. prune and forget) - * UI for browing and restoring files from snapshots - * Configurable backup notifications (e.g. Discord, Slack, Shoutrrr, Gotify) - * Add shell command hooks to run before and after backup operations. - * Compatible with rclone remotes - * Backup to any restic supported storage (e.g. S3, B2, Azure, GCS, local, SFTP, and all [rclone remotes](https://rclone.org/)) +- WebUI supports local and remote access (e.g. run on a NAS and access from your desktop) +- Multi-platform support (Linux, MacOS, Windows, FreeBSD, [Docker](https://hub.docker.com/r/garethgeorge/backrest)) +- Import your existing restic repositories +- Cron scheduled backups and health operations (e.g. prune and forget) +- UI for browing and restoring files from snapshots +- Configurable backup notifications (e.g. Discord, Slack, Shoutrrr, Gotify) +- Add shell command hooks to run before and after backup operations. +- Compatible with rclone remotes +- Backup to any restic supported storage (e.g. S3, B2, Azure, GCS, local, SFTP, and all [rclone remotes](https://rclone.org/)) ------ +--- # User Guide @@ -55,9 +55,9 @@ Backrest is packaged as a single executable. It can be run directly on Linux, Ma Download options - * Download and run a release from the [releases page](https://github.com/garethgeorge/backrest/releases). - * Build from source ([see below](#building)). - * Run with docker: `garethgeorge/backrest:latest` ([see on dockerhub](https://hub.docker.com/r/garethgeorge/backrest)) or `garethgeorge/backrest:latest-alpine` for an image that includes rclone and common unix utilities. +- Download and run a release from the [releases page](https://github.com/garethgeorge/backrest/releases). +- Build from source ([see below](#building)). +- Run with docker: `garethgeorge/backrest:latest` ([see on dockerhub](https://hub.docker.com/r/garethgeorge/backrest)) or `garethgeorge/backrest:latest-alpine` for an image that includes rclone and common unix utilities. Backrest is accessible from a web browser. By default it binds to `0.0.0.0:9898` and can be accessed at `http://localhost:9898`. Change the port with the `BACKREST_PORT` environment variable e.g. `BACKREST_PORT=127.0.0.1 backrest` to listen only on local interfaces. On first startup backrest will prompt you to create a default username and password, this can be changed later in the settings page. @@ -122,9 +122,9 @@ cd backrest && ./install.sh The install script will: - * Move the backrest binary to `/usr/local/bin` - * Create a systemd service file at `/etc/systemd/system/backrest.service` - * Enable and start the service +- Move the backrest binary to `/usr/local/bin` +- Create a systemd service file at `/etc/systemd/system/backrest.service` +- Enable and start the service Read the script before running it to make sure you are comfortable with these operations. @@ -188,8 +188,6 @@ brew install backrest This tap uses [Brew services](https://github.com/Homebrew/homebrew-services) to launch and manage Backrest's lifecycle. Backrest will launch on startup and run on port ':9898` by default. - - #### Manually using the install script (Recommended) Download a Darwin release from the [releases page](https://github.com/garethgeorge/backrest/releases) and install it to `/usr/local/bin`. @@ -205,9 +203,9 @@ cd backrest && ./install.sh The install script will: - * Move the backrest binary to `/usr/local/bin` - * Create a launch agent file at `~/Library/LaunchAgents/com.backrest.plist` - * Load the launch agent +- Move the backrest binary to `/usr/local/bin` +- Create a launch agent file at `~/Library/LaunchAgents/com.backrest.plist` +- Load the launch agent Read the script before running it to make sure you are comfortable with these operations. @@ -229,8 +227,8 @@ warning: Backrest is not tested on Windows to the same bar as Linux and MacOS. S ## Environment Variables - * `BACKREST_PORT` - the port to bind to. Defaults to 9898. - * `BACKREST_CONFIG` - the path to the config file. Defaults to `$HOME/.config/backrest/config.json` or if `$XDG_CONFIG_HOME` is set, `$XDG_CONFIG_HOME/backrest/config.json`. - * `BACKREST_DATA` - the path to the data directory. Defaults to `$HOME/.local/share/backrest` or if `$XDG_DATA_HOME` is set, `$XDG_DATA_HOME/backrest`. - * `BACKREST_RESTIC_COMMAND` - the path to the restic binary. Defaults managed version of restic which will be downloaded and installed in the data directory. - * `XDG_CACHE_HOME` -- the path to the cache directory. This is propagated to restic. +- `BACKREST_PORT` - the port to bind to. Defaults to 9898. +- `BACKREST_CONFIG` - the path to the config file. Defaults to `$HOME/.config/backrest/config.json` or if `$XDG_CONFIG_HOME` is set, `$XDG_CONFIG_HOME/backrest/config.json`. +- `BACKREST_DATA` - the path to the data directory. Defaults to `$HOME/.local/share/backrest` or if `$XDG_DATA_HOME` is set, `$XDG_DATA_HOME/backrest`. +- `BACKREST_RESTIC_COMMAND` - the path to the restic binary. Defaults managed version of restic which will be downloaded and installed in the data directory. +- `XDG_CACHE_HOME` -- the path to the cache directory. This is propagated to restic. diff --git a/docs/.eslintrc.cjs b/docs/.eslintrc.cjs index f0dc02bc..45b86ae3 100644 --- a/docs/.eslintrc.cjs +++ b/docs/.eslintrc.cjs @@ -1,14 +1,9 @@ module.exports = { root: true, - extends: ['@nuxt/eslint-config'], - ignorePatterns: [ - 'dist', - 'node_modules', - '.output', - '.nuxt' - ], + extends: ["@nuxt/eslint-config"], + ignorePatterns: ["dist", "node_modules", ".output", ".nuxt"], rules: { - 'vue/max-attributes-per-line': 'off', - 'vue/multi-word-component-names': 'off' - } -} \ No newline at end of file + "vue/max-attributes-per-line": "off", + "vue/multi-word-component-names": "off", + }, +}; diff --git a/docs/app.config.ts b/docs/app.config.ts index c340be74..2c02cd47 100644 --- a/docs/app.config.ts +++ b/docs/app.config.ts @@ -1,33 +1,33 @@ // https://github.com/nuxt-themes/docus/blob/main/nuxt.schema.ts export default defineAppConfig({ docus: { - title: 'Backrest', - description: 'Backrest is a web UI and orchestrator for restic backup.', + title: "Backrest", + description: "Backrest is a web UI and orchestrator for restic backup.", // image: 'https://user-images.githubusercontent.com/904724/185365452-87b7ca7b-6030-4813-a2db-5e65c785bf88.png', socials: { - github: 'garethgeorge/backrest', + github: "garethgeorge/backrest", }, github: { - dir: 'docs/content', - branch: 'main', - repo: 'backrest', - owner: 'garethgeorge', - edit: true + dir: "docs/content", + branch: "main", + repo: "backrest", + owner: "garethgeorge", + edit: true, }, aside: { level: 0, collapsed: false, - exclude: [] + exclude: [], }, main: { padded: true, - fluid: true + fluid: true, }, header: { logo: false, showLinkIcon: true, exclude: [], fluid: true, - } - } -}) + }, + }, +}); diff --git a/docs/content/0.index.md b/docs/content/0.index.md index 4b40cb40..7299a6e2 100644 --- a/docs/content/0.index.md +++ b/docs/content/0.index.md @@ -8,14 +8,16 @@ main: :ellipsis{right=0px width=75% blur=150px} -::block-hero ---- +## ::block-hero + cta: - - Get started - - /introduction/getting-started -secondary: - - Open on GitHub → - - https://github.com/garethgeorge/backrest + +- Get started +- /introduction/getting-started + secondary: +- Open on GitHub → +- https://github.com/garethgeorge/backrest + --- #title @@ -25,29 +27,32 @@ Web UI and orchestrator for [Restic](https://restic.net) backup. Backrest is a web-accessible backup solution built on top of [restic](https://restic.net/) and providing a WebUI which wraps the restic CLI and makes it easy to create repos, browse snapshots, and restore files. Additionally, Backrest can run in the background and take an opinionated approach to scheduling snapshots and orchestrating repo health operations. - #extra - ::list - - Import your existing restic repositories - - Cron scheduled backups and health operations (e.g. prune and forget) - - UI for browing and restoring files from snapshots - - Configurable backup notifications (e.g. Discord, Slack, Shoutrrr, Gotify) - - Add shell command hooks to run before and after backup operations. - - Compatible with rclone remotes - - Cross-platform support (Linux, MacOS, Windows, FreeBSD, [Docker](https://hub.docker.com/r/garethgeorge/backrest)) - - Backup to any restic supported storage (e.g. S3, B2, Azure, GCS, local, SFTP, and all [rclone remotes](https://rclone.org/)) +::list + +- Import your existing restic repositories +- Cron scheduled backups and health operations (e.g. prune and forget) +- UI for browing and restoring files from snapshots +- Configurable backup notifications (e.g. Discord, Slack, Shoutrrr, Gotify) +- Add shell command hooks to run before and after backup operations. +- Compatible with rclone remotes +- Cross-platform support (Linux, MacOS, Windows, FreeBSD, [Docker](https://hub.docker.com/r/garethgeorge/backrest)) +- Backup to any restic supported storage (e.g. S3, B2, Azure, GCS, local, SFTP, and all [rclone remotes](https://rclone.org/)) :: #support ::code-group + ```bash [MacOS] brew tap garethgeorge/homebrew-backrest-tap brew install backrest ``` + ```bash [Arch Linux] paru -Sy backrest sudo systemctl enable --now backreset@$USER.service ``` + ```yaml [docker-compose] version: "3.2" services: @@ -69,5 +74,6 @@ services: ports: - 9898:9898 ``` + :: :: diff --git a/docs/content/1.introduction/1.getting-started.md b/docs/content/1.introduction/1.getting-started.md index 3f05d507..189be094 100644 --- a/docs/content/1.introduction/1.getting-started.md +++ b/docs/content/1.introduction/1.getting-started.md @@ -8,14 +8,14 @@ See the Githu ## Terminology - * **Restic Repo** Backrest uses [restic](https://restic.net) under-the-hood to manage backups. A restic repo is a location where restic will store your backup data, this detail is typically abstracted away from the user by Backrest but is important to understand as it means you have the option to use the restic CLI to interact with snapshots created by Backrest directly if you wish. - * **Repo** A Backrest repo (called a Repo from here on) is configuration data which identifies a location where your backup data will be stored (forwarded to restic), the credentials that will encrypt your backup data, hooks, and any options needed by backrest to orchestrate your backups. - * **Plan** A Backrest plan (called a Plan from here on) is configuration data that describes a schedule for taking snapshots, forgetting old snapshots, and running prune operations. Multiple plans can write data to the same Backrest repo. - * **Operations** - * A **Backup** creates a restic snapshot and send it to a repo. - * A **Forget** operation marks old snapshots for deletion but does not remove data from storage. - * A **Prune** operation removes data from storage that is no longer referenced by any snapshot (see [restic docs on forget and prune](https://restic.readthedocs.io/en/latest/060_forget.html)). - * A **Restore** operation retrieves files from a snapshot and writes them to a location on disk. +- **Restic Repo** Backrest uses [restic](https://restic.net) under-the-hood to manage backups. A restic repo is a location where restic will store your backup data, this detail is typically abstracted away from the user by Backrest but is important to understand as it means you have the option to use the restic CLI to interact with snapshots created by Backrest directly if you wish. +- **Repo** A Backrest repo (called a Repo from here on) is configuration data which identifies a location where your backup data will be stored (forwarded to restic), the credentials that will encrypt your backup data, hooks, and any options needed by backrest to orchestrate your backups. +- **Plan** A Backrest plan (called a Plan from here on) is configuration data that describes a schedule for taking snapshots, forgetting old snapshots, and running prune operations. Multiple plans can write data to the same Backrest repo. +- **Operations** + - A **Backup** creates a restic snapshot and send it to a repo. + - A **Forget** operation marks old snapshots for deletion but does not remove data from storage. + - A **Prune** operation removes data from storage that is no longer referenced by any snapshot (see [restic docs on forget and prune](https://restic.readthedocs.io/en/latest/060_forget.html)). + - A **Restore** operation retrieves files from a snapshot and writes them to a location on disk. ## Configuration @@ -29,28 +29,29 @@ A Backrest repository is implemented as a restic repository under-the-hood (more The primary properties of a repository are: - * **Repo Name** A human-readable name for the repository. This is used to identify the repository in the UI and is immutable after creation. +- **Repo Name** A human-readable name for the repository. This is used to identify the repository in the UI and is immutable after creation. - * **Repo URI** identifies the location where the repo's data is stored. This corresponds to the URI used by restic. See [the restic docs](https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html) for the repo types that restic supports. For common storage providers this looks like: +- **Repo URI** identifies the location where the repo's data is stored. This corresponds to the URI used by restic. See [the restic docs](https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html) for the repo types that restic supports. For common storage providers this looks like: - * Backblaze: `b2:yourbucket` or `b2:yourbucket/pathprefix` - * AWS S3 (or S3 compatible storage): `s3:yourbucket` or `s3:yourbucket/pathprefix` - * SFTP e.g. `sftp:user@host:/path/to/repo` (note `sftp://` is known to have issues in some cases, do not include a double slash prefix). - * Local path: `/mnt/backupdisk/repo1`. - * Rclone remote: `rclone:remote:path`. See the [rclone docs](https://rclone.org/docs/) for more information. To use rclone remotes, you must first install and configure rclone and ensure that the rclone config (e.g. `~/.config/rclone/rclone.conf`) is available to the backrest process. + - Backblaze: `b2:yourbucket` or `b2:yourbucket/pathprefix` + - AWS S3 (or S3 compatible storage): `s3:yourbucket` or `s3:yourbucket/pathprefix` + - SFTP e.g. `sftp:user@host:/path/to/repo` (note `sftp://` is known to have issues in some cases, do not include a double slash prefix). + - Local path: `/mnt/backupdisk/repo1`. + - Rclone remote: `rclone:remote:path`. See the [rclone docs](https://rclone.org/docs/) for more information. To use rclone remotes, you must first install and configure rclone and ensure that the rclone config (e.g. `~/.config/rclone/rclone.conf`) is available to the backrest process. - * **Environment Variables** environment variables provide additional configuration to restic (typically related to credentials for the storage provider). Common examples are - - * For S3 storage set: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` - * For B2 storage set: `B2_ACCOUNT_ID` and `B2_ACCOUNT_KEY` +- **Environment Variables** environment variables provide additional configuration to restic (typically related to credentials for the storage provider). Common examples are - * **Flags** additional flags to provide to restic. At the moment only presence flags are supported. Common usage might include: - - * `-o sftp.args="-i /path/to/key"` will pass an SSH key to restic for use with SFTP repositories. - * `--no-lock` will disable the use of locks in the restic repository. This can be useful for read-only repos. - * `--limit-upload 1000` will limit the upload speed to a speed in kilobytes per second (e.g. 1000KB/s). This can be useful to avoid saturating a network connection. - * `--limit-download 1000` will limit the download speed to a speed in kilobytes per second (e.g. 1000KB/s). This can be useful to avoid saturating a network connection. - * **Hooks** are actions triggered by backup lifecycle events, repo hooks will apply to actions run by any plan that writes to the repo. Hooks can also be configured at the plan level. See the [hooks documentation](/docs/hooks) for more information. + - For S3 storage set: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` + - For B2 storage set: `B2_ACCOUNT_ID` and `B2_ACCOUNT_KEY` + +- **Flags** additional flags to provide to restic. At the moment only presence flags are supported. Common usage might include: + + - `-o sftp.args="-i /path/to/key"` will pass an SSH key to restic for use with SFTP repositories. + - `--no-lock` will disable the use of locks in the restic repository. This can be useful for read-only repos. + - `--limit-upload 1000` will limit the upload speed to a speed in kilobytes per second (e.g. 1000KB/s). This can be useful to avoid saturating a network connection. + - `--limit-download 1000` will limit the download speed to a speed in kilobytes per second (e.g. 1000KB/s). This can be useful to avoid saturating a network connection. + +- **Hooks** are actions triggered by backup lifecycle events, repo hooks will apply to actions run by any plan that writes to the repo. Hooks can also be configured at the plan level. See the [hooks documentation](/docs/hooks) for more information. ::alert{type="info"} Once you've added your repo you're ready to import snapshots (click Index Snapshots) if you have existing data. Go on to configure a backup plan to start creating new snapshots. @@ -62,27 +63,26 @@ A Backrest plan is a configuration object which describes a schedule for taking The primary properties of a plan are: - * **Plan Name** the plan name is immutable after creation, choose carefully. Organizationally it can help to choose a name that includes the type of storage or a short form of the name of the repo that will be used. E.g. to backup "Documents" directory to "b2storage" you might create a plan named "b2-documents" or similar. +- **Plan Name** the plan name is immutable after creation, choose carefully. Organizationally it can help to choose a name that includes the type of storage or a short form of the name of the repo that will be used. E.g. to backup "Documents" directory to "b2storage" you might create a plan named "b2-documents" or similar. - * **Repository** the repository that this plan will operate on. This is immutable after creation. +- **Repository** the repository that this plan will operate on. This is immutable after creation. - * **Paths** a list of paths to include in backups. +- **Paths** a list of paths to include in backups. - * **Excludes** a list of paths to exclude from backup operations. These can be fully qualified paths (e.g. /foo/bar/baz) or wildcard paths (e.g. `*node_modules*`). See the [restic docs](https://restic.readthedocs.io/en/latest/040_backup.html#excluding-files) on excluding files for more details. Files listed in excludes map to restic's `--excludes` flag. +- **Excludes** a list of paths to exclude from backup operations. These can be fully qualified paths (e.g. /foo/bar/baz) or wildcard paths (e.g. `*node_modules*`). See the [restic docs](https://restic.readthedocs.io/en/latest/040_backup.html#excluding-files) on excluding files for more details. Files listed in excludes map to restic's `--excludes` flag. - * **Schedule** the schedule on which backups will run. This is expressed in cron format (configurable visually in the webui). +- **Schedule** the schedule on which backups will run. This is expressed in cron format (configurable visually in the webui). - * **Retention Policy** the duration that snapshots are retained for. This is enforced by running `restic forget` after each backup operation if a retention policy is specified. This can be set to none for append only repos or if you'd like to manage your own retention (e.g. run forget manually). Setting some retention policy is recommended to avoid the snapshot history growing without bound. Retention may be configured either based on count or bucketed by time period. See [the restic docs](https://restic.readthedocs.io/en/latest/060_forget.html#removing-snapshots-according-to-a-policy) to understand more about these policy options. Supported modes are: - - * **By Count** - keeps a fixed number of snapshots. E.g. keep the last 7 snapshots. - * **By Time Period** - keeps snapshots in a time-based bucket. E.g. keep 1 snapshot per day for the last 7 days, 1 snapshot per week for the last 4 weeks, and 1 snapshot per month for the last 12 months. - * **None** - no retention policy is enforced. This is useful for append-only repos or if you'd like to manage retention manually e.g. in an external script. Note that care should be taken not to allow snapshots to grow without bound (though Backrest will typically scale and perform well with hundreds to thousands of snapshots). +- **Retention Policy** the duration that snapshots are retained for. This is enforced by running `restic forget` after each backup operation if a retention policy is specified. This can be set to none for append only repos or if you'd like to manage your own retention (e.g. run forget manually). Setting some retention policy is recommended to avoid the snapshot history growing without bound. Retention may be configured either based on count or bucketed by time period. See [the restic docs](https://restic.readthedocs.io/en/latest/060_forget.html#removing-snapshots-according-to-a-policy) to understand more about these policy options. Supported modes are: - * **Hooks** hooks are actions that can be configured in response to backup lifecycle events. See the hooks page of the wiki for more details. - * **Backup Flags** flags that are specific to the backup command (e.g. `--force` to force a full scan of all files rather than relying on metadata). These flags are passed directly to the restic command. - * `--one-file-system` will prevent restic crossing filesystem boundaries. - * `--force` will force rereading all files on each backup rather than relying on metadata (e.g. last modified time). This can be much slower. + - **By Count** - keeps a fixed number of snapshots. E.g. keep the last 7 snapshots. + - **By Time Period** - keeps snapshots in a time-based bucket. E.g. keep 1 snapshot per day for the last 7 days, 1 snapshot per week for the last 4 weeks, and 1 snapshot per month for the last 12 months. + - **None** - no retention policy is enforced. This is useful for append-only repos or if you'd like to manage retention manually e.g. in an external script. Note that care should be taken not to allow snapshots to grow without bound (though Backrest will typically scale and perform well with hundreds to thousands of snapshots). +- **Hooks** hooks are actions that can be configured in response to backup lifecycle events. See the hooks page of the wiki for more details. +- **Backup Flags** flags that are specific to the backup command (e.g. `--force` to force a full scan of all files rather than relying on metadata). These flags are passed directly to the restic command. + - `--one-file-system` will prevent restic crossing filesystem boundaries. + - `--force` will force rereading all files on each backup rather than relying on metadata (e.g. last modified time). This can be much slower. ::alert{type="success"} Success! Now that Backrest is configured you can sit back and let it manage your backups. You can monitor the status of your backups in the UI and restore files from snapshots as needed. @@ -90,4 +90,4 @@ Success! Now that Backrest is configured you can sit back and let it manage your ::alert{type="warning"} Make sure that you save a copy of your repo credentials and any encryption keys (e.g. the password) in a safe place. If you lose these you will not be able to restore your data. It can be a good idea to store your entire Backrest config (typically located at `~/.config/backrest/config.json`) in a secure location e.g. a password manager or encrypted storage. -:: \ No newline at end of file +:: diff --git a/docs/content/2.docs/1.operations.md b/docs/content/2.docs/1.operations.md index d4df2f5b..eae89ccf 100644 --- a/docs/content/2.docs/1.operations.md +++ b/docs/content/2.docs/1.operations.md @@ -14,23 +14,23 @@ When running restic commands, Backrest injects the environment variables configu [Restic docs on backup](https://restic.readthedocs.io/en/latest/040_backup.html) -A backup operation creates a snapshot of your data and sends it to a repository. The snapshot is created using the `restic backup` command. +A backup operation creates a snapshot of your data and sends it to a repository. The snapshot is created using the `restic backup` command. -As the backup runs Backrest will display the progress of the backup operation in the UI. The progress information is parsed from the JSON output of the `restic backup` command. +As the backup runs Backrest will display the progress of the backup operation in the UI. The progress information is parsed from the JSON output of the `restic backup` command. The backup flow is as follows - * Hook trigger: `CONDITION_SNAPSHOT_START`, if any hooks are configured for this event they will run. - * If any hook exits with a non-zero status, the hook's failure policy will be applied (e.g. cancelling or failing the backup operation). - * The `restic backup` command is run. The newly craeted snapshot is tagged with the ID of the plan creating it e.g. `plan:{PLAN_ID}`. - * The summary event is parsed from the backup and is stored in the operation's metadata. This includes: files added, files changed, files unmodified, total files processed, bytes added, bytes processed, and most importantly the snapshot ID. - * If an error occurred: hook trigger `CONDITION_SNAPSHOT_ERROR`, if any hooks are configured for this event they will run. - * Hook trigger: `CONDITION_SNAPSHOT_END`, if any hooks are configured for this event they will run. This condition is always triggered even if the backup failed. +- Hook trigger: `CONDITION_SNAPSHOT_START`, if any hooks are configured for this event they will run. + - If any hook exits with a non-zero status, the hook's failure policy will be applied (e.g. cancelling or failing the backup operation). +- The `restic backup` command is run. The newly craeted snapshot is tagged with the ID of the plan creating it e.g. `plan:{PLAN_ID}`. +- The summary event is parsed from the backup and is stored in the operation's metadata. This includes: files added, files changed, files unmodified, total files processed, bytes added, bytes processed, and most importantly the snapshot ID. +- If an error occurred: hook trigger `CONDITION_SNAPSHOT_ERROR`, if any hooks are configured for this event they will run. +- Hook trigger: `CONDITION_SNAPSHOT_END`, if any hooks are configured for this event they will run. This condition is always triggered even if the backup failed. If the backup completed successfully, Backrest triggers followup operations - * If a retention policy is set (e.g. not `None`) a forget operation is triggered for the backup plan. - * If a prune policy is set (e.g. not `None`) a prune operation is triggered for the backup plan if it has been long enough since the last prune operation. +- If a retention policy is set (e.g. not `None`) a forget operation is triggered for the backup plan. +- If a prune policy is set (e.g. not `None`) a prune operation is triggered for the backup plan if it has been long enough since the last prune operation. #### Forget @@ -40,8 +40,8 @@ A forget operation marks old snapshots for deletion but does not remove data fro Retention policies are mapped to forget arguments: - * **By Count** maps to `--keep-last {COUNT}` - * **By Time Period** maps to the `--keep-{hourly,daily,weekly,monthly,yearly} {COUNT}` flags +- **By Count** maps to `--keep-last {COUNT}` +- **By Time Period** maps to the `--keep-{hourly,daily,weekly,monthly,yearly} {COUNT}` flags Note that forget will never run for a plan if the forget policy is set to `None`. @@ -53,7 +53,7 @@ A prune operation removes data from storage that is no longer referenced by any Prunes are run in compliance with a prune policy which specifies: - * **Max Frequency Days** - the minimum time in days between prune operations. A prune is skipped following a backup if the last prune was less than this many days ago. This is to prevent excessive pruning which can be slow and is bandwidth intensive as prunes may read and rewrite portions of the repository. - * **Max Unused Percent** - the maximum percentage of the repository that may be left unused after a prune operation runs. Prune operations will try to repack blobs in the repository if more than this percentage of their is unused (e.g. formerly held data belonging to forgotten snapshots). +- **Max Frequency Days** - the minimum time in days between prune operations. A prune is skipped following a backup if the last prune was less than this many days ago. This is to prevent excessive pruning which can be slow and is bandwidth intensive as prunes may read and rewrite portions of the repository. +- **Max Unused Percent** - the maximum percentage of the repository that may be left unused after a prune operation runs. Prune operations will try to repack blobs in the repository if more than this percentage of their is unused (e.g. formerly held data belonging to forgotten snapshots). Prune operations do not support json output so the logs of a prune operation are not parsed for progress information, they are instead displayed as raw text in the Backrest UI as they are received from the restic process. diff --git a/docs/content/2.docs/2.hooks.md b/docs/content/2.docs/2.hooks.md index fa945fc0..3576f3cb 100644 --- a/docs/content/2.docs/2.hooks.md +++ b/docs/content/2.docs/2.hooks.md @@ -4,13 +4,13 @@ Backrest supports hooks in response to operation lifecycle events e.g. in response to the commands it runs on your behalf. -Available event types are +Available event types are - * `CONDITION_ANY_ERROR` any operation has failed. - * `CONDITION_SNAPSHOT_START` the start of a backup operation (e.g. corresponds to a call to `restic backup`) - * `CONDITION_SNAPSHOT_END` the end of a backup operation (e.g. corresponds to `restic backup` completing). Note that Snapshot End will still be called if a backup failed. - * `CONDITION_SNAPSHOT_ERROR` an error occurred during a backup operation (e.g. `restic backup` returned a non-zero exit code OR invalid output). - * `CONDITION_SNAPSHOT_WARNING` a warning occurred during a backup operation (e.g. a file was partially read). +- `CONDITION_ANY_ERROR` any operation has failed. +- `CONDITION_SNAPSHOT_START` the start of a backup operation (e.g. corresponds to a call to `restic backup`) +- `CONDITION_SNAPSHOT_END` the end of a backup operation (e.g. corresponds to `restic backup` completing). Note that Snapshot End will still be called if a backup failed. +- `CONDITION_SNAPSHOT_ERROR` an error occurred during a backup operation (e.g. `restic backup` returned a non-zero exit code OR invalid output). +- `CONDITION_SNAPSHOT_WARNING` a warning occurred during a backup operation (e.g. a file was partially read). ## Notification Services @@ -28,22 +28,22 @@ Most hooks will generate either a notification or execute a script. The script / Variables - * `Event:v1.Hook_Condition` - the event that triggered the backup. This is an enum. Values are one of: Hook_CONDITION_SNAPSHOT_START, Hook_CONDITION_SNAPSHOT_END, Hook_CONDITION_ANY_ERROR, Hook_CONDITION_SNAPSHOT_ERROR . - * `Task:string` - the name of the task that triggered the hook (e.g. `one time backup for plan "foo"` - * `Repo:v1.Repo` - the repo that triggered the backup. This is a struct. Access the name as `{{ .Repo.Id }}` - * `Plan:v1.Plan` - the plan that triggered the backup. This is a struct. Access the name as `{{ .Plan.Id }}` - * `SnapshotId:string` - the snapshot ID associated with the operation or empty string if none is associated. - * `SnapshotStats:restic.BackupProgressEntry` - summary of the current backup operation. This is a struct. See examples below for details. - * `CurTime:time.Time` - the current time. This is a struct. Format as `{{ .FormatTime .CurTime }}`. - * `Error:string` - the error message if an error occurred, or empty string if successful. +- `Event:v1.Hook_Condition` - the event that triggered the backup. This is an enum. Values are one of: Hook_CONDITION_SNAPSHOT_START, Hook_CONDITION_SNAPSHOT_END, Hook_CONDITION_ANY_ERROR, Hook_CONDITION_SNAPSHOT_ERROR . +- `Task:string` - the name of the task that triggered the hook (e.g. `one time backup for plan "foo"` +- `Repo:v1.Repo` - the repo that triggered the backup. This is a struct. Access the name as `{{ .Repo.Id }}` +- `Plan:v1.Plan` - the plan that triggered the backup. This is a struct. Access the name as `{{ .Plan.Id }}` +- `SnapshotId:string` - the snapshot ID associated with the operation or empty string if none is associated. +- `SnapshotStats:restic.BackupProgressEntry` - summary of the current backup operation. This is a struct. See examples below for details. +- `CurTime:time.Time` - the current time. This is a struct. Format as `{{ .FormatTime .CurTime }}`. +- `Error:string` - the error message if an error occurred, or empty string if successful. Functions - - * `.Summary` - prints a default summary of the current event. - * `.FormatTime Go template variables - - Functions - - - +export const hooksListTooltipText = ( + <> + Hooks are actions that can execute on backup lifecycle events. Available + events are: + + Arguments are available to hooks as{" "} + + Go template variables + + + Functions + + +); /** * HooksFormList is a UI component for editing a list of hooks that can apply either at the repo level or at the plan level. @@ -58,186 +89,291 @@ export const hooksListTooltipText = <> export const HooksFormList = () => { const form = Form.useFormInstance(); - return - {(fields, { add, remove }, { errors }) => ( - <> - {fields.map((field, index) => { - const hookData = form.getFieldValue(["hooks", field.name]) as HookFields; + return ( + + {(fields, { add, remove }, { errors }) => ( + <> + {fields.map((field, index) => { + const hookData = form.getFieldValue([ + "hooks", + field.name, + ]) as HookFields; - return - Hook {index} {findHookTypeName(hookData)} - remove(field.name)} - style={{ marginRight: "5px", marginTop: "2px", float: "right" }} - /> - - } size="small" style={{ marginBottom: "5px" }}> - - ({ label: v.name, value: v.name }))} + /> + + { + return prevValues.hooks[index] !== curValues.hooks[index]; + }} + > + + + + ); + })} + + + {hookTypes.map((hookType, index) => { + return ( + + ); + })} + + } + style={{ width: "60%" }} + placement="bottom" + > + + + + + + )} + + ); +}; const hookTypes: { - name: string, - template: HookFields, - oneofKey: string, - component: ({ field }: { field: FormListFieldData }) => React.ReactNode + name: string; + template: HookFields; + oneofKey: string; + component: ({ field }: { field: FormListFieldData }) => React.ReactNode; }[] = [ - { - name: "Command", template: { - actionCommand: { - command: "echo {{ .ShellEscape .Summary }}", - }, - conditions: [], + { + name: "Command", + template: { + actionCommand: { + command: "echo {{ .ShellEscape .Summary }}", }, - oneofKey: "actionCommand", - component: ({ field }: { field: FormListFieldData }) => { - return <> + conditions: [], + }, + oneofKey: "actionCommand", + component: ({ field }: { field: FormListFieldData }) => { + return ( + <> Script: - - + + - } + ); }, - { - name: "Shoutrrr", template: { - actionShoutrrr: { - template: "{{ .Summary }}", - }, - conditions: [], + }, + { + name: "Shoutrrr", + template: { + actionShoutrrr: { + template: "{{ .Summary }}", }, - oneofKey: "actionShoutrrr", - component: ({ field }: { field: FormListFieldData }) => { - return <> - - Shoutrrr is a multi-platform notification service, see docs to learn more about supported services - }> -
Shoutrrr URL
- } + conditions: [], + }, + oneofKey: "actionShoutrrr", + component: ({ field }: { field: FormListFieldData }) => { + return ( + <> + + + Shoutrrr is a multi-platform notification service,{" "} + + see docs + {" "} + to learn more about supported services + + } + > +
Shoutrrr URL
+ + } /> -
- Text Template: - - - - - } - }, - { - name: "Discord", template: { - actionDiscord: { - webhookUrl: "", - template: "{{ .Summary }}", - }, - conditions: [], - }, - oneofKey: "actionDiscord", - component: ({ field }: { field: FormListFieldData }) => { - return <> - - Discord Webhook} /> - - Text Template: - - - - - } - }, - { - name: "Gotify", template: { - actionGotify: { - baseUrl: "", - token: "", - template: "{{ .Summary }}", - titleTemplate: "Backrest {{ .EventName .Event }} in plan {{ .Plan.Id }}", - }, - conditions: [], - }, - oneofKey: "actionGotify", - component: ({ field }: { field: FormListFieldData }) => { - return <> - - Gotify Base URL} /> - - - Gotify Token} /> - - Title Template} /> + Text Template: + + + + + ); + }, + }, + { + name: "Discord", + template: { + actionDiscord: { + webhookUrl: "", + template: "{{ .Summary }}", + }, + conditions: [], + }, + oneofKey: "actionDiscord", + component: ({ field }: { field: FormListFieldData }) => { + return ( + <> + + Discord Webhook} + /> + + Text Template: + + + + + ); + }, + }, + { + name: "Gotify", + template: { + actionGotify: { + baseUrl: "", + token: "", + template: "{{ .Summary }}", + titleTemplate: + "Backrest {{ .EventName .Event }} in plan {{ .Plan.Id }}", + }, + conditions: [], + }, + oneofKey: "actionGotify", + component: ({ field }: { field: FormListFieldData }) => { + return ( + <> + + Gotify Base URL} + /> + + + Gotify Token} + /> + + + Title Template} + /> Text Template: - + - } + ); }, - { - name: "Slack", template: { - actionSlack: { - webhookUrl: "", - template: "{{ .Summary }}", - }, - conditions: [], + }, + { + name: "Slack", + template: { + actionSlack: { + webhookUrl: "", + template: "{{ .Summary }}", }, - oneofKey: "actionSlack", - component: ({ field }: { field: FormListFieldData }) => { - return <> - - Slack Webhook} /> - + conditions: [], + }, + oneofKey: "actionSlack", + component: ({ field }: { field: FormListFieldData }) => { + return ( + <> + + Slack Webhook} + /> + Text Template: - - - + + + - } - } - ]; + ); + }, + }, +]; const findHookTypeName = (field: HookFields): string => { if (!field) { @@ -249,7 +385,7 @@ const findHookTypeName = (field: HookFields): string => { } } return "Unknown"; -} +}; const HookBuilder = ({ field }: { field: FormListFieldData }) => { const form = Form.useFormInstance(); @@ -266,28 +402,50 @@ const HookBuilder = ({ field }: { field: FormListFieldData }) => { } return

Unknown hook type

; -} +}; const ItemOnErrorSelector = ({ field }: { field: FormListFieldData }) => { - return <> - - What happens when the hook fails (currently only has effect on backup start hooks) -
    -
  • IGNORE - the failure is ignored, subsequent hooks and the backup operation will run as normal.
  • -
  • FATAL - stops the backup with an error status (triggers an error notification). Skips running all subsequent hooks.
  • -
  • CANCEL - marks the backup as cancelled but does not trigger any error notification. Skips running all subsequent hooks.
  • -
- }>Error Behavior: -
- - ({ label: v.name, value: v.name }))} + /> + + + ); +}; -const requiredField = (message: string, extra?: Rule) => ({ required: true, message: message }); \ No newline at end of file +const requiredField = (message: string, extra?: Rule) => ({ + required: true, + message: message, +}); diff --git a/webui/src/components/OperationList.tsx b/webui/src/components/OperationList.tsx index d6b3110a..1df1d743 100644 --- a/webui/src/components/OperationList.tsx +++ b/webui/src/components/OperationList.tsx @@ -4,10 +4,7 @@ import { OperationEvent, OperationEventType, } from "../../gen/ts/v1/operations_pb"; -import { - Empty, - List, -} from "antd"; +import { Empty, List } from "antd"; import { BackupInfo, BackupInfoCollector, @@ -30,8 +27,8 @@ export const OperationList = ({ }: React.PropsWithoutRef<{ req?: GetOperationsRequest; useBackups?: BackupInfo[]; - showPlan?: boolean, - filter?: (op: Operation) => boolean, // if provided, only operations that pass this filter will be displayed. + showPlan?: boolean; + filter?: (op: Operation) => boolean; // if provided, only operations that pass this filter will be displayed. }>) => { const alertApi = useAlertApi(); @@ -62,13 +59,15 @@ export const OperationList = ({ }; subscribeToOperations(lis); - backupCollector.subscribe(_.debounce(() => { - let backups = backupCollector.getAll(); - backups.sort((a, b) => { - return b.startTimeMs - a.startTimeMs; - }); - setBackups(backups); - }, 50)); + backupCollector.subscribe( + _.debounce(() => { + let backups = backupCollector.getAll(); + backups.sort((a, b) => { + return b.startTimeMs - a.startTimeMs; + }); + setBackups(backups); + }, 50), + ); getOperations(req) .then((ops) => { @@ -94,9 +93,9 @@ export const OperationList = ({ ); } - let operations = backups.flatMap((b) => b.operations) + let operations = backups.flatMap((b) => b.operations); operations.sort((a, b) => { - return Number(b.unixTimeStartMs - a.unixTimeStartMs) + return Number(b.unixTimeStartMs - a.unixTimeStartMs); }); return ( { - return + return ( + + ); }} pagination={ operations.length > 25 @@ -114,4 +120,3 @@ export const OperationList = ({ /> ); }; - diff --git a/webui/src/components/OperationRow.tsx b/webui/src/components/OperationRow.tsx index bf272994..c1371602 100644 --- a/webui/src/components/OperationRow.tsx +++ b/webui/src/components/OperationRow.tsx @@ -47,12 +47,15 @@ import { useShowModal } from "./ModalManager"; import { proto3 } from "@bufbuild/protobuf"; import { Hook_Condition } from "../../gen/ts/v1/config_pb"; - export const OperationRow = ({ operation, alertApi, showPlan, -}: React.PropsWithoutRef<{ operation: Operation, alertApi?: MessageInstance, showPlan: boolean }>) => { +}: React.PropsWithoutRef<{ + operation: Operation; + alertApi?: MessageInstance; + showPlan: boolean; +}>) => { const showModal = useShowModal(); const details = detailsForOperation(operation); const displayType = getTypeForDisplay(operation); @@ -94,38 +97,75 @@ export const OperationRow = ({ const opName = displayTypeToString(getTypeForDisplay(operation)); let title = ( <> - {showPlan ? operation.planId + " - " : undefined} {formatTime(Number(operation.unixTimeStartMs))} - {opName}{" "} + {showPlan ? operation.planId + " - " : undefined}{" "} + {formatTime(Number(operation.unixTimeStartMs))} - {opName}{" "} {details.displayState} ); - if (operation.status === OperationStatus.STATUS_PENDING || operation.status == OperationStatus.STATUS_INPROGRESS) { - title = <> - {title} - - + if ( + operation.status === OperationStatus.STATUS_PENDING || + operation.status == OperationStatus.STATUS_INPROGRESS + ) { + title = ( + <> + {title} + + + ); } if (operation.logref) { - title = <> - {title} - - - - + title = ( + <> + {title} + + + + + ); } let body: React.ReactNode | undefined; @@ -133,7 +173,7 @@ export const OperationRow = ({ if (operation.op.case === "operationBackup") { const backupOp = operation.op.value; - const items: { key: number, label: string, children: React.ReactNode }[] = [ + const items: { key: number; label: string; children: React.ReactNode }[] = [ { key: 1, label: "Backup Details", @@ -145,7 +185,11 @@ export const OperationRow = ({ items.splice(0, 0, { key: 2, label: "Item Errors", - children:
{backupOp.errors.map(e => "Error on item: " + e.item).join("\n")}
, + children: ( +
+            {backupOp.errors.map((e) => "Error on item: " + e.item).join("\n")}
+          
+ ), }); } @@ -170,7 +214,7 @@ export const OperationRow = ({ ); } else if (operation.op.case === "operationForget") { const forgetOp = operation.op.value; - body = + body = ; } else if (operation.op.case === "operationPrune") { const prune = operation.op.value; body = ( @@ -194,21 +238,35 @@ export const OperationRow = ({ {details.percentage !== undefined ? ( ) : null} - {operation.status == OperationStatus.STATUS_SUCCESS ? (<> -
- - ) : null} + {operation.status == OperationStatus.STATUS_SUCCESS ? ( + <> +
+ + + ) : null} ); } else if (operation.op.case === "operationRunHook") { const hook = operation.op.value; - const triggeringCondition = proto3.getEnumType(Hook_Condition).findNumber(hook.condition); + const triggeringCondition = proto3 + .getEnumType(Hook_Condition) + .findNumber(hook.condition); if (triggeringCondition !== undefined) { displayMessage += "\ntriggered by condition: " + triggeringCondition.name; } @@ -217,9 +275,14 @@ export const OperationRow = ({ const children = []; if (operation.displayMessage) { - children.push(<> -
{details.state ? details.state + ": " : null}{displayMessage}
- ); + children.push( + <> +
+          {details.state ? details.state + ": " : null}
+          {displayMessage}
+        
+ , + ); } children.push(body); @@ -303,7 +366,7 @@ const BackupOperationStatus = ({ const st = status.entry.value; const progress = Math.round( - (Number(st.bytesDone) / Math.max(Number(st.totalBytes), 1)) * 1000 + (Number(st.bytesDone) / Math.max(Number(st.totalBytes), 1)) * 1000, ) / 10; return ( <> @@ -313,7 +376,8 @@ const BackupOperationStatus = ({ Bytes Done/Total
- {formatBytes(Number(st.bytesDone))}/{formatBytes(Number(st.totalBytes))} + {formatBytes(Number(st.bytesDone))}/ + {formatBytes(Number(st.totalBytes))} Files Done/Total @@ -376,7 +440,11 @@ const BackupOperationStatus = ({ } }; -const ForgetOperationDetails = ({ forgetOp }: { forgetOp: OperationForget }) => { +const ForgetOperationDetails = ({ + forgetOp, +}: { + forgetOp: OperationForget; +}) => { const policy = forgetOp.policy! || {}; const policyDesc = []; if (policy.keepLastN) { @@ -406,25 +474,33 @@ const ForgetOperationDetails = ({ forgetOp }: { forgetOp: OperationForget }) => { key: 1, label: "Removed " + forgetOp.forget?.length + " Snapshots", - children: <> - Removed snapshots: -
{forgetOp.forget?.map((f) => (
-              
- {"removed snapshot " + normalizeSnapshotId(f.id!) + " taken at " + formatTime(Number(f.unixTimeMs))}
-
- ))}
- {/* Policy: + children: ( + <> + Removed snapshots: +
+                {forgetOp.forget?.map((f) => (
+                  
+ {"removed snapshot " + + normalizeSnapshotId(f.id!) + + " taken at " + + formatTime(Number(f.unixTimeMs))}{" "} +
+
+ ))} +
+ {/* Policy:
    {policyDesc.map((desc, idx) => (
  • {desc}
  • ))}
*/} - , + + ), }, ]} /> ); -} +}; // TODO: refactor this to use the provider pattern const BigOperationDataVerbatim = ({ logref }: { logref: string }) => { @@ -434,14 +510,19 @@ const BigOperationDataVerbatim = ({ logref }: { logref: string }) => { if (!logref) { return; } - backrestService.getLogs(new LogDataRequest({ - ref: logref, - })).then((resp) => { - setOutput(new TextDecoder("utf-8").decode(resp.value)); - }).catch((e) => { - console.error("Failed to fetch hook output: ", e); - }); + backrestService + .getLogs( + new LogDataRequest({ + ref: logref, + }), + ) + .then((resp) => { + setOutput(new TextDecoder("utf-8").decode(resp.value)); + }) + .catch((e) => { + console.error("Failed to fetch hook output: ", e); + }); }, [logref]); return
{output}
; -} +}; diff --git a/webui/src/components/OperationTree.tsx b/webui/src/components/OperationTree.tsx index 2d56027b..aaa50ce9 100644 --- a/webui/src/components/OperationTree.tsx +++ b/webui/src/components/OperationTree.tsx @@ -26,10 +26,18 @@ import { QuestionOutlined, SaveOutlined, } from "@ant-design/icons"; -import { OperationEvent, OperationEventType, OperationStatus } from "../../gen/ts/v1/operations_pb"; +import { + OperationEvent, + OperationEventType, + OperationStatus, +} from "../../gen/ts/v1/operations_pb"; import { useAlertApi } from "./Alerts"; import { OperationList } from "./OperationList"; -import { ClearHistoryRequest, ForgetRequest, GetOperationsRequest } from "../../gen/ts/v1/service_pb"; +import { + ClearHistoryRequest, + ForgetRequest, + GetOperationsRequest, +} from "../../gen/ts/v1/service_pb"; import { isMobile } from "../lib/browserutil"; import { useShowModal } from "./ModalManager"; import { backrestService } from "../api"; @@ -67,13 +75,15 @@ export const OperationTree = ({ }; subscribeToOperations(lis); - backupCollector.subscribe(_.debounce(() => { - let backups = backupCollector.getAll(); - backups.sort((a, b) => { - return b.startTimeMs - a.startTimeMs; - }); - setBackups(backups); - }, 50)); + backupCollector.subscribe( + _.debounce(() => { + let backups = backupCollector.getAll(); + backups.sort((a, b) => { + return b.startTimeMs - a.startTimeMs; + }); + setBackups(backups); + }, 50), + ); getOperations(req) .then((ops) => { @@ -81,7 +91,8 @@ export const OperationTree = ({ }) .catch((e) => { alertApi!.error("Failed to fetch operations: " + e.messag); - }).finally(() => { + }) + .finally(() => { setLoading(false); }); return () => { @@ -104,91 +115,104 @@ export const OperationTree = ({ const useMobileLayout = isMobile(); - const backupTree = - treeData={treeData} - showIcon - defaultExpandedKeys={backups.slice(0, Math.min(5, backups.length)).map((b) => b.id!)} - onSelect={(keys, info) => { - if (info.selectedNodes.length === 0) return; - const backup = info.selectedNodes[0].backup; - if (!backup) { - setSelectedBackupId(null); - return; - } - setSelectedBackupId(backup.id!); - - if (useMobileLayout) { - showModal( - { showModal(null); }}> - - - ); - } - }} - titleRender={(node: OpTreeNode): React.ReactNode => { - if (node.title) { - return <>{node.title}; - } - if (node.backup) { - const b = node.backup; - const details: string[] = []; - - if (b.operations.length === 0) { - // this happens when all operations in a backup are deleted; it should be hidden until the deletion propagates to a refresh of the tree layout. - return null; + const backupTree = ( + + treeData={treeData} + showIcon + defaultExpandedKeys={backups + .slice(0, Math.min(5, backups.length)) + .map((b) => b.id!)} + onSelect={(keys, info) => { + if (info.selectedNodes.length === 0) return; + const backup = info.selectedNodes[0].backup; + if (!backup) { + setSelectedBackupId(null); + return; } + setSelectedBackupId(backup.id!); - if (b.status === OperationStatus.STATUS_PENDING) { - details.push("scheduled, waiting"); - } else if (b.status === OperationStatus.STATUS_SYSTEM_CANCELLED) { - details.push("system cancel"); - } else if (b.status === OperationStatus.STATUS_USER_CANCELLED) { - details.push("cancelled"); - } - - if (b.backupLastStatus) { - if (b.backupLastStatus.entry.case === "summary") { - const s = b.backupLastStatus.entry.value; - details.push( - `${formatBytes(Number(s.totalBytesProcessed))} in ${formatDuration( - s.totalDuration! * 1000.0 // convert to ms - )}` - ); - } else if (b.backupLastStatus.entry.case === "status") { - const s = b.backupLastStatus.entry.value; - const percent = Math.floor((Number(s.bytesDone) / Number(s.totalBytes)) * 100); - details.push( - `${percent}% processed ${formatBytes( - Number(s.bytesDone) - )} / ${formatBytes(Number(s.totalBytes))}` - ); - } - } - if (b.snapshotInfo) { - details.push(`ID: ${normalizeSnapshotId(b.snapshotInfo.id)}`); - } - - let detailsElem: React.ReactNode | null = null; - if (details.length > 0) { - detailsElem = ( - - [{details.join(", ")}] - + if (useMobileLayout) { + showModal( + { + showModal(null); + }} + > + + , ); } + }} + titleRender={(node: OpTreeNode): React.ReactNode => { + if (node.title) { + return <>{node.title}; + } + if (node.backup) { + const b = node.backup; + const details: string[] = []; - const type = getTypeForDisplay(b.operations[0]); + if (b.operations.length === 0) { + // this happens when all operations in a backup are deleted; it should be hidden until the deletion propagates to a refresh of the tree layout. + return null; + } + + if (b.status === OperationStatus.STATUS_PENDING) { + details.push("scheduled, waiting"); + } else if (b.status === OperationStatus.STATUS_SYSTEM_CANCELLED) { + details.push("system cancel"); + } else if (b.status === OperationStatus.STATUS_USER_CANCELLED) { + details.push("cancelled"); + } + + if (b.backupLastStatus) { + if (b.backupLastStatus.entry.case === "summary") { + const s = b.backupLastStatus.entry.value; + details.push( + `${formatBytes(Number(s.totalBytesProcessed))} in ${formatDuration( + s.totalDuration! * 1000.0, // convert to ms + )}`, + ); + } else if (b.backupLastStatus.entry.case === "status") { + const s = b.backupLastStatus.entry.value; + const percent = Math.floor( + (Number(s.bytesDone) / Number(s.totalBytes)) * 100, + ); + details.push( + `${percent}% processed ${formatBytes( + Number(s.bytesDone), + )} / ${formatBytes(Number(s.totalBytes))}`, + ); + } + } + if (b.snapshotInfo) { + details.push(`ID: ${normalizeSnapshotId(b.snapshotInfo.id)}`); + } + + let detailsElem: React.ReactNode | null = null; + if (details.length > 0) { + detailsElem = ( + + [{details.join(", ")}] + + ); + } + + const type = getTypeForDisplay(b.operations[0]); + return ( + <> + {displayTypeToString(type)} {formatTime(b.displayTime)}{" "} + {detailsElem} + + ); + } return ( - <> - {displayTypeToString(type)} {formatTime(b.displayTime)} {detailsElem} - + ERROR: this element should not appear, this is a bug. ); - } - return ( - ERROR: this element should not appear, this is a bug. - ); - }} - />; + }} + /> + ); if (useMobileLayout) { return backupTree; @@ -196,10 +220,12 @@ export const OperationTree = ({ return ( + {backupTree} - {backupTree} + {selectedBackupId ? ( + b.id === selectedBackupId)} /> + ) : null} - {selectedBackupId ? b.id === selectedBackupId)} /> : null} ); }; @@ -223,7 +249,10 @@ const buildTreePlan = (operations: BackupInfo[]): OpTreeNode[] => { return entries; }; -const buildTreeDay = (keyPrefix: string, operations: BackupInfo[]): OpTreeNode[] => { +const buildTreeDay = ( + keyPrefix: string, + operations: BackupInfo[], +): OpTreeNode[] => { const grouped = _.groupBy(operations, (op) => { return localISOTime(op.displayTime).substring(0, 10); }); @@ -278,51 +307,67 @@ const BackupView = ({ backup }: { backup?: BackupInfo }) => { } else { const doDeleteSnapshot = async () => { try { - await backrestService.forget(new ForgetRequest({ - planId: backup.planId!, - repoId: backup.repoId!, - snapshotId: backup.snapshotId! - })); + await backrestService.forget( + new ForgetRequest({ + planId: backup.planId!, + repoId: backup.repoId!, + snapshotId: backup.snapshotId!, + }), + ); alertApi!.success("Snapshot forgotten."); } catch (e) { alertApi!.error("Failed to forget snapshot: " + e); } - } + }; - const deleteButton = backup.snapshotId ? + const deleteButton = backup.snapshotId ? ( Forget (Destructive) - : + Forget (Destructive) + + + ) : ( + { - backrestService.clearHistory(new ClearHistoryRequest({ - ops: backup.operations.map((op) => op.id), - })) + backrestService.clearHistory( + new ClearHistoryRequest({ + ops: backup.operations.map((op) => op.id), + }), + ); }} > Delete Event - ; + + ); - return
-
-

Backup on {formatTime(backup.displayTime)}

-
- {backup.status !== OperationStatus.STATUS_PENDING && backup.status != OperationStatus.STATUS_INPROGRESS ? deleteButton : null} + return ( +
+
+

Backup on {formatTime(backup.displayTime)}

+
+ {backup.status !== OperationStatus.STATUS_PENDING && + backup.status != OperationStatus.STATUS_INPROGRESS + ? deleteButton + : null} +
+
- -
; + ); } -} \ No newline at end of file +}; diff --git a/webui/src/components/SnapshotBrowser.tsx b/webui/src/components/SnapshotBrowser.tsx index c868c9a3..295700e4 100644 --- a/webui/src/components/SnapshotBrowser.tsx +++ b/webui/src/components/SnapshotBrowser.tsx @@ -30,7 +30,7 @@ const SnapshotBrowserContext = React.createContext<{ const replaceKeyInTree = ( curNode: DataNode, setKey: string, - setValue: DataNode + setValue: DataNode, ): DataNode | null => { if (curNode.key === setKey) { return setValue; @@ -167,7 +167,7 @@ const respToNodes = (resp: ListSnapshotFilesResponse): DataNode[] => { const FileNode = ({ entry }: { entry: LsEntry }) => { const [dropdown, setDropdown] = useState(null); const { snapshotId, repoId, planId, showModal } = React.useContext( - SnapshotBrowserContext + SnapshotBrowserContext, )!; const showDropdown = () => { @@ -188,7 +188,7 @@ const FileNode = ({ entry }: { entry: LsEntry }) => { onOk={() => showModal(null)} >
{JSON.stringify(entry, null, 2)}
- + , ); }, }, @@ -202,7 +202,7 @@ const FileNode = ({ entry }: { entry: LsEntry }) => { repoId={repoId} planId={planId} snapshotId={snapshotId} - /> + />, ); }, }, @@ -210,7 +210,7 @@ const FileNode = ({ entry }: { entry: LsEntry }) => { }} > - + , ); }; diff --git a/webui/src/components/SpinButton.tsx b/webui/src/components/SpinButton.tsx index dcf537d0..b9c994d9 100644 --- a/webui/src/components/SpinButton.tsx +++ b/webui/src/components/SpinButton.tsx @@ -2,9 +2,11 @@ import React from "react"; import { Button, ButtonProps } from "antd"; import { useState } from "react"; -export const SpinButton: React.FC Promise; -}> = ({ onClickAsync, ...props }) => { +export const SpinButton: React.FC< + ButtonProps & { + onClickAsync: () => Promise; + } +> = ({ onClickAsync, ...props }) => { const [loading, setLoading] = useState(false); const onClick = async () => { @@ -19,20 +21,16 @@ export const SpinButton: React.FC - ); -} + return
} type="number" /> + Count
} + type="number" + />
); } else if (mode === "policyTimeBucketed") { @@ -604,23 +626,34 @@ const RetentionPolicyView = () => { <> - { - const selected = e.target.value; - if (selected === "policyKeepLastN") { - form.setFieldValue("retention", { policyKeepLastN: 30 }); - } else if (selected === "policyTimeBucketed") { - form.setFieldValue("retention", { policyTimeBucketed: { yearly: 0, monthly: 3, weekly: 4, daily: 7, hourly: 24 } }); - } else { - form.setFieldValue("retention", { policyKeepAll: true }); - } - }}> + { + const selected = e.target.value; + if (selected === "policyKeepLastN") { + form.setFieldValue("retention", { policyKeepLastN: 30 }); + } else if (selected === "policyTimeBucketed") { + form.setFieldValue("retention", { + policyTimeBucketed: { + yearly: 0, + monthly: 3, + weekly: 4, + daily: 7, + hourly: 24, + }, + }); + } else { + form.setFieldValue("retention", { policyKeepAll: true }); + } + }} + > By Count - + By Time Period @@ -633,11 +666,9 @@ const RetentionPolicyView = () => {
- - {elem} - + {elem} -
+
); }; diff --git a/webui/src/views/AddRepoModal.tsx b/webui/src/views/AddRepoModal.tsx index 80323f61..b108b3e8 100644 --- a/webui/src/views/AddRepoModal.tsx +++ b/webui/src/views/AddRepoModal.tsx @@ -30,11 +30,7 @@ import { import { ConfirmButton } from "../components/SpinButton"; import { useConfig } from "../components/ConfigProvider"; -export const AddRepoModal = ({ - template, -}: { - template: Repo | null; -}) => { +export const AddRepoModal = ({ template }: { template: Repo | null }) => { const [confirmLoading, setConfirmLoading] = useState(false); const showModal = useShowModal(); const alertsApi = useAlertApi()!; @@ -42,7 +38,7 @@ export const AddRepoModal = ({ const [form] = Form.useForm(); useEffect(() => { form.setFieldsValue(template ? JSON.parse(template.toJsonString()) : {}); - }, [template]) + }, [template]); if (!config) { return null; @@ -78,9 +74,9 @@ export const AddRepoModal = ({ showModal(null); alertsApi.success( "Deleted repo " + - template.id + - " from config but files remain. To release storage delete the files manually. URI: " + - template.uri + template.id + + " from config but files remain. To release storage delete the files manually. URI: " + + template.uri, ); } catch (e: any) { alertsApi.error("Operation failed: " + e.message, 15); @@ -94,7 +90,9 @@ export const AddRepoModal = ({ try { let repoFormData = await validateForm(form); - const repo = new Repo().fromJsonString(JSON.stringify(repoFormData), { ignoreUnknownFields: false }); + const repo = new Repo().fromJsonString(JSON.stringify(repoFormData), { + ignoreUnknownFields: false, + }); if (template !== null) { // We are in the edit repo flow, update the repo in the config @@ -168,7 +166,11 @@ export const AddRepoModal = ({ disabled={confirmLoading} > {/* Repo.id */} - + hasFeedback name="id" @@ -190,8 +192,9 @@ export const AddRepoModal = ({ }, { pattern: namePattern, - message: "Name must be alphanumeric with dashes or underscores as separators", - } + message: + "Name must be alphanumeric with dashes or underscores as separators", + }, ]} > SFTP e.g. sftp:user@host:/repo-path
  • See{" "} - + restic docs {" "} for more info. @@ -240,14 +246,26 @@ export const AddRepoModal = ({ {/* Repo.password */} - This password that encrypts data in your repository. -
      -
    • Recommended to pick a value that is 128 bits of entropy (20 chars or longer)
    • -
    • You may alternatively provide env variable credentials e.g. RESTIC_PASSWORD, RESTIC_PASSWORD_FILE, or RESTIC_PASSWORD_COMMAND.
    • -
    • Click [Generate] to seed a random password from your browser's crypto random API.
    • -
    - } + title={ + <> + This password that encrypts data in your repository. +
      +
    • + Recommended to pick a value that is 128 bits of entropy (20 + chars or longer) +
    • +
    • + You may alternatively provide env variable credentials e.g. + RESTIC_PASSWORD, RESTIC_PASSWORD_FILE, or + RESTIC_PASSWORD_COMMAND. +
    • +
    • + Click [Generate] to seed a random password from your + browser's crypto random API. +
    • +
    + + } > @@ -282,7 +300,11 @@ export const AddRepoModal = ({
    {/* Repo.env */} - + - + {(fields, { add, remove }, { errors }) => ( <> {fields.map((field, index) => ( @@ -399,7 +419,10 @@ export const AddRepoModal = ({ The schedule on which prune operations are run for this repository. Read{" "} - + the restic docs on customizing prune operations {" "} for more details. @@ -436,10 +459,20 @@ export const AddRepoModal = ({ - - Auto Unlock - } name="autoUnlock" valuePropName="checked"> + + Auto Unlock + + } + name="autoUnlock" + valuePropName="checked" + > @@ -459,7 +492,9 @@ export const AddRepoModal = ({ label: "Repo Config as JSON", children: ( -
    {JSON.stringify(form.getFieldsValue(), undefined, 2)}
    +
    +                          {JSON.stringify(form.getFieldsValue(), undefined, 2)}
    +                        
    ), }, @@ -468,7 +503,7 @@ export const AddRepoModal = ({ )} - + ); }; @@ -476,11 +511,20 @@ export const AddRepoModal = ({ const expectedEnvVars: { [scheme: string]: string[][] } = { s3: [["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"]], b2: [["B2_ACCOUNT_ID", "B2_ACCOUNT_KEY"]], - azure: [["AZURE_ACCOUNT_NAME", "AZURE_ACCOUNT_KEY"], ["AZURE_ACCOUNT_NAME", "AZURE_ACCOUNT_SAS"]], - gs: [["GOOGLE_APPLICATION_CREDENTIALS", "GOOGLE_PROJECT_ID"], ["GOOGLE_ACCESS_TOKEN"]], + azure: [ + ["AZURE_ACCOUNT_NAME", "AZURE_ACCOUNT_KEY"], + ["AZURE_ACCOUNT_NAME", "AZURE_ACCOUNT_SAS"], + ], + gs: [ + ["GOOGLE_APPLICATION_CREDENTIALS", "GOOGLE_PROJECT_ID"], + ["GOOGLE_ACCESS_TOKEN"], + ], }; -const envVarSetValidator = (form: FormInstance, envVars: string[]) => { +const envVarSetValidator = ( + form: FormInstance, + envVars: string[], +) => { if (!envVars) { return Promise.resolve(); } @@ -511,8 +555,8 @@ const envVarSetValidator = (form: FormInstance, envVars: string[]) => ) { return Promise.reject( new Error( - "Missing repo password. Either provide a password or set one of the env variables RESTIC_PASSWORD, RESTIC_PASSWORD_COMMAND, RESTIC_PASSWORD_FILE." - ) + "Missing repo password. Either provide a password or set one of the env variables RESTIC_PASSWORD, RESTIC_PASSWORD_COMMAND, RESTIC_PASSWORD_FILE.", + ), ); } @@ -533,7 +577,10 @@ const cryptoRandomPassword = (): string => { return btoa(String.fromCharCode(...vals)).slice(0, 48); }; -const checkSchemeEnvVars = (scheme: string, envVarNames: string[]): Promise => { +const checkSchemeEnvVars = ( + scheme: string, + envVarNames: string[], +): Promise => { let expected = expectedEnvVars[scheme]; if (!expected) { return Promise.resolve(); @@ -542,7 +589,9 @@ const checkSchemeEnvVars = (scheme: string, envVarNames: string[]): Promise !envVarNames.includes(envVar)); + const missingVars = possibility.filter( + (envVar) => !envVarNames.includes(envVar), + ); // If no env vars are missing, we have a full match and are good if (missingVars.length === 0) { @@ -562,16 +611,21 @@ const checkSchemeEnvVars = (scheme: string, envVarNames: string[]): Promise { - return partialMatches.map(x => { - if (x.length > 1) { - return `[ ${x.join(", ")} ]`; - } - return x[0]; - }).join(" or "); -} + return partialMatches + .map((x) => { + if (x.length > 1) { + return `[ ${x.join(", ")} ]`; + } + return x[0]; + }) + .join(" or "); +}; diff --git a/webui/src/views/App.tsx b/webui/src/views/App.tsx index b3eb7c9a..e921a191 100644 --- a/webui/src/views/App.tsx +++ b/webui/src/views/App.tsx @@ -16,7 +16,13 @@ import { useShowModal } from "../components/ModalManager"; import { uiBuildVersion } from "../state/buildcfg"; import { ActivityBar } from "../components/ActivityBar"; import { OperationEvent, OperationStatus } from "../../gen/ts/v1/operations_pb"; -import { colorForStatus, getStatusForPlan, getStatusForRepo, subscribeToOperations, unsubscribeFromOperations } from "../state/oplog"; +import { + colorForStatus, + getStatusForPlan, + getStatusForRepo, + subscribeToOperations, + unsubscribeFromOperations, +} from "../state/oplog"; import LogoSvg from "url:../../assets/logo.svg"; import _ from "lodash"; import { Code } from "@connectrpc/connect"; @@ -41,7 +47,8 @@ export const App: React.FC = () => { useEffect(() => { showModal(); - backrestService.getConfig({}) + backrestService + .getConfig({}) .then((config) => { setConfig(config); if (shouldShowSettings(config)) { @@ -56,12 +63,15 @@ export const App: React.FC = () => { if (err.code) { const code = err.code; if (code === Code.Unauthenticated) { - showModal() + showModal(); return; - } else if (code === Code.Unavailable || code === Code.DeadlineExceeded) { + } else if ( + code === Code.Unavailable || + code === Code.DeadlineExceeded + ) { alertApi.error( "Failed to fetch initial config, typically this means the UI could not connect to the backend", - 0 + 0, ); return; } @@ -70,16 +80,18 @@ export const App: React.FC = () => { alertApi.error(err.message, 0); alertApi.error( "Failed to fetch initial config, typically this means the UI could not connect to the backend", - 0 + 0, ); }); }, []); const showGettingStarted = () => { - setContent(, [{ - title: "Getting Started", - }]); - } + setContent(, [ + { + title: "Getting Started", + }, + ]); + }; useEffect(() => { if (config === null) { @@ -89,7 +101,6 @@ export const App: React.FC = () => { } }, [config === null]); - const items = getSidenavItems(config); return ( @@ -103,15 +114,22 @@ export const App: React.FC = () => { backgroundColor: "#1b232c", }} > - - + +

    - + {uiBuildVersion} @@ -125,7 +143,11 @@ export const App: React.FC = () => { - - - - -} \ No newline at end of file + + + } + type="password" + placeholder="Password" + /> + + + + + + + + + ); +}; diff --git a/webui/src/views/MainContentArea.tsx b/webui/src/views/MainContentArea.tsx index 206c0df7..fde233af 100644 --- a/webui/src/views/MainContentArea.tsx +++ b/webui/src/views/MainContentArea.tsx @@ -12,12 +12,18 @@ interface ContentAreaState { breadcrumbs: Breadcrumb[]; } -type ContentAreaCtx = [ContentAreaState, (content: React.ReactNode, breadcrumbs: Breadcrumb[]) => void]; +type ContentAreaCtx = [ + ContentAreaState, + (content: React.ReactNode, breadcrumbs: Breadcrumb[]) => void, +]; -const ContentAreaContext = React.createContext([{ - content: null, - breadcrumbs: [], -}, (content, breadcrumbs) => { }]); +const ContentAreaContext = React.createContext([ + { + content: null, + breadcrumbs: [], + }, + (content, breadcrumbs) => {}, +]); export const MainContentProvider = ({ children, @@ -31,11 +37,16 @@ export const MainContentProvider = ({ return ( <> - { - setState({ content, breadcrumbs }); - }]}> + { + setState({ content, breadcrumbs }); + }, + ]} + > {children} - + ); }; @@ -43,7 +54,7 @@ export const MainContentProvider = ({ export const useSetContent = () => { const context = React.useContext(ContentAreaContext); return context[1]; -} +}; export const MainContentArea = () => { const { breadcrumbs, content } = React.useContext(ContentAreaContext)[0]; @@ -53,7 +64,10 @@ export const MainContentArea = () => { return ( - + { ); -} +}; diff --git a/webui/src/views/PlanView.tsx b/webui/src/views/PlanView.tsx index 9f1a0586..2a40452a 100644 --- a/webui/src/views/PlanView.tsx +++ b/webui/src/views/PlanView.tsx @@ -51,14 +51,12 @@ export const PlanView = ({ plan }: React.PropsWithChildren<{ plan: Plan }>) => { } catch (e: any) { alertsApi.error("Failed to clear error history: " + e.message); } - } + }; return ( <> - - {plan.id} - + {plan.id} @@ -80,10 +78,13 @@ export const PlanView = ({ plan }: React.PropsWithChildren<{ plan: Plan }>) => { - @@ -97,7 +98,12 @@ export const PlanView = ({ plan }: React.PropsWithChildren<{ plan: Plan }>) => { children: ( <> ), @@ -110,7 +116,12 @@ export const PlanView = ({ plan }: React.PropsWithChildren<{ plan: Plan }>) => { <>

    Backup Action History

    !shouldHideStatus(op.status)} /> diff --git a/webui/src/views/RepoView.tsx b/webui/src/views/RepoView.tsx index 30bdb10c..1540ed70 100644 --- a/webui/src/views/RepoView.tsx +++ b/webui/src/views/RepoView.tsx @@ -1,13 +1,33 @@ import React, { useContext, useEffect, useState } from "react"; import { Repo } from "../../gen/ts/v1/config_pb"; -import { Col, Empty, Flex, Row, Spin, TabsProps, Tabs, Tooltip, Typography, Button } from "antd"; +import { + Col, + Empty, + Flex, + Row, + Spin, + TabsProps, + Tabs, + Tooltip, + Typography, + Button, +} from "antd"; import { OperationList } from "../components/OperationList"; import { OperationTree } from "../components/OperationTree"; import { MAX_OPERATION_HISTORY, STATS_OPERATION_HISTORY } from "../constants"; import { GetOperationsRequest } from "../../gen/ts/v1/service_pb"; -import { BackupInfo, BackupInfoCollector, getOperations, shouldHideStatus } from "../state/oplog"; +import { + BackupInfo, + BackupInfoCollector, + getOperations, + shouldHideStatus, +} from "../state/oplog"; import { formatBytes, formatDate, formatTime } from "../lib/formatting"; -import { Operation, OperationStats, OperationStatus } from "../../gen/ts/v1/operations_pb"; +import { + Operation, + OperationStats, + OperationStatus, +} from "../../gen/ts/v1/operations_pb"; import { backrestService } from "../api"; import { StringValue } from "@bufbuild/protobuf"; import { SpinButton } from "../components/SpinButton"; @@ -16,7 +36,6 @@ import { useAlertApi } from "../components/Alerts"; import { LineChart } from "@mui/x-charts"; import { useShowModal } from "../components/ModalManager"; - export const RepoView = ({ repo }: React.PropsWithChildren<{ repo: Repo }>) => { const [config, setConfig] = useConfig(); const showModal = useShowModal(); @@ -24,21 +43,21 @@ export const RepoView = ({ repo }: React.PropsWithChildren<{ repo: Repo }>) => { // Task handlers const handleIndexNow = async () => { await backrestService.indexSnapshots(new StringValue({ value: repo.id! })); - } + }; const handleStatsNow = async () => { await backrestService.stats(new StringValue({ value: repo.id! })); - } + }; // Gracefully handle deletions by checking if the plan is still in the config. let repoInConfig = config?.repos?.find((r) => r.id === repo.id); if (!repoInConfig) { - return <> - Repo was deleted -
    -        {JSON.stringify(config, null, 2)}
    -      
    - + return ( + <> + Repo was deleted +
    {JSON.stringify(config, null, 2)}
    + + ); } repo = repoInConfig; @@ -50,7 +69,12 @@ export const RepoView = ({ repo }: React.PropsWithChildren<{ repo: Repo }>) => { <>

    Browse Backups

    ), @@ -63,7 +87,12 @@ export const RepoView = ({ repo }: React.PropsWithChildren<{ repo: Repo }>) => { <>

    Backup Action History

    !shouldHideStatus(op.status)} /> @@ -81,13 +110,11 @@ export const RepoView = ({ repo }: React.PropsWithChildren<{ repo: Repo }>) => { ), destroyInactiveTabPane: true, }, - ] + ]; return ( <> - - {repo.id} - + {repo.id} @@ -102,18 +129,18 @@ export const RepoView = ({ repo }: React.PropsWithChildren<{ repo: Repo }>) => { - - + ); }; @@ -128,14 +155,25 @@ const StatsPanel = ({ repoId }: { repoId: string }) => { } const backupCollector = new BackupInfoCollector((op) => { - return op.status === OperationStatus.STATUS_SUCCESS && op.op.case === "operationStats" && !!op.op.value.stats + return ( + op.status === OperationStatus.STATUS_SUCCESS && + op.op.case === "operationStats" && + !!op.op.value.stats + ); }); - getOperations(new GetOperationsRequest({ repoId: repoId, lastN: BigInt(MAX_OPERATION_HISTORY) })) + getOperations( + new GetOperationsRequest({ + repoId: repoId, + lastN: BigInt(MAX_OPERATION_HISTORY), + }), + ) .then((ops) => { backupCollector.bulkAddOperations(ops); - const operations = backupCollector.getAll().flatMap((b) => b.operations); + const operations = backupCollector + .getAll() + .flatMap((b) => b.operations); operations.sort((a, b) => { return Number(b.unixTimeEndMs - a.unixTimeEndMs); }); @@ -147,15 +185,17 @@ const StatsPanel = ({ repoId }: { repoId: string }) => { }, [repoId]); if (operations.length === 0) { - return + return ( + + ); } const dataset: { - time: number, - totalSizeMb: number, - compressionRatio: number, - snapshotCount: number, - totalBlobCount: number, + time: number; + totalSizeMb: number; + compressionRatio: number; + snapshotCount: number; + totalBlobCount: number; }[] = operations.map((op) => { const stats = (op.op.value! as OperationStats).stats!; return { @@ -164,86 +204,96 @@ const StatsPanel = ({ repoId }: { repoId: string }) => { compressionRatio: Number(stats.compressionRatio), snapshotCount: Number(stats.snapshotCount), totalBlobCount: Number(stats.totalBlobCount), - } + }; }); const minTime = Math.min(...dataset.map((d) => d.time)); const maxTime = Math.max(...dataset.map((d) => d.time)); - return <> - - - formatDate(v as number), - min: minTime, - max: maxTime, - }]} - series={[ - { - dataKey: "totalSizeMb", - label: "Total Size", - valueFormatter: (v: any) => formatBytes(v * 1000000 as number), - }, - ]} - height={300} - dataset={dataset} - /> + return ( + <> + + + formatDate(v as number), + min: minTime, + max: maxTime, + }, + ]} + series={[ + { + dataKey: "totalSizeMb", + label: "Total Size", + valueFormatter: (v: any) => + formatBytes((v * 1000000) as number), + }, + ]} + height={300} + dataset={dataset} + /> - formatDate(v as number), - min: minTime, - max: maxTime, - }]} - series={[ - { - dataKey: "compressionRatio", - label: "Compression Ratio", - }, - ]} - height={300} - dataset={dataset} - /> - - - formatDate(v as number), - min: minTime, - max: maxTime, - }]} - series={[ - { - dataKey: "snapshotCount", - label: "Snapshot Count", - }, - ]} - height={300} - dataset={dataset} - /> + formatDate(v as number), + min: minTime, + max: maxTime, + }, + ]} + series={[ + { + dataKey: "compressionRatio", + label: "Compression Ratio", + }, + ]} + height={300} + dataset={dataset} + /> + + + formatDate(v as number), + min: minTime, + max: maxTime, + }, + ]} + series={[ + { + dataKey: "snapshotCount", + label: "Snapshot Count", + }, + ]} + height={300} + dataset={dataset} + /> - formatDate(v as number), - min: minTime, - max: maxTime, - }]} - series={[ - { - dataKey: "totalBlobCount", - label: "Blob Count", - }, - ]} - height={300} - dataset={dataset} - /> - - - - -} \ No newline at end of file + formatDate(v as number), + min: minTime, + max: maxTime, + }, + ]} + series={[ + { + dataKey: "totalBlobCount", + label: "Blob Count", + }, + ]} + height={300} + dataset={dataset} + /> + + + + ); +}; diff --git a/webui/src/views/RunCommandModal.tsx b/webui/src/views/RunCommandModal.tsx index 14112682..64b76d3a 100644 --- a/webui/src/views/RunCommandModal.tsx +++ b/webui/src/views/RunCommandModal.tsx @@ -5,14 +5,12 @@ import { backrestService } from "../api"; import { SpinButton } from "../components/SpinButton"; import { ConnectError } from "@connectrpc/connect"; - interface Invocation { command: string; output: string; error: string; } - export const RunCommandModal = ({ repoId }: { repoId: string }) => { const showModal = useShowModal(); const [command, setCommand] = React.useState(""); @@ -21,7 +19,7 @@ export const RunCommandModal = ({ repoId }: { repoId: string }) => { const handleCancel = () => { showModal(null); - } + }; const doExecute = async () => { if (running) return; @@ -33,7 +31,10 @@ export const RunCommandModal = ({ repoId }: { repoId: string }) => { let segments: string[] = []; try { - for await (const bytes of backrestService.runCommand({ repoId, command })) { + for await (const bytes of backrestService.runCommand({ + repoId, + command, + })) { const output = new TextDecoder("utf-8").decode(bytes.value); segments.push(output); setInvocations((invocations) => { @@ -41,7 +42,7 @@ export const RunCommandModal = ({ repoId }: { repoId: string }) => { copy[0] = { ...copy[0], output: segments.join(""), - } + }; return copy; }); } @@ -51,32 +52,44 @@ export const RunCommandModal = ({ repoId }: { repoId: string }) => { copy[0] = { ...copy[0], error: (e as Error).message, - } + }; return copy; }); } finally { setRunning(false); } - } + }; - return - - setCommand(e.target.value)} onKeyUp={(e) => { - if (e.key === "Enter") { - doExecute(); - } - }} /> - Execute - - {invocations.map((invocation, i) =>
    - {invocation.output ?
    {invocation.output}
    : null} - {invocation.error ?
    {invocation.error}
    : null} -
    )} -
    -} \ No newline at end of file + return ( + + + setCommand(e.target.value)} + onKeyUp={(e) => { + if (e.key === "Enter") { + doExecute(); + } + }} + /> + + Execute + + + {invocations.map((invocation, i) => ( +
    + {invocation.output ?
    {invocation.output}
    : null} + {invocation.error ? ( +
    {invocation.error}
    + ) : null} +
    + ))} +
    + ); +}; diff --git a/webui/src/views/SettingsModal.tsx b/webui/src/views/SettingsModal.tsx index ed00e2d2..8585050b 100644 --- a/webui/src/views/SettingsModal.tsx +++ b/webui/src/views/SettingsModal.tsx @@ -25,12 +25,12 @@ import { authenticationService, backrestService } from "../api"; interface FormData { auth: { - users: ({ + users: { name: string; passwordBcrypt: string; needsBcrypt?: boolean; - })[]; - } + }[]; + }; instance: string; } @@ -52,7 +52,9 @@ export const SettingsModal = () => { if (formData.auth?.users) { for (const user of formData.auth?.users) { if (user.needsBcrypt) { - const hash = await authenticationService.hashPassword({ value: user.passwordBcrypt }); + const hash = await authenticationService.hashPassword({ + value: user.passwordBcrypt, + }); user.passwordBcrypt = hash.value; delete user.needsBcrypt; } @@ -61,11 +63,15 @@ export const SettingsModal = () => { // Update configuration let newConfig = config!.clone(); - newConfig.auth = new Auth().fromJson(formData.auth, { ignoreUnknownFields: false }); + newConfig.auth = new Auth().fromJson(formData.auth, { + ignoreUnknownFields: false, + }); newConfig.instance = formData.instance; if (!newConfig.auth?.users && !newConfig.auth?.disabled) { - throw new Error("At least one user must be configured or authentication must be disabled"); + throw new Error( + "At least one user must be configured or authentication must be disabled", + ); } setConfig(await backrestService.setConfig(newConfig)); @@ -96,11 +102,7 @@ export const SettingsModal = () => { , - , ]} @@ -111,19 +113,21 @@ export const SettingsModal = () => { labelCol={{ span: 6 }} wrapperCol={{ span: 16 }} > - {(users.length > 0 || config.auth?.disabled) ? null : ( + {users.length > 0 || config.auth?.disabled ? null : ( <> Initial backrest setup!

    - Backrest has detected that you do not have any users configured, please add at least one user to secure the web interface. + Backrest has detected that you do not have any users configured, + please add at least one user to secure the web interface.

    - You can add more users later or, if you forget your password, reset users by editing the configuration file (typically in $HOME/.backrest/config.json) + You can add more users later or, if you forget your password, + reset users by editing the configuration file (typically in + $HOME/.backrest/config.json)

    )} - { initialValue={config.instance || ""} rules={[ { required: true, message: "Instance ID is required" }, - { pattern: namePattern, message: "Instance ID must be alphanumeric with '_-.' allowed as separators" }, + { + pattern: namePattern, + message: + "Instance ID must be alphanumeric with '_-.' allowed as separators", + }, ]} > - + @@ -152,13 +167,19 @@ export const SettingsModal = () => { {(fields, { add, remove }) => ( <> {fields.map((field, index) => { - return ( @@ -166,12 +187,26 @@ export const SettingsModal = () => { - { - form.setFieldValue(["auth", "users", index, "needsBcrypt"], true); - form.setFieldValue(["auth", "users", index, "passwordBcrypt"], ""); - }} /> + { + form.setFieldValue( + ["auth", "users", index, "needsBcrypt"], + true, + ); + form.setFieldValue( + ["auth", "users", index, "passwordBcrypt"], + "", + ); + }} + /> @@ -182,7 +217,7 @@ export const SettingsModal = () => { /> - ) + ); })}