Compare commits

...
35 Commits
Author SHA1 Message Date
github-actions[bot] 21b9b8b44d chore: release v1.4.13 2026-03-04 12:37:48 +00:00
6ef7fcc0c2 fix: Feat/changelog icon (#137)
* Update .release-it.json

* Update .release-it.json

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 13:37:19 +01:00
fc4ce178cb fix: Update .release-it.json (#136)
Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 13:33:58 +01:00
github-actions[bot] 98b72988c4 chore: release v1.4.12 2026-03-04 12:30:32 +00:00
317473e528 fix: Update CONTRIBUTING.md (#135)
Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 13:30:04 +01:00
github-actions[bot] e13c5ddf51 chore: release v1.4.11 2026-03-04 12:24:36 +00:00
90be3ab731 fix: password input on sensible fields (#134)
Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 13:24:10 +01:00
github-actions[bot] 85c0445a64 chore: release v1.4.10 2026-03-04 12:02:54 +00:00
6a227ccd7c fix: Feat/flow (#133)
* fix

* fix

* fix

* fix

* Update docker.yml

* Update auto-release.yml

* Update pr-checker.yml

* Update pr-checker.yml

* fix: citation version

* Update .release-it.json

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 13:02:24 +01:00
github-actions[bot] 3d9a21f854 chore: release v1.4.9 2026-03-04 11:58:24 +00:00
d4229a985d fix: Feat/flow (#132)
* fix

* fix

* fix

* fix

* Update docker.yml

* Update auto-release.yml

* Update pr-checker.yml

* Update pr-checker.yml

* fix: citation version

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 12:57:56 +01:00
github-actions[bot] c6e0921dea chore: release v1.4.8 2026-03-04 10:57:55 +00:00
346a8a4375 fix: Feat/flow (#131)
* fix

* fix

* fix

* fix

* Update docker.yml

* Update auto-release.yml

* Update pr-checker.yml

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 11:57:11 +01:00
github-actions[bot] 4799faa827 chore: release v1.4.7 2026-03-04 10:34:00 +00:00
2c6f5c38ed fix: Feat/flow (#130)
* fix

* fix

* fix

* fix

* Update docker.yml

* Update auto-release.yml

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 11:33:25 +01:00
github-actions[bot] 4a884ab5cc chore: release v1.4.6 2026-03-04 10:27:05 +00:00
e59beaf749 fix: feat/flow (#129)
* fix

* fix

* fix

* fix

* Update docker.yml

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 11:26:28 +01:00
github-actions[bot] 0d4e1229ab chore: release v1.4.5 2026-03-04 10:23:35 +00:00
8810fd91c9 fix: Feat/flow (#128)
* fix

* fix

* fix

* fix

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 11:22:51 +01:00
github-actions[bot] 7cf43c5e7c chore: release v1.4.4 2026-03-04 09:29:30 +00:00
77183af08d fix: Feat/flow (#127)
* fix

* fix

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 10:23:52 +01:00
3a2c5be5dd fix: bug
Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 10:21:02 +01:00
Théo LAGACHE 11c764c2f3 fix 2026-03-04 10:17:37 +01:00
d128234ae6 fix: Feat/workflow (#125)
* update: release

* fix

* fix

* fix

* Update docker.yml

* fix

* Update auto-release.yml

* Update auto-release.yml

* add: bumper

* Update auto-release.yml

* Update auto-release.yml

* fix

* Update auto-release.yml

* fix

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 09:46:47 +01:00
Théo LAGACHE ee31ee225d fix 2026-03-04 09:44:30 +01:00
e2195616d3 fix: Feat/workflow (#124)
* update: release

* fix

* fix

* fix

* Update docker.yml

* fix

* Update auto-release.yml

* Update auto-release.yml

* add: bumper

* Update auto-release.yml

* Update auto-release.yml

* fix

* Update auto-release.yml

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 09:34:32 +01:00
Théo LAGACHE 2ca818b996 Update auto-release.yml 2026-03-04 09:33:51 +01:00
131f2b4538 fix Feat/workflow (#123)
* update: release

* fix

* fix

* fix

* Update docker.yml

* fix

* Update auto-release.yml

* Update auto-release.yml

* add: bumper

* Update auto-release.yml

* Update auto-release.yml

* fix

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 09:30:26 +01:00
6731c3fea9 fix: Feat/new workflow (#122)
* update: release

* fix

* fix

* fix

* Update docker.yml

* fix

* Update auto-release.yml

* Update auto-release.yml

* add: bumper

* Update auto-release.yml

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 09:27:00 +01:00
d3da5e8c13 fix: Feat/new workflow (#121)
* update: release

* fix

* fix

* fix

* Update docker.yml

* fix

* Update auto-release.yml

* Update auto-release.yml

* add: bumper

* Update auto-release.yml

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-04 09:20:10 +01:00
3b0d4225ce fix: Feat/new workflow (#118)
* update: release

* fix

* fix

* fix

* Update docker.yml

* fix

* Update auto-release.yml

* Update auto-release.yml

* add: bumper

* Update auto-release.yml

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-03 17:00:01 +01:00
66f0930164 fix: Feat/new workflow (#117)
* update: release

* fix

* fix

* fix

* Update docker.yml

* fix

* Update auto-release.yml

* Update auto-release.yml

* add: bumper

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-03 16:50:36 +01:00
3979b83a0a fix: Feat/new workflow (#116)
* update: release

* fix

* fix

* fix

* Update docker.yml

* fix

* Update auto-release.yml

* Update auto-release.yml

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-03 16:47:59 +01:00
b65e432564 fix: Feat/new workflow (#115)
* update: release

* fix

* fix

* fix

* Update docker.yml

* fix

* Update auto-release.yml

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-03 16:45:31 +01:00
340e7c3e00 fix: new workflow CI (#114)
* update: release

* fix

* fix

* fix

* Update docker.yml

* fix

---------

Co-authored-by: Théo LAGACHE <theo.lagache@soluce-technologies.com>
2026-03-03 16:39:59 +01:00
22 changed files with 2109 additions and 906 deletions
+3 -3
View File
@@ -72,7 +72,7 @@ If you encounter a bug or have a suggestion for improvement, follow these steps:
3. **Push your branch** 3. **Push your branch**
```bash ```bash
git push origin feature/<feature-name> git push origin feat/<feature-name>
``` ```
4. **Open a Pull Request (PR)** 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 ## 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. - Use meaningful variable names and include comments where necessary.
- Tests before submitting your changes. - 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! 🙌 Thank you for contributing! 🙌
--- ---
+46
View File
@@ -0,0 +1,46 @@
name: Auto Release bot
on:
pull_request:
types: [closed]
branches:
- main
jobs:
release:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
ref: ${{ github.base_ref }}
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
cache: "pnpm"
- run: pnpm install --frozen-lockfile
- run: git config --global user.name 'github-actions[bot]'
- run: git config --global user.email 'github-actions[bot]@users.noreply.github.com'
- name: Run release-it
run: |
git pull origin main
pnpm exec release-it --ci
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
@@ -1,16 +1,8 @@
name: GitHub Release name: Discord Notification
on: on:
workflow_call: workflow_call:
inputs: inputs:
prerelease:
required: false
type: boolean
default: false
make_latest:
required: false
type: boolean
default: false
discord_title: discord_title:
required: true required: true
type: string type: string
@@ -27,74 +19,24 @@ on:
required: true required: true
jobs: jobs:
create-release: notify-discord:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: write
steps: steps:
- name: Check out the repo
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build Changelog
id: build_changelog
uses: mikepenz/release-changelog-builder-action@v5
with:
mode: "COMMIT"
configurationJson: |
{
"template": "#{{CHANGELOG}}",
"categories": [
{
"title": "## Feature",
"labels": ["feat", "feature"]
},
{
"title": "## Fix",
"labels": ["fix", "bug"]
},
{
"title": "## Other",
"labels": []
}
],
"label_extractor": [
{
"pattern": "^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test){1}(\([\w\-\.]+\))?(!)?: ([\w ])+([\s\S]*)",
"on_property": "title",
"target": "$1"
}
]
}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: false
body: ${{ steps.build_changelog.outputs.changelog }}
prerelease: ${{ inputs.prerelease }}
make_latest: ${{ inputs.make_latest }}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
- name: Send Discord Notification - name: Send Discord Notification
env: env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
GH_TOKEN: ${{ secrets.GH_TOKEN }} GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: | run: |
RELEASE_INFO=$(gh release view "${{ github.ref_name }}" -R ${{ github.repository }} --json name,url,body,author) RELEASE_INFO=$(gh release view "${{ github.ref_name }}" -R ${{ github.repository }} --json name,url,body,author)
RELEASE_TITLE=$(echo "$RELEASE_INFO" | jq -r .name) RELEASE_TITLE=$(echo "$RELEASE_INFO" | jq -r .name)
if [ -z "$RELEASE_TITLE" ] || [ "$RELEASE_TITLE" = "null" ]; then RELEASE_TITLE="${{ github.ref_name }}"; fi if [ -z "$RELEASE_TITLE" ] || [ "$RELEASE_TITLE" = "null" ]; then RELEASE_TITLE="${{ github.ref_name }}"; fi
RELEASE_URL=$(echo "$RELEASE_INFO" | jq -r .url) RELEASE_URL=$(echo "$RELEASE_INFO" | jq -r .url)
RELEASE_BODY=$(echo "$RELEASE_INFO" | jq -r .body) RELEASE_BODY=$(echo "$RELEASE_INFO" | jq -r .body)
AUTHOR_NAME="Portabase" AUTHOR_NAME="Portabase"
AUTHOR_ICON="https://github.com/Portabase.png" AUTHOR_ICON="https://github.com/Portabase.png"
PAYLOAD=$(jq -n \ PAYLOAD=$(jq -n \
--arg title "$RELEASE_TITLE" \ --arg title "$RELEASE_TITLE" \
@@ -105,7 +47,7 @@ jobs:
--arg discord_title "${{ inputs.discord_title }}" \ --arg discord_title "${{ inputs.discord_title }}" \
--arg discord_footer "${{ inputs.discord_footer }}" \ --arg discord_footer "${{ inputs.discord_footer }}" \
--argjson discord_color ${{ inputs.discord_color }} \ --argjson discord_color ${{ inputs.discord_color }} \
'{ '{
content: $discord_title, content: $discord_title,
embeds: [{ embeds: [{
title: $title, title: $title,
@@ -121,8 +63,8 @@ jobs:
} }
}] }]
}' }'
) )
curl -H "Content-Type: application/json" \ curl -H "Content-Type: application/json" \
-d "$PAYLOAD" \ -d "$PAYLOAD" \
"$DISCORD_WEBHOOK" "$DISCORD_WEBHOOK"
+40 -48
View File
@@ -6,7 +6,7 @@ on:
image_name: image_name:
required: false required: false
type: string type: string
default: 'portabase/portabase' default: "portabase/portabase"
add_latest: add_latest:
required: false required: false
type: boolean type: boolean
@@ -14,11 +14,11 @@ on:
target: target:
required: false required: false
type: string type: string
default: 'prod' default: "prod"
dockerfile: dockerfile:
required: false required: false
type: string type: string
default: './docker/dockerfile/Dockerfile' default: "./docker/dockerfile/Dockerfile"
secrets: secrets:
DOCKER_USERNAME: DOCKER_USERNAME:
required: true required: true
@@ -26,34 +26,32 @@ on:
required: true required: true
jobs: jobs:
build: build:
name: Build and push Docker images name: Build architectures
runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || matrix.platform == 'linux/arm64' && 'ubuntu-24.04-arm' }} runs-on: ${{ matrix.platform == 'linux/amd64' && 'ubuntu-latest' || 'ubuntu-24.04-arm' }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [ linux/amd64, linux/arm64 ] platform: [linux/amd64, linux/arm64]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker - name: Login to Docker
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Set image tag - name: Prepare Image Tags
id: set-tags id: prep
run: | run: |
REF_NAME=${GITHUB_REF#refs/tags/} ARCH=${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
if [ "${{ matrix.platform }}" = "linux/amd64" ]; then echo "image=${{ inputs.image_name }}:${GITHUB_REF#refs/tags/}-$ARCH" >> $GITHUB_OUTPUT
IMAGE="${{ inputs.image_name }}:$REF_NAME-amd64" echo "safe_platform=${{ matrix.platform == 'linux/amd64' && 'linux-amd64' || 'linux-arm64' }}" >> $GITHUB_OUTPUT
else
IMAGE="${{ inputs.image_name }}:$REF_NAME-arm64"
fi
echo "image=$IMAGE" >> $GITHUB_OUTPUT
- name: Build and push image - name: Build and push image
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
@@ -62,61 +60,55 @@ jobs:
file: ${{ inputs.dockerfile }} file: ${{ inputs.dockerfile }}
platforms: ${{ matrix.platform }} platforms: ${{ matrix.platform }}
push: true push: true
tags: ${{ steps.set-tags.outputs.image }} tags: ${{ steps.prep.outputs.image }}
target: ${{ inputs.target }} target: ${{ inputs.target }}
cache-from: type=gha,scope=build-${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=build-${{ matrix.platform }}
- name: Prepare artifact name - name: Save image name for manifest
id: artifact run: echo "${{ steps.prep.outputs.image }}" > image.txt
run: |
platform=${{ matrix.platform }}
echo "safe_platform=${platform//\//-}" >> $GITHUB_OUTPUT
echo "${{ steps.set-tags.outputs.image }}" > image.txt
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f - uses: actions/upload-artifact@v4
with: with:
name: image-${{ steps.artifact.outputs.safe_platform }} name: image-${{ steps.prep.outputs.safe_platform }}
path: image.txt path: image.txt
if-no-files-found: warn retention-days: 1
compression-level: 6
overwrite: false
include-hidden-files: false
create-manifest: create-manifest:
name: Create multi-arch Docker manifest (Portabase) name: Create multi-arch manifest
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build
steps: steps:
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 - uses: actions/download-artifact@v4
with: with:
name: image-linux-amd64 name: image-linux-amd64
path: /tmp/digests/amd64 path: /tmp/digests/amd64
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 - uses: actions/download-artifact@v4
with: with:
name: image-linux-arm64 name: image-linux-arm64
path: /tmp/digests/arm64 path: /tmp/digests/arm64
- name: Login to Docker - name: Login to Docker
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ inputs.image_name }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable=${{ inputs.add_latest }}
- name: Create and push manifest list - name: Create and push manifest list
working-directory: /tmp/digests working-directory: /tmp/digests
run: | run: |
DOCKER_IMAGES="$(cat amd64/image.txt) $(cat arm64/image.txt)" DOCKER_IMAGES="$(cat amd64/image.txt) $(cat arm64/image.txt)"
REF_NAME=${GITHUB_REF#refs/tags/} TAG_ARGS=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON")
MANIFEST_IMAGE="${{ inputs.image_name }}:$REF_NAME" docker buildx imagetools create $DOCKER_IMAGES $TAG_ARGS
docker buildx imagetools create $DOCKER_IMAGES -t $MANIFEST_IMAGE
docker buildx imagetools inspect $MANIFEST_IMAGE
if [ "${{ inputs.add_latest }}" = "true" ]; then
docker buildx imagetools create $DOCKER_IMAGES -t ${{ inputs.image_name }}:latest
docker buildx imagetools inspect ${{ inputs.image_name }}:latest
fi
+47
View File
@@ -0,0 +1,47 @@
name: PR Checker
on:
pull_request:
branches:
- main
- dev
jobs:
validate-code:
name: Code Integrity Check
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
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
+8 -9
View File
@@ -3,29 +3,28 @@ name: Publish Docker image for release candidate
on: on:
push: push:
tags: tags:
- '*-rc*' - "*.*.*-rc*"
- "!*-*-rc*"
permissions: permissions:
contents: write contents: read
packages: write packages: write
jobs: jobs:
docker_publish: docker_publish:
uses: ./.github/workflows/docker.yml uses: ./.github/workflows/docker.yml
with: with:
add_latest: false add_latest: true
secrets: secrets:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME_2 }} DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME_2 }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD_2 }} DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD_2 }}
github_release: discord_notification:
needs: docker_publish needs: docker_publish
uses: ./.github/workflows/github.yml uses: ./.github/workflows/discord.yml
with: with:
prerelease: true discord_title: "New Release Candidate: ${{ github.ref_name }}"
make_latest: false discord_color: 2044800
discord_title: "||@release-dashboard|| New release candidate published"
discord_color: 16776960
discord_footer: "Portabase" discord_footer: "Portabase"
secrets: secrets:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
+8 -10
View File
@@ -3,11 +3,11 @@ name: Publish Docker image for release
on: on:
push: push:
tags: tags:
- '*.*.*' - "*.*.*"
- '!*-*' - "!*-*"
permissions: permissions:
contents: write contents: read
packages: write packages: write
jobs: jobs:
@@ -19,15 +19,13 @@ jobs:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME_2 }} DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME_2 }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD_2 }} DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD_2 }}
github_release: discord_notification:
needs: docker_publish needs: docker_publish
uses: ./.github/workflows/github.yml uses: ./.github/workflows/discord.yml
with: with:
prerelease: false discord_title: "New Release: ${{ github.ref_name }}"
make_latest: true discord_color: 3066993
discord_title: "||@release-dashboard|| New release published"
discord_color: 5814783
discord_footer: "Portabase" discord_footer: "Portabase"
secrets: secrets:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+56
View File
@@ -0,0 +1,56 @@
{
"git": {
"commit": true,
"commitMessage": "chore: release v${version}",
"requireCleanWorkingDir": true,
"tag": true,
"tagName": "${version}",
"push": true
},
"github": {
"release": true,
"tokenRef": "GITHUB_TOKEN"
},
"plugins": {
"@release-it/conventional-changelog": {
"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": {
"out": {
"file": "CITATION.cff",
"path": "version",
"type": "text/yaml"
}
}
}
}
+9 -4
View File
@@ -1,6 +1,6 @@
cff-version: 1.2.0 cff-version: 1.2.0
title: Portabase 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 type: software
authors: authors:
- family-names: Gauthereau - family-names: Gauthereau
@@ -9,7 +9,12 @@ authors:
given-names: Killian given-names: Killian
repository-code: https://github.com/Portabase/portabase repository-code: https://github.com/Portabase/portabase
url: https://portabase.io 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: keywords:
- docker - docker
- kubernetes - kubernetes
@@ -26,5 +31,5 @@ keywords:
- web-ui - web-ui
- agent - agent
license: Apache-2.0 license: Apache-2.0
version: 1.4.3 version: 1.4.13
date-released: "2026-03-02" date-released: '2026-03-02'
-3
View File
@@ -1,4 +1,3 @@
#FROM node:22-bullseye AS base
FROM --platform=$BUILDPLATFORM node:22-bullseye AS base FROM --platform=$BUILDPLATFORM node:22-bullseye AS base
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
@@ -112,8 +111,6 @@ RUN chmod +x /usr/local/bin/tusd
COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf
#RUN mkdir -p .next /app/private/uploads \
# && chown -R nextjs:nodejs .next /app/private /app/public
RUN mkdir -p .next /data/private/uploads \ RUN mkdir -p .next /data/private/uploads \
&& chown -R nextjs:nodejs .next /data/private /app/public && chown -R nextjs:nodejs .next /data/private /app/public
+6 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "portabase", "name": "portabase",
"version": "1.4.3", "version": "1.4.13",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev --turbopack -p 8887", "dev": "next dev --turbopack -p 8887",
@@ -11,7 +11,8 @@
"db:generate": "drizzle-kit generate", "db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate", "db:migrate": "drizzle-kit migrate",
"db:drop": "drizzle-kit drop", "db:drop": "drizzle-kit drop",
"auth:generate": "npx @better-auth/cli generate --config ./src/lib/auth/auth.ts" "auth:generate": "npx @better-auth/cli generate --config ./src/lib/auth/auth.ts",
"release": "release-it"
}, },
"dependencies": { "dependencies": {
"@better-auth/passkey": "^1.4.19", "@better-auth/passkey": "^1.4.19",
@@ -65,7 +66,6 @@
"drizzle-orm": "^0.43.1", "drizzle-orm": "^0.43.1",
"drizzle-zod": "^0.7.1", "drizzle-zod": "^0.7.1",
"embla-carousel-react": "^8.6.0", "embla-carousel-react": "^8.6.0",
"express": "^5.2.1",
"googleapis": "^170.1.0", "googleapis": "^170.1.0",
"input-otp": "^1.4.2", "input-otp": "^1.4.2",
"lucide-react": "^0.553.0", "lucide-react": "^0.553.0",
@@ -106,6 +106,8 @@
"@iconify/react": "^6.0.2", "@iconify/react": "^6.0.2",
"@react-email/preview-server": "4.3.2", "@react-email/preview-server": "4.3.2",
"@react-email/render": "^2.0.4", "@react-email/render": "^2.0.4",
"@release-it/bumper": "^7.0.5",
"@release-it/conventional-changelog": "^10.0.5",
"@tailwindcss/postcss": "^4.2.1", "@tailwindcss/postcss": "^4.2.1",
"@types/eslint-plugin-tailwindcss": "^3.17.0", "@types/eslint-plugin-tailwindcss": "^3.17.0",
"@types/node": "^22.19.11", "@types/node": "^22.19.11",
@@ -123,6 +125,7 @@
"eslint-plugin-tailwindcss": "^3.18.2", "eslint-plugin-tailwindcss": "^3.18.2",
"framer-motion": "^12.34.3", "framer-motion": "^12.34.3",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"release-it": "^19.2.4",
"tailwindcss": "^4.2.1", "tailwindcss": "^4.2.1",
"tsx": "^4.21.0", "tsx": "^4.21.0",
"tw-animate-css": "^1.4.0", "tw-animate-css": "^1.4.0",
+1498 -276
View File
File diff suppressed because it is too large Load Diff
-95
View File
@@ -1,95 +0,0 @@
#!/bin/bash
set -e
if [ -z "$1" ]; then
echo "Usage: ./release <version>"
echo "Example: ./release 1.0.0"
exit 1
fi
VERSION=$1
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
#if [ "$CURRENT_BRANCH" = "main" ]; then
# if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
# echo "Error: On 'main' branch, only release tags (X.Y.Z) are allowed."
# exit 1
# fi
#else
# if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then
# echo "Error: On branch '$CURRENT_BRANCH', only RC tags matching X.Y.Z-rc.W are allowed (e.g., 1.0.0-rc.1)."
# exit 1
# fi
#fi
CLEAN_VERSION=${VERSION#v}
CURRENT_DATE=$(date +%Y-%m-%d)
echo "Preparing release $VERSION..."
# package.json
if [ -f package.json ]; then
echo "Updating package.json..."
if sed --version >/dev/null 2>&1; then
sed -i "s/\"version\": \".*\"/\"version\": \"$CLEAN_VERSION\"/" package.json
else
sed -i '' "s/\"version\": \".*\"/\"version\": \"$CLEAN_VERSION\"/" package.json
fi
fi
# pyproject.toml
if [ -f pyproject.toml ]; then
echo "Updating pyproject.toml..."
if sed --version >/dev/null 2>&1; then
sed -i "s/^version = \".*\"/version = \"$CLEAN_VERSION\"/" pyproject.toml
else
sed -i '' "s/^version = \".*\"/version = \"$CLEAN_VERSION\"/" pyproject.toml
fi
fi
# Cargo.toml
if [ -f Cargo.toml ]; then
echo "Updating Cargo.toml..."
if sed --version >/dev/null 2>&1; then
sed -i "s/^version = \".*\"/version = \"$CLEAN_VERSION\"/" Cargo.toml
else
sed -i '' "s/^version = \".*\"/version = \"$CLEAN_VERSION\"/" Cargo.toml
fi
fi
# CITATION.cff
if [ -f CITATION.cff ]; then
echo "Updating CITATION.cff..."
if sed --version >/dev/null 2>&1; then
sed -i "s/^version: .*/version: $CLEAN_VERSION/" CITATION.cff
sed -i "s/^date-released: .*/date-released: \"$CURRENT_DATE\"/" CITATION.cff
else
sed -i '' "s/^version: .*/version: $CLEAN_VERSION/" CITATION.cff
sed -i '' "s/^date-released: .*/date-released: \"$CURRENT_DATE\"/" CITATION.cff
fi
fi
git add .
if ! git diff-index --quiet HEAD --; then
echo "Committing changes..."
git commit -m "chore(release): $VERSION"
else
echo "No changes to commit. Proceeding to tag..."
fi
if git rev-parse "$VERSION" >/dev/null 2>&1; then
echo "Tag $VERSION already exists. Aborting."
exit 1
fi
echo "Creating tag $VERSION..."
git tag -a "$VERSION" -m "Release $VERSION"
echo "Pushing changes and tags to remote..."
git push
git push origin "$VERSION"
echo "Successfully released $VERSION!"
-6
View File
@@ -1,6 +0,0 @@
import express from "express";
import router from "../src/features/api/router";
export function mountApi(app: express.Express) {
app.use("/services/v1", router);
}
-52
View File
@@ -1,52 +0,0 @@
import next from "next";
import express from "express";
import {mountApi} from "./api";
import http from "http";
const port = Number(process.env.PORT) || 8887;
const dev = process.env.NODE_ENV !== "production";
async function start() {
const nextApp = next({
dev,
hostname: "0.0.0.0",
turbopack: dev,
port
});
const handle = nextApp.getRequestHandler();
await nextApp.prepare();
const app = express();
app.use((req, res, next) => {
req.setTimeout(0);
res.setTimeout(0);
next();
});
mountApi(app);
app.use((req, res, next) => {
if (req.path.startsWith('/services/v1')) return next();
handle(req, res).catch((err) => {
console.error('Next.js App Router error:', err);
res.status(500).send('Internal Server Error');
});
});
const server = http.createServer(app);
server.setTimeout(0);
server.headersTimeout = 0;
server.requestTimeout = 0;
server.keepAliveTimeout = 0;
server.listen(port, "0.0.0.0", () => {
console.log(`NEXT APP → http://localhost:${port}`);
console.log(`API → http://localhost:${port}/services/v1`);
});
}
start();
@@ -1,30 +1,38 @@
import {UseFormReturn} from "react-hook-form"; import { UseFormReturn } from "react-hook-form";
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form"; import {
import {Input} from "@/components/ui/input"; FormControl,
import {Separator} from "@/components/ui/separator"; FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Separator } from "@/components/ui/separator";
import { PasswordInput } from "@/components/ui/password-input";
type NotifierDiscordFormProps = { type NotifierDiscordFormProps = {
form: UseFormReturn<any, any, any> form: UseFormReturn<any, any, any>;
} };
export const NotifierDiscordForm = ({form}: NotifierDiscordFormProps) => { export const NotifierDiscordForm = ({ form }: NotifierDiscordFormProps) => {
return ( return (
<> <>
<Separator className="my-1"/> <Separator className="my-1" />
<FormField <FormField
control={form.control} control={form.control}
name="config.discordWebhook" name="config.discordWebhook"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Discord Webhook URL</FormLabel> <FormLabel>Discord Webhook URL</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="https://discord.com/api/webhooks/..."/> <PasswordInput
</FormControl> {...field}
<FormMessage/> placeholder="https://discord.com/api/webhooks/..."
</FormItem> />
)} </FormControl>
/> <FormMessage />
</> </FormItem>
) )}
} />
</>
);
};
@@ -1,43 +1,49 @@
import {UseFormReturn} from "react-hook-form"; import type { UseFormReturn } from "react-hook-form";
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form"; import {
import {Input} from "@/components/ui/input"; FormControl,
import {Separator} from "@/components/ui/separator"; 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 = { type NotifierGotifyFormProps = {
form: UseFormReturn<any, any, any> form: UseFormReturn<any, any, any>;
} };
export const NotifierGotifyForm = ({form}: NotifierGotifyFormProps) => { export const NotifierGotifyForm = ({ form }: NotifierGotifyFormProps) => {
return ( return (
<> <>
<Separator className="my-1"/> <Separator className="my-1" />
<FormField <FormField
control={form.control} control={form.control}
name="config.gotifyServerUrl" name="config.gotifyServerUrl"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Gotify Server URL</FormLabel> <FormLabel>Gotify Server URL</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="https://gotify.example.com"/> <Input {...field} placeholder="https://gotify.example.com" />
</FormControl> </FormControl>
<FormMessage/> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
<FormField <FormField
control={form.control} control={form.control}
name="config.gotifyAppToken" name="config.gotifyAppToken"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Application Token</FormLabel> <FormLabel>Application Token</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="A1b2C3d4E5f6G7h"/> <PasswordInput {...field} placeholder="A1b2C3d4E5f6G7h" />
</FormControl> </FormControl>
<FormMessage/> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
</> </>
) );
} };
@@ -49,7 +49,7 @@ export const NotifierNtfyForm = ({form}: NotifierNtfyFormProps) => {
<FormItem> <FormItem>
<FormLabel>Access Token (Optional)</FormLabel> <FormLabel>Access Token (Optional)</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="tk_..."/> <PasswordInput {...field} placeholder="tk_..."/>
</FormControl> </FormControl>
<p className="text-xs text-muted-foreground">Only required for protected topics or self-hosted instances with auth.</p> <p className="text-xs text-muted-foreground">Only required for protected topics or self-hosted instances with auth.</p>
<FormMessage/> <FormMessage/>
@@ -1,31 +1,38 @@
import { UseFormReturn } from "react-hook-form";
import {UseFormReturn} from "react-hook-form"; import {
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form"; FormControl,
import {Input} from "@/components/ui/input"; FormField,
import {Separator} from "@/components/ui/separator"; FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Separator } from "@/components/ui/separator";
import { PasswordInput } from "@/components/ui/password-input";
type NotifierSmtpFormProps = { type NotifierSmtpFormProps = {
form: UseFormReturn<any, any, any> form: UseFormReturn<any, any, any>;
} };
export const NotifierSlackForm = ({form}: NotifierSmtpFormProps) => { export const NotifierSlackForm = ({ form }: NotifierSmtpFormProps) => {
return( return (
<> <>
<Separator className="my-1"/> <Separator className="my-1" />
<FormField <FormField
control={form.control} control={form.control}
name="config.slackWebhook" name="config.slackWebhook"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Slack Webhook URL</FormLabel> <FormLabel>Slack Webhook URL</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="https://hooks.slack.com/services/..."/> <PasswordInput
</FormControl> {...field}
<FormMessage/> placeholder="https://hooks.slack.com/services/..."
</FormItem> />
)} </FormControl>
/> <FormMessage />
</> </FormItem>
) )}
} />
</>
);
};
@@ -1,64 +1,84 @@
import {UseFormReturn} from "react-hook-form"; import { UseFormReturn } from "react-hook-form";
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form"; import {
import {Input} from "@/components/ui/input"; FormControl,
import {Separator} from "@/components/ui/separator"; 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 = { type NotifierTelegramFormProps = {
form: UseFormReturn<any, any, any> form: UseFormReturn<any, any, any>;
} };
export const NotifierTelegramForm = ({form}: NotifierTelegramFormProps) => { export const NotifierTelegramForm = ({ form }: NotifierTelegramFormProps) => {
return ( return (
<> <>
<Separator className="my-1"/> <Separator className="my-1" />
<FormField <FormField
control={form.control} control={form.control}
name="config.telegramBotToken" name="config.telegramBotToken"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Telegram Bot Token</FormLabel> <FormLabel>Telegram Bot Token</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"/> <PasswordInput
</FormControl> {...field}
<FormMessage/> placeholder="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
</FormItem> />
)} </FormControl>
/> <FormMessage />
<FormField </FormItem>
control={form.control} )}
name="config.telegramChatId" />
render={({field}) => ( <FormField
<FormItem> control={form.control}
<FormLabel>Telegram Chat ID</FormLabel> name="config.telegramChatId"
<FormControl> render={({ field }) => (
<Input {...field} placeholder="-100123456789 or 123456789"/> <FormItem>
</FormControl> <FormLabel>Telegram Chat ID</FormLabel>
<p className="text-xs text-muted-foreground"> <FormControl>
You must start the conversation with the bot first (<strong>/start</strong>). <br/> <Input {...field} placeholder="-100123456789 or 123456789" />
For groups, add the bot to the group. <br/> </FormControl>
You can use <a href="https://t.me/userinfobot" target="_blank" rel="noopener noreferrer" className="underline">@userinfobot</a> to find your ID. <p className="text-xs text-muted-foreground">
</p> You must start the conversation with the bot first (
<FormMessage/> <strong>/start</strong>). <br />
</FormItem> For groups, add the bot to the group. <br />
)} You can use{" "}
/> <a
<FormField href="https://t.me/userinfobot"
control={form.control} target="_blank"
name="config.telegramTopicId" rel="noopener noreferrer"
render={({field}) => ( className="underline"
<FormItem> >
<FormLabel>Telegram Topic ID</FormLabel> @userinfobot
<FormControl> </a>{" "}
<Input {...field} placeholder="123456"/> to find your ID.
</FormControl> </p>
<p className="text-xs text-muted-foreground"> <FormMessage />
Unique identifier for the target message thread (topic) of the forum; for forum supergroups only </FormItem>
</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>
)}
/>
</>
);
};
@@ -1,65 +1,72 @@
import {UseFormReturn} from "react-hook-form"; import { UseFormReturn } from "react-hook-form";
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form"; import {
import {Input} from "@/components/ui/input"; FormControl,
import {Separator} from "@/components/ui/separator"; 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 = { type NotifierWebhookFormProps = {
form: UseFormReturn<any, any, any> form: UseFormReturn<any, any, any>;
} };
export const NotifierWebhookForm = ({form}: NotifierWebhookFormProps) => { export const NotifierWebhookForm = ({ form }: NotifierWebhookFormProps) => {
return ( return (
<> <>
<Separator className="my-1"/> <Separator className="my-1" />
<FormField <FormField
control={form.control} control={form.control}
name="config.webhookUrl" name="config.webhookUrl"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Webhook URL</FormLabel> <FormLabel>Webhook URL</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="https://example.com/api/webhook"/> <Input {...field} placeholder="https://example.com/api/webhook" />
</FormControl> </FormControl>
<FormMessage/> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
<div className="flex gap-4"> <div className="flex gap-4">
<div className="flex-1"> <div className="flex-1">
<FormField <FormField
control={form.control} control={form.control}
name="config.webhookSecretHeader" name="config.webhookSecretHeader"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Header Name (Optional)</FormLabel> <FormLabel>Header Name (Optional)</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="X-Webhook-Secret"/> <Input {...field} placeholder="X-Webhook-Secret" />
</FormControl> </FormControl>
<FormMessage/> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
</div> </div>
<div className="flex-1"> <div className="flex-1">
<FormField <FormField
control={form.control} control={form.control}
name="config.webhookSecret" name="config.webhookSecret"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Secret Value (Optional)</FormLabel> <FormLabel>Secret Value (Optional)</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="Secret value..."/> <PasswordInput {...field} placeholder="Secret value..." />
</FormControl> </FormControl>
<FormMessage/> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
</div> </div>
</div> </div>
<p className="text-xs text-muted-foreground mt-2"> <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>). If provided, the secret will be sent in the specified header (defaults
</p> to <code>X-Webhook-Secret</code>).
</> </p>
) </>
} );
};
@@ -1,115 +1,116 @@
import {UseFormReturn} from "react-hook-form"; import { UseFormReturn } from "react-hook-form";
import {FormControl, FormField, FormItem, FormLabel, FormMessage} from "@/components/ui/form"; import {
import {Input} from "@/components/ui/input"; FormControl,
import {Separator} from "@/components/ui/separator"; FormField,
import {PasswordInput} from "@/components/ui/password-input"; FormItem,
import {Switch} from "@/components/ui/switch"; 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 = { type StorageS3FormProps = {
form: UseFormReturn<any, any, any> form: UseFormReturn<any, any, any>;
} };
export const StorageS3Form = ({form}: StorageS3FormProps) => { export const StorageS3Form = ({ form }: StorageS3FormProps) => {
return ( return (
<> <>
<Separator className="my-1"/> <Separator className="my-1" />
<FormField <FormField
control={form.control} control={form.control}
name="config.endPointUrl" name="config.endPointUrl"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Endpoint URL</FormLabel> <FormLabel>Endpoint URL</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="s3.amazonaws.com"/> <Input {...field} placeholder="s3.amazonaws.com" />
</FormControl> </FormControl>
<FormMessage/> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
<FormField <FormField
control={form.control} control={form.control}
name="config.region" name="config.region"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Region</FormLabel> <FormLabel>Region</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="us-east-1"/> <Input {...field} placeholder="us-east-1" />
</FormControl> </FormControl>
<FormMessage/> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
<FormField <FormField
control={form.control} control={form.control}
name="config.accessKey" name="config.accessKey"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Access Key</FormLabel> <FormLabel>Access Key</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="A1b2C3d4E5f6G7h"/> <Input {...field} placeholder="A1b2C3d4E5f6G7h" />
</FormControl> </FormControl>
<FormMessage/> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
<FormField <FormField
control={form.control} control={form.control}
name="config.secretKey" name="config.secretKey"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Secret Key</FormLabel> <FormLabel>Secret Key</FormLabel>
<FormControl> <FormControl>
<PasswordInput {...field} placeholder="A1b2C3d4E5f6G7h"/> <PasswordInput {...field} placeholder="A1b2C3d4E5f6G7h" />
</FormControl> </FormControl>
<FormMessage/> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
<FormField <FormField
control={form.control} control={form.control}
name="config.bucketName" name="config.bucketName"
render={({field}) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Bucket name</FormLabel> <FormLabel>Bucket name</FormLabel>
<FormControl> <FormControl>
<Input {...field} placeholder="portabase-dev"/> <Input {...field} placeholder="portabase-dev" />
</FormControl> </FormControl>
<FormMessage/> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
<FormField <FormField
control={form.control} control={form.control}
name="config.port" name="config.port"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Port</FormLabel> <FormLabel>Port</FormLabel>
<FormControl> <FormControl>
<Input {...field} type="number" placeholder="443" /> <Input {...field} type="number" placeholder="443" />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
<FormField <FormField
control={form.control} control={form.control}
name="config.ssl" name="config.ssl"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel>Use SSL</FormLabel> <FormLabel>Use SSL</FormLabel>
<FormControl> <FormControl>
<Switch <Switch checked={field.value} onCheckedChange={field.onChange} />
checked={field.value} </FormControl>
onCheckedChange={field.onChange} <FormMessage />
/> </FormItem>
</FormControl> )}
<FormMessage /> />
</FormItem> </>
)} );
/> };
</>
)
}