mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21b9b8b44d | ||
|
|
6ef7fcc0c2 | ||
|
|
fc4ce178cb | ||
|
|
98b72988c4 | ||
|
|
317473e528 | ||
|
|
e13c5ddf51 | ||
|
|
90be3ab731 | ||
|
|
85c0445a64 | ||
|
|
6a227ccd7c | ||
|
|
3d9a21f854 | ||
|
|
d4229a985d | ||
|
|
c6e0921dea | ||
|
|
346a8a4375 | ||
|
|
4799faa827 | ||
|
|
2c6f5c38ed |
@@ -72,7 +72,7 @@ If you encounter a bug or have a suggestion for improvement, follow these steps:
|
||||
|
||||
3. **Push your branch**
|
||||
```bash
|
||||
git push origin feature/<feature-name>
|
||||
git push origin feat/<feature-name>
|
||||
```
|
||||
|
||||
4. **Open a Pull Request (PR)**
|
||||
@@ -82,7 +82,7 @@ If you encounter a bug or have a suggestion for improvement, follow these steps:
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
- Follow the [specific coding style guide] (e.g., Prettier, ESLint, PEP8).
|
||||
- Follow the [specific coding style guide] (e.g., Prettier, ESLint, PEP8,Biome).
|
||||
- Use meaningful variable names and include comments where necessary.
|
||||
- Tests before submitting your changes.
|
||||
|
||||
@@ -107,4 +107,4 @@ If you encounter a bug or have a suggestion for improvement, follow these steps:
|
||||
|
||||
Thank you for contributing! 🙌
|
||||
|
||||
---
|
||||
---
|
||||
|
||||
@@ -24,6 +24,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
ref: ${{ github.base_ref }}
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
|
||||
@@ -38,6 +39,8 @@ jobs:
|
||||
- run: git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
|
||||
- name: Run release-it
|
||||
run: pnpm exec release-it --ci
|
||||
run: |
|
||||
git pull origin main
|
||||
pnpm exec release-it --ci
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
@@ -7,22 +7,41 @@ on:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
dry-run:
|
||||
name: Dry run
|
||||
validate-code:
|
||||
name: Code Integrity Check
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Build image
|
||||
uses: docker/build-push-action@v6
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/dockerfile/Dockerfile
|
||||
push: false
|
||||
tags: portabase/portabase:pr-${{ github.event.number }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
node-version: "lts/*"
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Check code formatting
|
||||
run: pnpm run format:check
|
||||
continue-on-error: true
|
||||
|
||||
- name: Run Linter
|
||||
run: pnpm run lint
|
||||
continue-on-error: true
|
||||
|
||||
- name: Type Check
|
||||
run: pnpm run typecheck
|
||||
continue-on-error: true
|
||||
|
||||
- name: Run Tests
|
||||
run: pnpm run test
|
||||
continue-on-error: true
|
||||
|
||||
- name: Test Application Build
|
||||
run: pnpm run build
|
||||
|
||||
+36
-12
@@ -13,20 +13,44 @@
|
||||
},
|
||||
"plugins": {
|
||||
"@release-it/conventional-changelog": {
|
||||
"preset": "angular"
|
||||
"preset": {
|
||||
"name": "conventionalcommits",
|
||||
"types": [
|
||||
{
|
||||
"type": "feat",
|
||||
"section": "✨ Features"
|
||||
},
|
||||
{
|
||||
"type": "fix",
|
||||
"section": "🐛 Bug Fixes"
|
||||
},
|
||||
{
|
||||
"type": "perf",
|
||||
"section": "⚡️ Performance Improvements"
|
||||
},
|
||||
{
|
||||
"type": "revert",
|
||||
"section": "⏪️ Reverts"
|
||||
},
|
||||
{
|
||||
"type": "docs",
|
||||
"section": "📝 Documentation",
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"type": "chore",
|
||||
"section": "🔧 Chores",
|
||||
"hidden": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"@release-it/bumper": {
|
||||
"files": ["package.json", "CITATION.cff"],
|
||||
"bumpFiles": [
|
||||
{
|
||||
"file": "CITATION.cff",
|
||||
"versionRegExp": "version:\\s*\"([0-9]+\\.[0-9]+\\.[0-9]+)\""
|
||||
},
|
||||
{
|
||||
"file": "package.json",
|
||||
"versionRegExp": "\"version\":\\s*\"([0-9]+\\.[0-9]+\\.[0-9]+)\""
|
||||
}
|
||||
]
|
||||
"out": {
|
||||
"file": "CITATION.cff",
|
||||
"path": "version",
|
||||
"type": "text/yaml"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-4
@@ -1,6 +1,6 @@
|
||||
cff-version: 1.2.0
|
||||
title: Portabase
|
||||
message: "If you use this software, please cite it as below."
|
||||
message: If you use this software, please cite it as below.
|
||||
type: software
|
||||
authors:
|
||||
- family-names: Gauthereau
|
||||
@@ -9,7 +9,12 @@ authors:
|
||||
given-names: Killian
|
||||
repository-code: https://github.com/Portabase/portabase
|
||||
url: https://portabase.io
|
||||
abstract: "Portabase is a free, open-source, self-hosted solution for database administration, providing backup and restore capabilities, scheduling, retention policies, notifications, and support for multiple storage backends. Its headless agent architecture enables connection to multiple database instances securely and efficiently."
|
||||
abstract: >-
|
||||
Portabase is a free, open-source, self-hosted solution for database
|
||||
administration, providing backup and restore capabilities, scheduling,
|
||||
retention policies, notifications, and support for multiple storage backends.
|
||||
Its headless agent architecture enables connection to multiple database
|
||||
instances securely and efficiently.
|
||||
keywords:
|
||||
- docker
|
||||
- kubernetes
|
||||
@@ -26,5 +31,5 @@ keywords:
|
||||
- web-ui
|
||||
- agent
|
||||
license: Apache-2.0
|
||||
version: 1.4.3
|
||||
date-released: "2026-03-02"
|
||||
version: 1.4.13
|
||||
date-released: '2026-03-02'
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "portabase",
|
||||
"version": "1.4.6",
|
||||
"version": "1.4.13",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack -p 8887",
|
||||
|
||||
+35
-27
@@ -1,30 +1,38 @@
|
||||
import {UseFormReturn} from "react-hook-form";
|
||||
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Separator} from "@/components/ui/separator";
|
||||
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { PasswordInput } from "@/components/ui/password-input";
|
||||
|
||||
type NotifierDiscordFormProps = {
|
||||
form: UseFormReturn<any, any, any>
|
||||
}
|
||||
form: UseFormReturn<any, any, any>;
|
||||
};
|
||||
|
||||
export const NotifierDiscordForm = ({form}: NotifierDiscordFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1"/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.discordWebhook"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Discord Webhook URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="https://discord.com/api/webhooks/..."/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export const NotifierDiscordForm = ({ form }: NotifierDiscordFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1" />
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.discordWebhook"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Discord Webhook URL</FormLabel>
|
||||
<FormControl>
|
||||
<PasswordInput
|
||||
{...field}
|
||||
placeholder="https://discord.com/api/webhooks/..."
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+46
-40
@@ -1,43 +1,49 @@
|
||||
import {UseFormReturn} from "react-hook-form";
|
||||
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Separator} from "@/components/ui/separator";
|
||||
|
||||
import type { UseFormReturn } from "react-hook-form";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { PasswordInput } from "@/components/ui/password-input";
|
||||
|
||||
type NotifierGotifyFormProps = {
|
||||
form: UseFormReturn<any, any, any>
|
||||
}
|
||||
form: UseFormReturn<any, any, any>;
|
||||
};
|
||||
|
||||
export const NotifierGotifyForm = ({form}: NotifierGotifyFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1"/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.gotifyServerUrl"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Gotify Server URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="https://gotify.example.com"/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.gotifyAppToken"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Application Token</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="A1b2C3d4E5f6G7h"/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export const NotifierGotifyForm = ({ form }: NotifierGotifyFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1" />
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.gotifyServerUrl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Gotify Server URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="https://gotify.example.com" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.gotifyAppToken"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Application Token</FormLabel>
|
||||
<FormControl>
|
||||
<PasswordInput {...field} placeholder="A1b2C3d4E5f6G7h" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ export const NotifierNtfyForm = ({form}: NotifierNtfyFormProps) => {
|
||||
<FormItem>
|
||||
<FormLabel>Access Token (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="tk_..."/>
|
||||
<PasswordInput {...field} placeholder="tk_..."/>
|
||||
</FormControl>
|
||||
<p className="text-xs text-muted-foreground">Only required for protected topics or self-hosted instances with auth.</p>
|
||||
<FormMessage/>
|
||||
|
||||
+35
-28
@@ -1,31 +1,38 @@
|
||||
|
||||
import {UseFormReturn} from "react-hook-form";
|
||||
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Separator} from "@/components/ui/separator";
|
||||
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { PasswordInput } from "@/components/ui/password-input";
|
||||
|
||||
type NotifierSmtpFormProps = {
|
||||
form: UseFormReturn<any, any, any>
|
||||
}
|
||||
form: UseFormReturn<any, any, any>;
|
||||
};
|
||||
|
||||
export const NotifierSlackForm = ({form}: NotifierSmtpFormProps) => {
|
||||
return(
|
||||
<>
|
||||
<Separator className="my-1"/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.slackWebhook"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Slack Webhook URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="https://hooks.slack.com/services/..."/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export const NotifierSlackForm = ({ form }: NotifierSmtpFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1" />
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.slackWebhook"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Slack Webhook URL</FormLabel>
|
||||
<FormControl>
|
||||
<PasswordInput
|
||||
{...field}
|
||||
placeholder="https://hooks.slack.com/services/..."
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+81
-61
@@ -1,64 +1,84 @@
|
||||
import {UseFormReturn} from "react-hook-form";
|
||||
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Separator} from "@/components/ui/separator";
|
||||
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { PasswordInput } from "@/components/ui/password-input";
|
||||
|
||||
type NotifierTelegramFormProps = {
|
||||
form: UseFormReturn<any, any, any>
|
||||
}
|
||||
form: UseFormReturn<any, any, any>;
|
||||
};
|
||||
|
||||
export const NotifierTelegramForm = ({form}: NotifierTelegramFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1"/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.telegramBotToken"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Telegram Bot Token</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.telegramChatId"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Telegram Chat ID</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="-100123456789 or 123456789"/>
|
||||
</FormControl>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
You must start the conversation with the bot first (<strong>/start</strong>). <br/>
|
||||
For groups, add the bot to the group. <br/>
|
||||
You can use <a href="https://t.me/userinfobot" target="_blank" rel="noopener noreferrer" className="underline">@userinfobot</a> to find your ID.
|
||||
</p>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.telegramTopicId"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Telegram Topic ID</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="123456"/>
|
||||
</FormControl>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
|
||||
</p>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export const NotifierTelegramForm = ({ form }: NotifierTelegramFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1" />
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.telegramBotToken"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Telegram Bot Token</FormLabel>
|
||||
<FormControl>
|
||||
<PasswordInput
|
||||
{...field}
|
||||
placeholder="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.telegramChatId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Telegram Chat ID</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="-100123456789 or 123456789" />
|
||||
</FormControl>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
You must start the conversation with the bot first (
|
||||
<strong>/start</strong>). <br />
|
||||
For groups, add the bot to the group. <br />
|
||||
You can use{" "}
|
||||
<a
|
||||
href="https://t.me/userinfobot"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline"
|
||||
>
|
||||
@userinfobot
|
||||
</a>{" "}
|
||||
to find your ID.
|
||||
</p>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.telegramTopicId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Telegram Topic ID</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="123456" />
|
||||
</FormControl>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Unique identifier for the target message thread (topic) of the
|
||||
forum; for forum supergroups only
|
||||
</p>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+69
-62
@@ -1,65 +1,72 @@
|
||||
import {UseFormReturn} from "react-hook-form";
|
||||
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Separator} from "@/components/ui/separator";
|
||||
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { PasswordInput } from "@/components/ui/password-input";
|
||||
|
||||
type NotifierWebhookFormProps = {
|
||||
form: UseFormReturn<any, any, any>
|
||||
}
|
||||
form: UseFormReturn<any, any, any>;
|
||||
};
|
||||
|
||||
export const NotifierWebhookForm = ({form}: NotifierWebhookFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1"/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.webhookUrl"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Webhook URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="https://example.com/api/webhook"/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.webhookSecretHeader"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Header Name (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="X-Webhook-Secret"/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.webhookSecret"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Secret Value (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Secret value..."/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground mt-2">
|
||||
If provided, the secret will be sent in the specified header (defaults to <code>X-Webhook-Secret</code>).
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export const NotifierWebhookForm = ({ form }: NotifierWebhookFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1" />
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.webhookUrl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Webhook URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="https://example.com/api/webhook" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.webhookSecretHeader"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Header Name (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="X-Webhook-Secret" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.webhookSecret"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Secret Value (Optional)</FormLabel>
|
||||
<FormControl>
|
||||
<PasswordInput {...field} placeholder="Secret value..." />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground mt-2">
|
||||
If provided, the secret will be sent in the specified header (defaults
|
||||
to <code>X-Webhook-Secret</code>).
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+112
-111
@@ -1,115 +1,116 @@
|
||||
import {UseFormReturn} from "react-hook-form";
|
||||
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Separator} from "@/components/ui/separator";
|
||||
import {PasswordInput} from "@/components/ui/password-input";
|
||||
import {Switch} from "@/components/ui/switch";
|
||||
|
||||
import { UseFormReturn } from "react-hook-form";
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { PasswordInput } from "@/components/ui/password-input";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
|
||||
type StorageS3FormProps = {
|
||||
form: UseFormReturn<any, any, any>
|
||||
}
|
||||
form: UseFormReturn<any, any, any>;
|
||||
};
|
||||
|
||||
export const StorageS3Form = ({form}: StorageS3FormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1"/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.endPointUrl"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Endpoint URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="s3.amazonaws.com"/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.region"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Region</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="us-east-1"/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.accessKey"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Access Key</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="A1b2C3d4E5f6G7h"/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.secretKey"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Secret Key</FormLabel>
|
||||
<FormControl>
|
||||
<PasswordInput {...field} placeholder="A1b2C3d4E5f6G7h"/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.bucketName"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bucket name</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="portabase-dev"/>
|
||||
</FormControl>
|
||||
<FormMessage/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.port"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Port</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="443" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
export const StorageS3Form = ({ form }: StorageS3FormProps) => {
|
||||
return (
|
||||
<>
|
||||
<Separator className="my-1" />
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.endPointUrl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Endpoint URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="s3.amazonaws.com" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.region"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Region</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="us-east-1" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.accessKey"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Access Key</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="A1b2C3d4E5f6G7h" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.secretKey"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Secret Key</FormLabel>
|
||||
<FormControl>
|
||||
<PasswordInput {...field} placeholder="A1b2C3d4E5f6G7h" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.bucketName"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bucket name</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="portabase-dev" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.port"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Port</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="number" placeholder="443" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.ssl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Use SSL</FormLabel>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="config.ssl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Use SSL</FormLabel>
|
||||
<FormControl>
|
||||
<Switch checked={field.value} onCheckedChange={field.onChange} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user