From 6728271a9891f25b88e4a380c1d695d213b2f6ca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 21:12:26 +0200 Subject: [PATCH 001/113] fix(deps): update bun minor and patch dependencies (#842) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- bun.lock | 24 +++++++++++++----------- package.json | 4 ++-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/bun.lock b/bun.lock index ab238f54..70ec0554 100644 --- a/bun.lock +++ b/bun.lock @@ -26,7 +26,7 @@ "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.2.8", "@scalar/hono-api-reference": "^0.10.4", - "@tanstack/react-hotkeys": "^0.9.0", + "@tanstack/react-hotkeys": "^0.10.0", "@tanstack/react-query": "^5.91.3", "@tanstack/react-query-devtools": "^5.91.3", "@tanstack/react-router": "^1.168.1", @@ -70,7 +70,7 @@ "devDependencies": { "@effect/language-service": "^0.85.0", "@faker-js/faker": "^10.3.0", - "@hey-api/openapi-ts": "^0.96.0", + "@hey-api/openapi-ts": "^0.97.0", "@libsql/client": "^0.17.2", "@playwright/test": "^1.58.2", "@rolldown/plugin-babel": "^0.2.2", @@ -458,13 +458,13 @@ "@fumadocs/tailwind": ["@fumadocs/tailwind@0.0.3", "", { "dependencies": { "postcss-selector-parser": "^7.1.1" }, "peerDependencies": { "tailwindcss": "^4.0.0" }, "optionalPeers": ["tailwindcss"] }, "sha512-/FWcggMz9BhoX+13xBoZLX+XX9mYvJ50dkTqy3IfocJqua65ExcsKfxwKH8hgTO3vA5KnWv4+4jU7LaW2AjAmQ=="], - "@hey-api/codegen-core": ["@hey-api/codegen-core@0.8.0", "", { "dependencies": { "@hey-api/types": "0.1.4", "ansi-colors": "4.1.3", "c12": "3.3.4", "color-support": "1.1.3" } }, "sha512-OuF/jenX9wz7AWHRBfb37v+jLkrfCt0FJXQuALNH2UsW6+bdZBmoibHl0K778SiHwneotJbAaEvX2S05wEqUQw=="], + "@hey-api/codegen-core": ["@hey-api/codegen-core@0.8.1", "", { "dependencies": { "@hey-api/types": "0.1.4", "ansi-colors": "4.1.3", "c12": "3.3.4", "color-support": "1.1.3" } }, "sha512-Iciv2vUCJTW9lWM/ROvyZLblmcbYJHPuXfzb1SzeDVVn4xEXu2ilLU1pq3fn+09FZ/Y0P7VyvRE47UDU6om8xA=="], - "@hey-api/json-schema-ref-parser": ["@hey-api/json-schema-ref-parser@1.4.0", "", { "dependencies": { "@jsdevtools/ono": "7.1.3", "@types/json-schema": "7.0.15", "yaml": "2.8.3" } }, "sha512-o7X03OSoQgSqMB9DkI8cx/8MizGzeFYhIUnWuASdBOFWTgJhkStdazi1P7Vd5GXFkOx8d2yX/eErEzrQddi2GA=="], + "@hey-api/json-schema-ref-parser": ["@hey-api/json-schema-ref-parser@1.4.1", "", { "dependencies": { "@jsdevtools/ono": "7.1.3", "@types/json-schema": "7.0.15", "yaml": "2.8.3" } }, "sha512-DoPJGxVApDlktP1yYLjmOrF0YBEqb32ieCbx1S1i09n8TyCgdoh4yQaQ3kp0sMTauH+bwNKPsFh7S8qiWCoKZA=="], - "@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.96.0", "", { "dependencies": { "@hey-api/codegen-core": "0.8.0", "@hey-api/json-schema-ref-parser": "1.4.0", "@hey-api/shared": "0.4.0", "@hey-api/spec-types": "0.2.0", "@hey-api/types": "0.1.4", "ansi-colors": "4.1.3", "color-support": "1.1.3", "commander": "14.0.3", "get-tsconfig": "4.13.7" }, "peerDependencies": { "typescript": ">=5.5.3 || >=6.0.0 || 6.0.1-rc" }, "bin": { "openapi-ts": "bin/run.js" } }, "sha512-KVEHhw02+wDokvMCmHn4PA230PEd8+gF8NGdUeX0Ucxdex9ws18GBP3JqxrDyxhqO2q0o7XJA0E1T7zsJVguKg=="], + "@hey-api/openapi-ts": ["@hey-api/openapi-ts@0.97.0", "", { "dependencies": { "@hey-api/codegen-core": "0.8.1", "@hey-api/json-schema-ref-parser": "1.4.1", "@hey-api/shared": "0.4.2", "@hey-api/spec-types": "0.2.0", "@hey-api/types": "0.1.4", "@lukeed/ms": "2.0.2", "ansi-colors": "4.1.3", "color-support": "1.1.3", "commander": "14.0.3", "get-tsconfig": "4.14.0" }, "peerDependencies": { "typescript": ">=5.5.3 || >=6.0.0 || 6.0.1-rc" }, "bin": { "openapi-ts": "bin/run.js" } }, "sha512-WZkKgrDlZpxKlDv2HkBCzaAYeuM+EtZKFmKGBv9/JblAKpX3JQTROi7PzlCZE3eisetRPSakbcRgn+LGyB7EiQ=="], - "@hey-api/shared": ["@hey-api/shared@0.4.0", "", { "dependencies": { "@hey-api/codegen-core": "0.8.0", "@hey-api/json-schema-ref-parser": "1.4.0", "@hey-api/spec-types": "0.2.0", "@hey-api/types": "0.1.4", "ansi-colors": "4.1.3", "cross-spawn": "7.0.6", "open": "11.0.0", "semver": "7.7.4" } }, "sha512-kTAH703vFnS/W/U0DqdEh+2hXTNbq3JSrKG3jb1Es7kcV/N5vej2xMstHWHTYazn5q+UGkDa/BLJxBzS6bda8A=="], + "@hey-api/shared": ["@hey-api/shared@0.4.2", "", { "dependencies": { "@hey-api/codegen-core": "0.8.1", "@hey-api/json-schema-ref-parser": "1.4.1", "@hey-api/spec-types": "0.2.0", "@hey-api/types": "0.1.4", "ansi-colors": "4.1.3", "cross-spawn": "7.0.6", "open": "11.0.0", "semver": "7.7.4" } }, "sha512-4fconS10E0Xr4/acV8G+BkApxaIStxrT0GhB9BDTQWvrFTy5/nV933SyFk8qImcbpKvgv9hpn3N+7bV8oFrbjA=="], "@hey-api/spec-types": ["@hey-api/spec-types@0.2.0", "", { "dependencies": { "@hey-api/types": "0.1.4" } }, "sha512-ibQ8Is7evMavzr8GNyJCcTg975d8DpaMUyLmOrQ85UBdy1l6t1KuRAwgChAbesJsIlNV6gjmlXruWyegDX18Fg=="], @@ -600,6 +600,8 @@ "@libsql/win32-x64-msvc": ["@libsql/win32-x64-msvc@0.5.28", "", { "os": "win32", "cpu": "x64" }, "sha512-KLB4TQKkRdki9Ugbz+X986a1F7IaZUZbPuTfPNFi7slTT+biSw0b/LPJ0tCk7EHyo5QmN8tZ1XLZwI7GgUBsfA=="], + "@lukeed/ms": ["@lukeed/ms@2.0.2", "", {}, "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA=="], + "@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="], "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], @@ -1206,7 +1208,7 @@ "@tanstack/history": ["@tanstack/history@1.161.6", "", {}, "sha512-NaOGLRrddszbQj9upGat6HG/4TKvXLvu+osAIgfxPYA+eIvYKv8GKDJOrY2D3/U9MRnKfMWD7bU4jeD4xmqyIg=="], - "@tanstack/hotkeys": ["@tanstack/hotkeys@0.7.1", "", { "dependencies": { "@tanstack/store": "^0.9.3" } }, "sha512-YHVO1z6wnvUCu7bg870Kv5k2D+FIuIOSIcbN0dAmTTsJ3mLMDLwcTVx0qVaq+SZp1B514JJTqGVstvUp85yIpQ=="], + "@tanstack/hotkeys": ["@tanstack/hotkeys@0.8.0", "", { "dependencies": { "@tanstack/store": "^0.11.0" } }, "sha512-vqH7X9nb0MTJ/O08++dB5bP9jgj4+BIPOUu/U+6myG86lDsirZSVSobpq5UQpE7nBuk62i8eIYeOhd+OMl/UrA=="], "@tanstack/query-core": ["@tanstack/query-core@5.91.2", "", {}, "sha512-Uz2pTgPC1mhqrrSGg18RKCWT/pkduAYtxbcyIyKBhw7dTWjXZIzqmpzO2lBkyWr4hlImQgpu1m1pei3UnkFRWw=="], @@ -1214,7 +1216,7 @@ "@tanstack/react-devtools": ["@tanstack/react-devtools@0.10.2", "", { "dependencies": { "@tanstack/devtools": "0.11.2" }, "peerDependencies": { "@types/react": ">=16.8", "@types/react-dom": ">=16.8", "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-1BmZyxOrI5SqmRJ5MgkYZNNdnlLsJxQRI2YgorrAvcF2MxK6x5RcuStvD8+YlXoMw3JtNukPxoITirKAnKYDQA=="], - "@tanstack/react-hotkeys": ["@tanstack/react-hotkeys@0.9.1", "", { "dependencies": { "@tanstack/hotkeys": "0.7.1", "@tanstack/react-store": "^0.9.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-/qdQUUVkYAHAWRGdFXqFgWpW/S+a6OzkvxWNWKLLDHQODJlO6EPBPa073CglaafBfzig58RK07T09ET+NnZhpg=="], + "@tanstack/react-hotkeys": ["@tanstack/react-hotkeys@0.10.0", "", { "dependencies": { "@tanstack/hotkeys": "0.8.0", "@tanstack/react-store": "^0.11.0" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-GwOSndI5j3qBVYTmgP1mYyRTnlxb2MS17cwGlsavSxMQPSnmDf+m3LzMIpRMs+3zzQMjg3cYhHsFYizYlFI2tw=="], "@tanstack/react-query": ["@tanstack/react-query@5.91.3", "", { "dependencies": { "@tanstack/query-core": "5.91.2" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-D8jsCexxS5crZxAeiH6VlLHOUzmHOxeW5c11y8rZu0c34u/cy18hUKQXA/gn1Ila3ZIFzP+Pzv76YnliC0EtZQ=="], @@ -1232,7 +1234,7 @@ "@tanstack/react-start-server": ["@tanstack/react-start-server@1.166.16", "", { "dependencies": { "@tanstack/history": "1.161.6", "@tanstack/react-router": "1.168.1", "@tanstack/router-core": "1.168.1", "@tanstack/start-client-core": "1.167.1", "@tanstack/start-server-core": "1.167.1" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-YEuM5XSxNQhLr30e6uyep7m5yZHtZwCeEeQVyo7CSWKmUpkBtN60+bg4T2/nLY0MXrwo6DTK1Crsu80ZZLkPAA=="], - "@tanstack/react-store": ["@tanstack/react-store@0.9.3", "", { "dependencies": { "@tanstack/store": "0.9.3", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg=="], + "@tanstack/react-store": ["@tanstack/react-store@0.11.0", "", { "dependencies": { "@tanstack/store": "0.11.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-tX4YXh3PDkmpvGQWkWqKpzs/MSqbtuwY9dWdWhtV9Q50PmO+jOkUKIWIX4G85dwt7lxdHLXsiaEKPdKmC8F41w=="], "@tanstack/router-core": ["@tanstack/router-core@1.168.1", "", { "dependencies": { "@tanstack/history": "1.161.6", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "bin": { "intent": "bin/intent.js" } }, "sha512-RtpshTLZsMOkwW7rI52WFWGZSSfMAyDR1zWP9kVm91UX28gedc+LXih1CTP6TchS+TvxK4q8oW7ApMTvnpiY1w=="], @@ -1256,7 +1258,7 @@ "@tanstack/start-storage-context": ["@tanstack/start-storage-context@1.166.15", "", { "dependencies": { "@tanstack/router-core": "1.168.1" } }, "sha512-mGDNfJo/eFtwgFFBrJ85rNdIBNTroE3zy5zbwHZ/FV0HPYOawnev7KscDjKBuVxBGY2jl0fQLrRNUO/Sjqy3cg=="], - "@tanstack/store": ["@tanstack/store@0.9.3", "", {}, "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw=="], + "@tanstack/store": ["@tanstack/store@0.11.0", "", {}, "sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw=="], "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.161.7", "", { "bin": { "intent": "bin/intent.js" } }, "sha512-olW33+Cn+bsCsZKPwEGhlkqS6w3M2slFv11JIobdnCFKMLG97oAI2kWKdx5/zsywTL8flpnoIgaZZPlQTFYhdQ=="], @@ -1864,7 +1866,7 @@ "get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="], - "get-tsconfig": ["get-tsconfig@4.13.7", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q=="], + "get-tsconfig": ["get-tsconfig@4.14.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA=="], "giget": ["giget@3.2.0", "", { "bin": { "giget": "dist/cli.mjs" } }, "sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A=="], diff --git a/package.json b/package.json index 377d402e..1605598e 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.2.8", "@scalar/hono-api-reference": "^0.10.4", - "@tanstack/react-hotkeys": "^0.9.0", + "@tanstack/react-hotkeys": "^0.10.0", "@tanstack/react-query": "^5.91.3", "@tanstack/react-query-devtools": "^5.91.3", "@tanstack/react-router": "^1.168.1", @@ -98,7 +98,7 @@ "devDependencies": { "@effect/language-service": "^0.85.0", "@faker-js/faker": "^10.3.0", - "@hey-api/openapi-ts": "^0.96.0", + "@hey-api/openapi-ts": "^0.97.0", "@libsql/client": "^0.17.2", "@playwright/test": "^1.58.2", "@rolldown/plugin-babel": "^0.2.2", From 11e9fbcc441f135cf7e55454194e0c1af301464b Mon Sep 17 00:00:00 2001 From: Nico <47644445+nicotsx@users.noreply.github.com> Date: Wed, 29 Apr 2026 23:48:58 +0200 Subject: [PATCH 002/113] feat: pre/post backup webhooks (#835) * feat: pre/post backup webhooks * fix(hooks): run post when cancelled * refactor(webhooks): headers as array * refactor: pr feedback * refactor: simplify hooks ceremonies * chore: pr feedbacks * chore: re-gen migration --- app/client/api-client/types.gen.ts | 84 + .../components/webhook-request-preview.tsx | 25 + .../create-schedule-form/advanced-section.tsx | 82 +- .../components/create-schedule-form/index.tsx | 16 +- .../components/create-schedule-form/types.ts | 33 +- .../components/create-schedule-form/utils.ts | 36 +- .../routes/__tests__/backup-details.test.tsx | 1 + .../routes/__tests__/edit-backup.test.tsx | 26 + .../modules/backups/routes/backup-details.tsx | 1 + .../modules/backups/routes/create-backup.tsx | 1 + .../notification-forms/generic-form.tsx | 19 +- .../migration.sql | 1 + .../snapshot.json | 2341 +++++++++++++++++ app/server/db/schema.ts | 2 + .../modules/agents/__tests__/session.test.ts | 1 + .../backups.service.execution.test.ts | 35 + .../backups/__tests__/backups.service.test.ts | 56 + app/server/modules/backups/backup-executor.ts | 52 +- .../modules/backups/backups.controller.ts | 9 +- app/server/modules/backups/backups.dto.ts | 10 +- app/server/modules/backups/backups.service.ts | 9 +- .../backups/helpers/backup-lifecycle.ts | 2 +- .../src/__tests__/controller-session.test.ts | 1 + apps/agent/src/commands/backup-run.test.ts | 258 +- apps/agent/src/commands/backup-run.ts | 113 +- packages/contracts/src/agent-protocol.ts | 2 + packages/core/package.json | 5 + .../src/backup-hooks/__tests__/hooks.test.ts | 383 +++ packages/core/src/backup-hooks/index.ts | 280 ++ 29 files changed, 3762 insertions(+), 122 deletions(-) create mode 100644 app/client/components/webhook-request-preview.tsx create mode 100644 app/drizzle/20260429214453_classy_namora/migration.sql create mode 100644 app/drizzle/20260429214453_classy_namora/snapshot.json create mode 100644 packages/core/src/backup-hooks/__tests__/hooks.test.ts create mode 100644 packages/core/src/backup-hooks/index.ts diff --git a/app/client/api-client/types.gen.ts b/app/client/api-client/types.gen.ts index ddf355f3..e6e5f670 100644 --- a/app/client/api-client/types.gen.ts +++ b/app/client/api-client/types.gen.ts @@ -2434,6 +2434,18 @@ export type ListBackupSchedulesResponses = { includePatterns: Array | null; oneFileSystem: boolean; customResticParams: Array | null; + backupWebhooks: { + pre: { + url: string; + headers?: Array; + body?: string; + } | null; + post: { + url: string; + headers?: Array; + body?: string; + } | null; + } | null; maxRetries: number; retryDelay: number; lastBackupAt: number | null; @@ -2712,6 +2724,18 @@ export type CreateBackupScheduleData = { oneFileSystem?: boolean; tags?: Array; customResticParams?: Array; + backupWebhooks?: { + pre: { + url: string; + headers?: Array; + body?: string; + } | null; + post: { + url: string; + headers?: Array; + body?: string; + } | null; + } | null; maxRetries?: number; retryDelay?: number; }; @@ -2747,6 +2771,18 @@ export type CreateBackupScheduleResponses = { includePatterns: Array | null; oneFileSystem: boolean; customResticParams: Array | null; + backupWebhooks: { + pre: { + url: string; + headers?: Array; + body?: string; + } | null; + post: { + url: string; + headers?: Array; + body?: string; + } | null; + } | null; maxRetries: number; retryDelay: number; lastBackupAt: number | null; @@ -2816,6 +2852,18 @@ export type GetBackupScheduleResponses = { includePatterns: Array | null; oneFileSystem: boolean; customResticParams: Array | null; + backupWebhooks: { + pre: { + url: string; + headers?: Array; + body?: string; + } | null; + post: { + url: string; + headers?: Array; + body?: string; + } | null; + } | null; maxRetries: number; retryDelay: number; lastBackupAt: number | null; @@ -3093,6 +3141,18 @@ export type UpdateBackupScheduleData = { oneFileSystem?: boolean; tags?: Array; customResticParams?: Array; + backupWebhooks?: { + pre: { + url: string; + headers?: Array; + body?: string; + } | null; + post: { + url: string; + headers?: Array; + body?: string; + } | null; + } | null; maxRetries?: number; retryDelay?: number; }; @@ -3130,6 +3190,18 @@ export type UpdateBackupScheduleResponses = { includePatterns: Array | null; oneFileSystem: boolean; customResticParams: Array | null; + backupWebhooks: { + pre: { + url: string; + headers?: Array; + body?: string; + } | null; + post: { + url: string; + headers?: Array; + body?: string; + } | null; + } | null; maxRetries: number; retryDelay: number; lastBackupAt: number | null; @@ -3179,6 +3251,18 @@ export type GetBackupScheduleForVolumeResponses = { includePatterns: Array | null; oneFileSystem: boolean; customResticParams: Array | null; + backupWebhooks: { + pre: { + url: string; + headers?: Array; + body?: string; + } | null; + post: { + url: string; + headers?: Array; + body?: string; + } | null; + } | null; maxRetries: number; retryDelay: number; lastBackupAt: number | null; diff --git a/app/client/components/webhook-request-preview.tsx b/app/client/components/webhook-request-preview.tsx new file mode 100644 index 00000000..1b1c132f --- /dev/null +++ b/app/client/components/webhook-request-preview.tsx @@ -0,0 +1,25 @@ +import { CodeBlock } from "~/client/components/ui/code-block"; +import { Label } from "~/client/components/ui/label"; + +type WebhookRequestPreviewProps = { + method: string; + url?: string; + contentType?: string; + headers?: string[]; + body: string; +}; + +export const WebhookRequestPreview = ({ method, url, contentType, headers, body }: WebhookRequestPreviewProps) => { + const headerLines = [contentType ? `Content-Type: ${contentType}` : undefined, ...(headers ?? [])].filter(Boolean); + const previewCode = `${method} ${url || "https://api.example.com/webhook"}${headerLines.length > 0 ? `\n${headerLines.join("\n")}` : ""} + +${body}`; + + return ( +
+ + +

This is a preview of the HTTP request that will be sent.

+
+ ); +}; diff --git a/app/client/modules/backups/components/create-schedule-form/advanced-section.tsx b/app/client/modules/backups/components/create-schedule-form/advanced-section.tsx index a6d865a3..0b6c3d33 100644 --- a/app/client/modules/backups/components/create-schedule-form/advanced-section.tsx +++ b/app/client/modules/backups/components/create-schedule-form/advanced-section.tsx @@ -1,6 +1,6 @@ import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "~/client/components/ui/form"; import { Textarea } from "~/client/components/ui/textarea"; -import type { UseFormReturn } from "react-hook-form"; +import { type UseFormReturn } from "react-hook-form"; import type { InternalFormValues } from "./types"; import { Input } from "~/client/components/ui/input"; @@ -8,6 +8,72 @@ type AdvancedSectionProps = { form: UseFormReturn; }; +type WebhookFieldsProps = { + form: UseFormReturn; + phase: "pre" | "post"; + urlPlaceholder: string; + bodyPlaceholder: string; + description: string; +}; + +const WebhookFields = ({ form, phase, urlPlaceholder, bodyPlaceholder, description }: WebhookFieldsProps) => { + const labelPrefix = phase === "pre" ? "Pre-backup" : "Post-backup"; + const fieldPrefix = phase === "pre" ? "preBackupWebhook" : "postBackupWebhook"; + + return ( + <> + ( + + {labelPrefix} webhook + + + + {description} + + + )} + /> + ( + + {labelPrefix} webhook headers + +