diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index f5304bb1..52494864 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -7,7 +7,7 @@ assignees: ""
---
**描述问题**
-简要描述问题是什么
+简要描述问题是什么,1 个 ISSUE 只描述一个问题。
**复现步骤**
复现该问题的步骤:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index eccd8712..9eb598c9 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -7,7 +7,7 @@ assignees: ""
---
**功能描述**
-简要描述你希望添加的功能和相关问题。
+简要描述你希望添加的功能和相关问题,1 个 ISSUE 只描述一个功能。
**动机**
为什么这个功能对项目有帮助?
diff --git a/.github/workflows/push_image.yml b/.github/workflows/push_image.yml
index b64c8bbf..22802cbf 100644
--- a/.github/workflows/push_image.yml
+++ b/.github/workflows/push_image.yml
@@ -52,7 +52,7 @@ jobs:
uses: docker/build-push-action@v6
with:
context: .
- file: ./Dockerfile_build
+ file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d1b51411..8ec32deb 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -14,18 +14,18 @@ jobs:
with:
fetch-depth: 0
- # - name: Set up Node.js
- # uses: actions/setup-node@v4
- # with:
- # node-version: 20.11.0
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20.11.0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ">=1.22.5"
- # - name: Build Admin dashboard UI
- # run: npm --prefix=./ui ci && npm --prefix=./ui run build
+ - name: Build Admin dashboard UI
+ run: npm --prefix=./ui ci && npm --prefix=./ui run build
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
diff --git a/.gitignore b/.gitignore
index 7fd3ecd1..bfb74e99 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,13 +9,12 @@
*.njsproj
*.sln
*.sw?
-
__debug_bin*
vendor
pb_data
build
main
-
+ui/dist
./dist
./certimate
/docker/data
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..173dca23
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,29 @@
+FROM node:20-alpine3.19 AS front-builder
+
+WORKDIR /app
+
+COPY . /app/
+
+RUN \
+ cd /app/ui && \
+ npm install && \
+ npm run build
+
+FROM golang:1.22-alpine AS builder
+
+WORKDIR /app
+
+COPY ../. /app/
+
+RUN rm -rf /app/ui/dist
+COPY --from=front-builder /app/ui/dist /app/ui/dist
+
+RUN go build -o certimate
+
+FROM alpine:latest
+
+WORKDIR /app
+
+COPY --from=builder /app/certimate .
+
+ENTRYPOINT ["./certimate", "serve", "--http", "0.0.0.0:8090"]
diff --git a/Dockerfile_build b/Dockerfile_build
deleted file mode 100644
index efd3d962..00000000
--- a/Dockerfile_build
+++ /dev/null
@@ -1,16 +0,0 @@
-FROM golang:1.22-alpine as builder
-
-WORKDIR /app
-
-COPY ../. /app/
-
-RUN go build -o certimate
-
-
-FROM alpine:latest
-
-WORKDIR /app
-
-COPY --from=builder /app/certimate .
-
-ENTRYPOINT ["./certimate", "serve", "--http", "0.0.0.0:8090"]
diff --git a/README.md b/README.md
index bacb09f0..cb3b0b29 100644
--- a/README.md
+++ b/README.md
@@ -82,6 +82,8 @@ go run main.go serve
| CloudFlare | √ | | 可签发在 CloudFlare 注册的域名;CloudFlare 服务自带 SSL 证书 |
| GoDaddy | √ | | 可签发在 GoDaddy 注册的域名 |
| Namesilo | √ | | 可签发在 Namesilo 注册的域名 |
+| PowerDNS | √ | | 可签发通过PowerDNS管理的域名 |
+| HTTP request | √ | | 可签发通过HTTP Request修改dns的域名 |
| 本地部署 | | √ | 可部署到本地服务器 |
| SSH | | √ | 可部署到 SSH 服务器 |
| Webhook | | √ | 可部署时回调到 Webhook |
diff --git a/README_EN.md b/README_EN.md
index 85625fed..d048cecb 100644
--- a/README_EN.md
+++ b/README_EN.md
@@ -81,6 +81,9 @@ password:1234567890
| CloudFlare | √ | | Supports domains registered on CloudFlare; CloudFlare services come with SSL certificates |
| GoDaddy | √ | | Supports domains registered on GoDaddy |
| Namesilo | √ | | Supports domains registered on Namesilo |
+| PowerDNS | √ | | Supports domains managed by PowerDNS |
+| HTTP request | √ | | Supports domains dns managed by HTTP Request |
+
| Local Deploy | | √ | Supports deployment to local servers |
| SSH | | √ | Supports deployment to SSH servers |
| Webhook | | √ | Supports callback to Webhook |
diff --git a/go.mod b/go.mod
index 7604d1e9..6a8a5f15 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module certimate
+module github.com/usual2970/certimate
go 1.22.0
diff --git a/internal/applicant/aliyun.go b/internal/applicant/aliyun.go
index 0b0dc61d..40adf960 100644
--- a/internal/applicant/aliyun.go
+++ b/internal/applicant/aliyun.go
@@ -7,7 +7,7 @@ import (
"github.com/go-acme/lego/v4/providers/dns/alidns"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type aliyun struct {
diff --git a/internal/applicant/applicant.go b/internal/applicant/applicant.go
index 60209b90..b70f216e 100644
--- a/internal/applicant/applicant.go
+++ b/internal/applicant/applicant.go
@@ -9,6 +9,9 @@ import (
"fmt"
"strings"
+ "github.com/usual2970/certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/utils/app"
+
"github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/certificate"
"github.com/go-acme/lego/v4/challenge"
@@ -16,9 +19,6 @@ import (
"github.com/go-acme/lego/v4/lego"
"github.com/go-acme/lego/v4/registration"
"github.com/pocketbase/pocketbase/models"
-
- "certimate/internal/domain"
- "certimate/internal/utils/app"
)
const (
@@ -29,6 +29,8 @@ const (
configTypeCloudflare = "cloudflare"
configTypeNamesilo = "namesilo"
configTypeGodaddy = "godaddy"
+ configTypePdns = "pdns"
+ configTypeHttpreq = "httpreq"
)
const defaultSSLProvider = "letsencrypt"
@@ -136,6 +138,10 @@ func Get(record *models.Record) (Applicant, error) {
return NewNamesilo(option), nil
case configTypeGodaddy:
return NewGodaddy(option), nil
+ case configTypePdns:
+ return NewPdns(option), nil
+ case configTypeHttpreq:
+ return NewHttpreq(option), nil
default:
return nil, errors.New("unknown config type")
}
diff --git a/internal/applicant/aws.go b/internal/applicant/aws.go
index 9a491d06..be18d747 100644
--- a/internal/applicant/aws.go
+++ b/internal/applicant/aws.go
@@ -7,7 +7,7 @@ import (
"github.com/go-acme/lego/v4/providers/dns/route53"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type aws struct {
diff --git a/internal/applicant/cloudflare.go b/internal/applicant/cloudflare.go
index 75d083fd..f1c40ebe 100644
--- a/internal/applicant/cloudflare.go
+++ b/internal/applicant/cloudflare.go
@@ -7,7 +7,7 @@ import (
cf "github.com/go-acme/lego/v4/providers/dns/cloudflare"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type cloudflare struct {
diff --git a/internal/applicant/godaddy.go b/internal/applicant/godaddy.go
index adcfe13b..7ae40a72 100644
--- a/internal/applicant/godaddy.go
+++ b/internal/applicant/godaddy.go
@@ -7,7 +7,7 @@ import (
godaddyProvider "github.com/go-acme/lego/v4/providers/dns/godaddy"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type godaddy struct {
diff --git a/internal/applicant/httpreq.go b/internal/applicant/httpreq.go
new file mode 100644
index 00000000..7972b7ae
--- /dev/null
+++ b/internal/applicant/httpreq.go
@@ -0,0 +1,38 @@
+package applicant
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+
+ "github.com/go-acme/lego/v4/providers/dns/httpreq"
+
+ "github.com/usual2970/certimate/internal/domain"
+)
+
+type httpReq struct {
+ option *ApplyOption
+}
+
+func NewHttpreq(option *ApplyOption) Applicant {
+ return &httpReq{
+ option: option,
+ }
+}
+
+func (a *httpReq) Apply() (*Certificate, error) {
+ access := &domain.HttpreqAccess{}
+ json.Unmarshal([]byte(a.option.Access), access)
+
+ os.Setenv("HTTPREQ_ENDPOINT", access.Endpoint)
+ os.Setenv("HTTPREQ_MODE", access.Mode)
+ os.Setenv("HTTPREQ_USERNAME", access.Username)
+ os.Setenv("HTTPREQ_PASSWORD", access.Password)
+ os.Setenv("HTTPREQ_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", a.option.Timeout))
+ dnsProvider, err := httpreq.NewDNSProvider()
+ if err != nil {
+ return nil, err
+ }
+
+ return apply(a.option, dnsProvider)
+}
diff --git a/internal/applicant/huaweicloud.go b/internal/applicant/huaweicloud.go
index 294e95a6..94f72c7f 100644
--- a/internal/applicant/huaweicloud.go
+++ b/internal/applicant/huaweicloud.go
@@ -7,7 +7,7 @@ import (
huaweicloudProvider "github.com/go-acme/lego/v4/providers/dns/huaweicloud"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type huaweicloud struct {
diff --git a/internal/applicant/namesilo.go b/internal/applicant/namesilo.go
index 0f2aa155..55fd3b3c 100644
--- a/internal/applicant/namesilo.go
+++ b/internal/applicant/namesilo.go
@@ -7,7 +7,7 @@ import (
namesiloProvider "github.com/go-acme/lego/v4/providers/dns/namesilo"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type namesilo struct {
diff --git a/internal/applicant/pdns.go b/internal/applicant/pdns.go
new file mode 100644
index 00000000..2c84c85e
--- /dev/null
+++ b/internal/applicant/pdns.go
@@ -0,0 +1,36 @@
+package applicant
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+
+ "github.com/go-acme/lego/v4/providers/dns/pdns"
+
+ "github.com/usual2970/certimate/internal/domain"
+)
+
+type powerdns struct {
+ option *ApplyOption
+}
+
+func NewPdns(option *ApplyOption) Applicant {
+ return &powerdns{
+ option: option,
+ }
+}
+
+func (a *powerdns) Apply() (*Certificate, error) {
+ access := &domain.PdnsAccess{}
+ json.Unmarshal([]byte(a.option.Access), access)
+
+ os.Setenv("PDNS_API_URL", access.ApiUrl)
+ os.Setenv("PDNS_API_KEY", access.ApiKey)
+ os.Setenv("PDNS_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", a.option.Timeout))
+ dnsProvider, err := pdns.NewDNSProvider()
+ if err != nil {
+ return nil, err
+ }
+
+ return apply(a.option, dnsProvider)
+}
diff --git a/internal/applicant/tencent.go b/internal/applicant/tencent.go
index 705f63ad..4733e22e 100644
--- a/internal/applicant/tencent.go
+++ b/internal/applicant/tencent.go
@@ -7,7 +7,7 @@ import (
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type tencent struct {
diff --git a/internal/deployer/aliyun_cdn.go b/internal/deployer/aliyun_cdn.go
index 467ab96f..97ac0d83 100644
--- a/internal/deployer/aliyun_cdn.go
+++ b/internal/deployer/aliyun_cdn.go
@@ -10,8 +10,8 @@ import (
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
- "certimate/internal/domain"
- "certimate/internal/utils/rand"
+ "github.com/usual2970/certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/utils/rand"
)
type AliyunCDNDeployer struct {
diff --git a/internal/deployer/aliyun_esa.go b/internal/deployer/aliyun_esa.go
index 0403e04b..79bc54ea 100644
--- a/internal/deployer/aliyun_esa.go
+++ b/internal/deployer/aliyun_esa.go
@@ -1,7 +1,7 @@
/*
* @Author: Bin
* @Date: 2024-09-17
- * @FilePath: /certimate/internal/deployer/aliyun_esa.go
+ * @FilePath: /github.com/usual2970/certimate/internal/deployer/aliyun_esa.go
*/
package deployer
@@ -15,8 +15,8 @@ import (
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
- "certimate/internal/domain"
- "certimate/internal/utils/rand"
+ "github.com/usual2970/certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/utils/rand"
)
type AliyunESADeployer struct {
diff --git a/internal/deployer/aliyun_oss.go b/internal/deployer/aliyun_oss.go
index e8d259d5..9626e3bc 100644
--- a/internal/deployer/aliyun_oss.go
+++ b/internal/deployer/aliyun_oss.go
@@ -7,7 +7,7 @@ import (
"github.com/aliyun/aliyun-oss-go-sdk/oss"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type AliyunOSSDeployer struct {
diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go
index b60b5d51..18794028 100644
--- a/internal/deployer/deployer.go
+++ b/internal/deployer/deployer.go
@@ -9,9 +9,9 @@ import (
"github.com/pocketbase/pocketbase/models"
- "certimate/internal/applicant"
- "certimate/internal/domain"
- "certimate/internal/utils/app"
+ "github.com/usual2970/certimate/internal/applicant"
+ "github.com/usual2970/certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/utils/app"
)
const (
diff --git a/internal/deployer/huaweicloud_cdn.go b/internal/deployer/huaweicloud_cdn.go
index 65963578..f7db488d 100644
--- a/internal/deployer/huaweicloud_cdn.go
+++ b/internal/deployer/huaweicloud_cdn.go
@@ -11,8 +11,8 @@ import (
cdnModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2/model"
cdnRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2/region"
- "certimate/internal/domain"
- uploaderImpl "certimate/internal/pkg/core/uploader/impl"
+ "github.com/usual2970/certimate/internal/domain"
+ uploaderImpl "github.com/usual2970/certimate/internal/pkg/core/uploader/impl"
)
type HuaweiCloudCDNDeployer struct {
diff --git a/internal/deployer/k8s_secret.go b/internal/deployer/k8s_secret.go
index 97d16fcf..3729114f 100644
--- a/internal/deployer/k8s_secret.go
+++ b/internal/deployer/k8s_secret.go
@@ -9,7 +9,7 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type K8sSecretDeployer struct {
diff --git a/internal/deployer/local.go b/internal/deployer/local.go
index c9f9ecd6..784660b6 100644
--- a/internal/deployer/local.go
+++ b/internal/deployer/local.go
@@ -9,7 +9,7 @@ import (
"path/filepath"
"runtime"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type LocalDeployer struct {
diff --git a/internal/deployer/qiniu_cdn.go b/internal/deployer/qiniu_cdn.go
index f6ff80c6..f6e6b167 100644
--- a/internal/deployer/qiniu_cdn.go
+++ b/internal/deployer/qiniu_cdn.go
@@ -10,8 +10,8 @@ import (
"github.com/qiniu/go-sdk/v7/auth"
- "certimate/internal/domain"
- xhttp "certimate/internal/utils/http"
+ "github.com/usual2970/certimate/internal/domain"
+ xhttp "github.com/usual2970/certimate/internal/utils/http"
)
const qiniuGateway = "http://api.qiniu.com"
diff --git a/internal/deployer/qiniu_cdn_test.go b/internal/deployer/qiniu_cdn_test.go
index 7e625dfb..396f6546 100644
--- a/internal/deployer/qiniu_cdn_test.go
+++ b/internal/deployer/qiniu_cdn_test.go
@@ -5,7 +5,7 @@ import (
"github.com/qiniu/go-sdk/v7/auth"
- "certimate/internal/applicant"
+ "github.com/usual2970/certimate/internal/applicant"
)
func Test_qiuniu_uploadCert(t *testing.T) {
diff --git a/internal/deployer/ssh.go b/internal/deployer/ssh.go
index e2885236..551e8634 100644
--- a/internal/deployer/ssh.go
+++ b/internal/deployer/ssh.go
@@ -11,7 +11,7 @@ import (
"github.com/pkg/sftp"
sshPkg "golang.org/x/crypto/ssh"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
type SSHDeployer struct {
diff --git a/internal/deployer/tencent_cdn.go b/internal/deployer/tencent_cdn.go
index e97898eb..aa315466 100644
--- a/internal/deployer/tencent_cdn.go
+++ b/internal/deployer/tencent_cdn.go
@@ -12,8 +12,8 @@ import (
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
ssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205"
- "certimate/internal/domain"
- "certimate/internal/utils/rand"
+ "github.com/usual2970/certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/utils/rand"
)
type TencentCDNDeployer struct {
diff --git a/internal/deployer/webhook.go b/internal/deployer/webhook.go
index 97927254..522705d4 100644
--- a/internal/deployer/webhook.go
+++ b/internal/deployer/webhook.go
@@ -7,8 +7,8 @@ import (
"fmt"
"net/http"
- "certimate/internal/domain"
- xhttp "certimate/internal/utils/http"
+ "github.com/usual2970/certimate/internal/domain"
+ xhttp "github.com/usual2970/certimate/internal/utils/http"
)
type WebhookDeployer struct {
diff --git a/internal/domain/access.go b/internal/domain/access.go
index ebd9191a..889d37fa 100644
--- a/internal/domain/access.go
+++ b/internal/domain/access.go
@@ -41,6 +41,18 @@ type GodaddyAccess struct {
ApiSecret string `json:"apiSecret"`
}
+type PdnsAccess struct {
+ ApiUrl string `json:"apiUrl"`
+ ApiKey string `json:"apiKey"`
+}
+
+type HttpreqAccess struct {
+ Endpoint string `json:"endpoint"`
+ Mode string `json:"mode"`
+ Username string `json:"username"`
+ Password string `json:"password"`
+}
+
type LocalAccess struct{}
type SSHAccess struct {
diff --git a/internal/domains/deploy.go b/internal/domains/deploy.go
index 0f6776c6..23b3a1dd 100644
--- a/internal/domains/deploy.go
+++ b/internal/domains/deploy.go
@@ -7,9 +7,9 @@ import (
"github.com/pocketbase/pocketbase/models"
- "certimate/internal/applicant"
- "certimate/internal/deployer"
- "certimate/internal/utils/app"
+ "github.com/usual2970/certimate/internal/applicant"
+ "github.com/usual2970/certimate/internal/deployer"
+ "github.com/usual2970/certimate/internal/utils/app"
)
type Phase string
diff --git a/internal/domains/domains.go b/internal/domains/domains.go
index 03fc24f1..dd65dff8 100644
--- a/internal/domains/domains.go
+++ b/internal/domains/domains.go
@@ -6,7 +6,7 @@ import (
"github.com/pocketbase/pocketbase/models"
- "certimate/internal/utils/app"
+ "github.com/usual2970/certimate/internal/utils/app"
)
func create(ctx context.Context, record *models.Record) error {
diff --git a/internal/domains/event.go b/internal/domains/event.go
index 5ad38ad1..7acb31e9 100644
--- a/internal/domains/event.go
+++ b/internal/domains/event.go
@@ -3,7 +3,7 @@ package domains
import (
"github.com/pocketbase/pocketbase/core"
- "certimate/internal/utils/app"
+ "github.com/usual2970/certimate/internal/utils/app"
)
const tableName = "domains"
diff --git a/internal/domains/history.go b/internal/domains/history.go
index 616c7c8c..47ed5afa 100644
--- a/internal/domains/history.go
+++ b/internal/domains/history.go
@@ -5,9 +5,9 @@ import (
"github.com/pocketbase/pocketbase/models"
- "certimate/internal/applicant"
- "certimate/internal/utils/app"
- "certimate/internal/utils/xtime"
+ "github.com/usual2970/certimate/internal/applicant"
+ "github.com/usual2970/certimate/internal/utils/app"
+ "github.com/usual2970/certimate/internal/utils/xtime"
)
type historyItem struct {
diff --git a/internal/domains/init.go b/internal/domains/init.go
index 69de4018..6ca683a0 100644
--- a/internal/domains/init.go
+++ b/internal/domains/init.go
@@ -3,8 +3,8 @@ package domains
import (
"context"
- "certimate/internal/notify"
- "certimate/internal/utils/app"
+ "github.com/usual2970/certimate/internal/notify"
+ "github.com/usual2970/certimate/internal/utils/app"
)
func InitSchedule() {
diff --git a/internal/notify/expire.go b/internal/notify/expire.go
index 985d7491..d4942272 100644
--- a/internal/notify/expire.go
+++ b/internal/notify/expire.go
@@ -8,8 +8,8 @@ import (
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/models"
- "certimate/internal/utils/app"
- "certimate/internal/utils/xtime"
+ "github.com/usual2970/certimate/internal/utils/app"
+ "github.com/usual2970/certimate/internal/utils/xtime"
)
type msg struct {
diff --git a/internal/notify/notify.go b/internal/notify/notify.go
index 90e661f1..e5265b51 100644
--- a/internal/notify/notify.go
+++ b/internal/notify/notify.go
@@ -5,8 +5,8 @@ import (
"fmt"
"strconv"
- "certimate/internal/domain"
- "certimate/internal/utils/app"
+ "github.com/usual2970/certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/utils/app"
notifyPackage "github.com/nikoksr/notify"
"github.com/nikoksr/notify/service/dingding"
diff --git a/internal/notify/service.go b/internal/notify/service.go
index 3e733514..22b77160 100644
--- a/internal/notify/service.go
+++ b/internal/notify/service.go
@@ -4,7 +4,7 @@ import (
"context"
"fmt"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
)
const (
diff --git a/internal/repository/setting.go b/internal/repository/setting.go
index 2bf29d0c..c173151f 100644
--- a/internal/repository/setting.go
+++ b/internal/repository/setting.go
@@ -3,8 +3,8 @@ package repository
import (
"context"
- "certimate/internal/domain"
- "certimate/internal/utils/app"
+ "github.com/usual2970/certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/utils/app"
)
type SettingRepository struct{}
diff --git a/internal/rest/notify.go b/internal/rest/notify.go
index 3430119b..eb8aae48 100644
--- a/internal/rest/notify.go
+++ b/internal/rest/notify.go
@@ -3,8 +3,8 @@ package rest
import (
"context"
- "certimate/internal/domain"
- "certimate/internal/utils/resp"
+ "github.com/usual2970/certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/utils/resp"
"github.com/labstack/echo/v5"
)
diff --git a/internal/routes/routes.go b/internal/routes/routes.go
index 2c670446..d469bb3c 100644
--- a/internal/routes/routes.go
+++ b/internal/routes/routes.go
@@ -1,9 +1,9 @@
package routes
import (
- "certimate/internal/notify"
- "certimate/internal/repository"
- "certimate/internal/rest"
+ "github.com/usual2970/certimate/internal/notify"
+ "github.com/usual2970/certimate/internal/repository"
+ "github.com/usual2970/certimate/internal/rest"
"github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase/apis"
diff --git a/internal/utils/resp/resp.go b/internal/utils/resp/resp.go
index 0153a14c..b4d8240f 100644
--- a/internal/utils/resp/resp.go
+++ b/internal/utils/resp/resp.go
@@ -3,7 +3,7 @@ package resp
import (
"net/http"
- "certimate/internal/domain"
+ "github.com/usual2970/certimate/internal/domain"
"github.com/labstack/echo/v5"
)
diff --git a/main.go b/main.go
index 37482041..7a0bf641 100644
--- a/main.go
+++ b/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "github.com/usual2970/certimate/ui"
"log"
"os"
"strings"
@@ -10,11 +11,11 @@ import (
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/plugins/migratecmd"
- "certimate/internal/domains"
- "certimate/internal/routes"
- "certimate/internal/utils/app"
- _ "certimate/migrations"
- "certimate/ui"
+ _ "github.com/usual2970/certimate/migrations"
+
+ "github.com/usual2970/certimate/internal/domains"
+ "github.com/usual2970/certimate/internal/routes"
+ "github.com/usual2970/certimate/internal/utils/app"
_ "time/tzdata"
)
diff --git a/migrations/1726569833_updated_domains.go b/migrations/1726569833_updated_domains.go
index d624ca51..262b0c42 100644
--- a/migrations/1726569833_updated_domains.go
+++ b/migrations/1726569833_updated_domains.go
@@ -11,7 +11,7 @@ import (
func init() {
m.Register(func(db dbx.Builder) error {
- dao := daos.New(db);
+ dao := daos.New(db)
collection, err := dao.FindCollectionByNameOrId("z3p974ainxjqlvs")
if err != nil {
@@ -47,7 +47,7 @@ func init() {
return dao.SaveCollection(collection)
}, func(db dbx.Builder) error {
- dao := daos.New(db);
+ dao := daos.New(db)
collection, err := dao.FindCollectionByNameOrId("z3p974ainxjqlvs")
if err != nil {
diff --git a/migrations/1728610007_updated_access.go b/migrations/1728610007_updated_access.go
index 1c02c53a..48f3a74a 100644
--- a/migrations/1728610007_updated_access.go
+++ b/migrations/1728610007_updated_access.go
@@ -11,7 +11,7 @@ import (
func init() {
m.Register(func(db dbx.Builder) error {
- dao := daos.New(db);
+ dao := daos.New(db)
collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
if err != nil {
@@ -50,7 +50,7 @@ func init() {
return dao.SaveCollection(collection)
}, func(db dbx.Builder) error {
- dao := daos.New(db);
+ dao := daos.New(db)
collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
if err != nil {
diff --git a/migrations/1729160433_updated_access.go b/migrations/1729160433_updated_access.go
index 22290d79..05e14cc0 100644
--- a/migrations/1729160433_updated_access.go
+++ b/migrations/1729160433_updated_access.go
@@ -11,7 +11,7 @@ import (
func init() {
m.Register(func(db dbx.Builder) error {
- dao := daos.New(db);
+ dao := daos.New(db)
collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
if err != nil {
@@ -51,7 +51,7 @@ func init() {
return dao.SaveCollection(collection)
}, func(db dbx.Builder) error {
- dao := daos.New(db);
+ dao := daos.New(db)
collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
if err != nil {
diff --git a/migrations/1729241998_updated_access.go b/migrations/1729241998_updated_access.go
index 65ac594e..cfa43c23 100644
--- a/migrations/1729241998_updated_access.go
+++ b/migrations/1729241998_updated_access.go
@@ -11,7 +11,7 @@ import (
func init() {
m.Register(func(db dbx.Builder) error {
- dao := daos.New(db);
+ dao := daos.New(db)
collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
if err != nil {
@@ -52,7 +52,7 @@ func init() {
return dao.SaveCollection(collection)
}, func(db dbx.Builder) error {
- dao := daos.New(db);
+ dao := daos.New(db)
collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
if err != nil {
diff --git a/migrations/1729339341_updated_access.go b/migrations/1729339341_updated_access.go
new file mode 100644
index 00000000..51561a76
--- /dev/null
+++ b/migrations/1729339341_updated_access.go
@@ -0,0 +1,98 @@
+package migrations
+
+import (
+ "encoding/json"
+
+ "github.com/pocketbase/dbx"
+ "github.com/pocketbase/pocketbase/daos"
+ m "github.com/pocketbase/pocketbase/migrations"
+ "github.com/pocketbase/pocketbase/models/schema"
+)
+
+func init() {
+ m.Register(func(db dbx.Builder) error {
+ dao := daos.New(db)
+
+ collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
+ if err != nil {
+ return err
+ }
+
+ // update
+ edit_configType := &schema.SchemaField{}
+ if err := json.Unmarshal([]byte(`{
+ "system": false,
+ "id": "hwy7m03o",
+ "name": "configType",
+ "type": "select",
+ "required": false,
+ "presentable": false,
+ "unique": false,
+ "options": {
+ "maxSelect": 1,
+ "values": [
+ "aliyun",
+ "tencent",
+ "huaweicloud",
+ "qiniu",
+ "aws",
+ "cloudflare",
+ "namesilo",
+ "godaddy",
+ "pdns",
+ "httpreq",
+ "local",
+ "ssh",
+ "webhook",
+ "k8s"
+ ]
+ }
+ }`), edit_configType); err != nil {
+ return err
+ }
+ collection.Schema.AddField(edit_configType)
+
+ return dao.SaveCollection(collection)
+ }, func(db dbx.Builder) error {
+ dao := daos.New(db)
+
+ collection, err := dao.FindCollectionByNameOrId("4yzbv8urny5ja1e")
+ if err != nil {
+ return err
+ }
+
+ // update
+ edit_configType := &schema.SchemaField{}
+ if err := json.Unmarshal([]byte(`{
+ "system": false,
+ "id": "hwy7m03o",
+ "name": "configType",
+ "type": "select",
+ "required": false,
+ "presentable": false,
+ "unique": false,
+ "options": {
+ "maxSelect": 1,
+ "values": [
+ "aliyun",
+ "tencent",
+ "huaweicloud",
+ "qiniu",
+ "aws",
+ "cloudflare",
+ "namesilo",
+ "godaddy",
+ "local",
+ "ssh",
+ "webhook",
+ "k8s"
+ ]
+ }
+ }`), edit_configType); err != nil {
+ return err
+ }
+ collection.Schema.AddField(edit_configType)
+
+ return dao.SaveCollection(collection)
+ })
+}
diff --git a/ui/dist/assets/index-YqBWA4KK.css b/ui/dist/assets/index-YqBWA4KK.css
deleted file mode 100644
index d169c0a5..00000000
--- a/ui/dist/assets/index-YqBWA4KK.css
+++ /dev/null
@@ -1 +0,0 @@
-*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}:root{--background: 0 0% 100%;--foreground: 20 14.3% 4.1%;--card: 0 0% 100%;--card-foreground: 20 14.3% 4.1%;--popover: 0 0% 100%;--popover-foreground: 20 14.3% 4.1%;--primary: 24.6 95% 53.1%;--primary-foreground: 60 9.1% 97.8%;--secondary: 60 4.8% 95.9%;--secondary-foreground: 24 9.8% 10%;--muted: 60 4.8% 95.9%;--muted-foreground: 25 5.3% 44.7%;--accent: 60 4.8% 95.9%;--accent-foreground: 24 9.8% 10%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 60 9.1% 97.8%;--border: 20 5.9% 90%;--input: 20 5.9% 90%;--ring: 24.6 95% 53.1%;--radius: .5rem;--chart-1: 12 76% 61%;--chart-2: 173 58% 39%;--chart-3: 197 37% 24%;--chart-4: 43 74% 66%;--chart-5: 27 87% 67%}.dark{--background: 20 14.3% 4.1%;--foreground: 60 9.1% 97.8%;--card: 20 14.3% 4.1%;--card-foreground: 60 9.1% 97.8%;--popover: 20 14.3% 4.1%;--popover-foreground: 60 9.1% 97.8%;--primary: 20.5 90.2% 48.2%;--primary-foreground: 60 9.1% 97.8%;--secondary: 12 6.5% 15.1%;--secondary-foreground: 60 9.1% 97.8%;--muted: 12 6.5% 15.1%;--muted-foreground: 24 5.4% 63.9%;--accent: 12 6.5% 15.1%;--accent-foreground: 60 9.1% 97.8%;--destructive: 0 72.2% 50.6%;--destructive-foreground: 60 9.1% 97.8%;--border: 12 6.5% 15.1%;--input: 12 6.5% 15.1%;--ring: 20.5 90.2% 48.2%;--chart-1: 220 70% 50%;--chart-2: 160 60% 45%;--chart-3: 30 80% 55%;--chart-4: 280 65% 60%;--chart-5: 340 75% 55%}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%;margin-right:auto;margin-left:auto;padding-right:2rem;padding-left:2rem}@media (min-width: 1400px){.container{max-width:1400px}}@media (min-width: 1920px){.container{max-width:1920px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.left-0{left:0}.left-2{left:.5rem}.left-\[50\%\]{left:50%}.right-0{right:0}.right-2{right:.5rem}.right-4{right:1rem}.top-0{top:0}.top-2{top:.5rem}.top-4{top:1rem}.top-\[1px\]{top:1px}.top-\[50\%\]{top:50%}.top-\[60\%\]{top:60%}.top-full{top:100%}.z-10{z-index:10}.z-50{z-index:50}.z-\[100\]{z-index:100}.z-\[1\]{z-index:1}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-\[-0\.65rem\]{margin-left:-.65rem;margin-right:-.65rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-4{margin-top:1rem;margin-bottom:1rem}.mb-1{margin-bottom:.25rem}.mb-10{margin-bottom:2.5rem}.mb-3{margin-bottom:.75rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-20{margin-top:5rem}.mt-24{margin-top:6rem}.mt-3{margin-top:.75rem}.mt-32{margin-top:8rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-7{margin-top:1.75rem}.mt-auto{margin-top:auto}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[1\.2rem\]{height:1.2rem}.h-\[1px\]{height:1px}.h-\[36px\]{height:36px}.h-\[75vh\]{height:75vh}.h-\[80dvh\]{height:80dvh}.h-\[80vh\]{height:80vh}.h-\[var\(--radix-navigation-menu-viewport-height\)\]{height:var(--radix-navigation-menu-viewport-height)}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.max-h-96{max-height:24rem}.max-h-\[80vh\]{max-height:80vh}.max-h-screen{max-height:100vh}.min-h-\[180px\]{min-height:180px}.min-h-\[80px\]{min-height:80px}.min-h-screen{min-height:100vh}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-24{width:6rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-3\/4{width:75%}.w-32{width:8rem}.w-36{width:9rem}.w-4{width:1rem}.w-40{width:10rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-56{width:14rem}.w-6{width:1.5rem}.w-60{width:15rem}.w-64{width:16rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[1\.2rem\]{width:1.2rem}.w-\[100px\]{width:100px}.w-\[1px\]{width:1px}.w-\[36px\]{width:36px}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.min-w-\[8rem\]{min-width:8rem}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.max-w-\[35em\]{max-width:35em}.max-w-\[40em\]{max-width:40em}.max-w-\[60px\]{max-width:60px}.max-w-lg{max-width:32rem}.max-w-max{max-width:-moz-max-content;max-width:max-content}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.caption-bottom{caption-side:bottom}.translate-x-\[-50\%\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[-50\%\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-0{--tw-rotate: 0deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-45{--tw-rotate: 45deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-0{--tw-scale-x: 0;--tw-scale-y: 0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.list-none{list-style-type:none}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.75rem * var(--tw-space-x-reverse));margin-left:calc(.75rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-5>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1.25rem * var(--tw-space-x-reverse));margin-left:calc(1.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(0px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-hidden{overflow-y:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.text-nowrap{text-wrap:nowrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-\[inherit\]{border-radius:inherit}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:.75rem}.rounded-t-\[10px\]{border-top-left-radius:10px;border-top-right-radius:10px}.rounded-tl-sm{border-top-left-radius:calc(var(--radius) - 4px)}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-destructive{border-color:hsl(var(--destructive))}.border-destructive\/50{border-color:hsl(var(--destructive) / .5)}.border-input{border-color:hsl(var(--input))}.border-primary{border-color:hsl(var(--primary))}.border-transparent{border-color:transparent}.border-l-transparent{border-left-color:transparent}.border-t-transparent{border-top-color:transparent}.bg-background{background-color:hsl(var(--background))}.bg-black\/80{background-color:#000c}.bg-border{background-color:hsl(var(--border))}.bg-card{background-color:hsl(var(--card))}.bg-destructive{background-color:hsl(var(--destructive))}.bg-gray-950{--tw-bg-opacity: 1;background-color:rgb(3 7 18 / var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity))}.bg-muted{background-color:hsl(var(--muted))}.bg-muted\/40{background-color:hsl(var(--muted) / .4)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-orange-100{--tw-bg-opacity: 1;background-color:rgb(255 237 213 / var(--tw-bg-opacity))}.bg-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-secondary{background-color:hsl(var(--secondary))}.bg-transparent{background-color:transparent}.fill-current{fill:currentColor}.p-0{padding:0}.p-1{padding:.25rem}.p-10{padding:2.5rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-\[1px\]{padding:1px}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-4{padding-bottom:1rem}.pl-2\.5{padding-left:.625rem}.pl-8{padding-left:2rem}.pr-2{padding-right:.5rem}.pr-2\.5{padding-right:.625rem}.pr-8{padding-right:2rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-5{padding-top:1.25rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.leading-none{line-height:1}.tracking-tight{letter-spacing:-.025em}.tracking-widest{letter-spacing:.1em}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-current{color:currentColor}.text-destructive{color:hsl(var(--destructive))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-foreground{color:hsl(var(--foreground))}.text-foreground\/50{color:hsl(var(--foreground) / .5)}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-stone-100{--tw-text-opacity: 1;color:rgb(245 245 244 / var(--tw-text-opacity))}.text-stone-600{--tw-text-opacity: 1;color:rgb(87 83 78 / var(--tw-text-opacity))}.text-stone-700{--tw-text-opacity: 1;color:rgb(68 64 60 / var(--tw-text-opacity))}.text-yellow-400{--tw-text-opacity: 1;color:rgb(250 204 21 / var(--tw-text-opacity))}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-90{opacity:.9}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-0{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background))}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.animate-in{animation-name:enter;animation-duration:.15s;--tw-enter-opacity: initial;--tw-enter-scale: initial;--tw-enter-rotate: initial;--tw-enter-translate-x: initial;--tw-enter-translate-y: initial}.fade-in-0{--tw-enter-opacity: 0}.zoom-in-95{--tw-enter-scale: .95}.duration-200{animation-duration:.2s}.ease-in-out{animation-timing-function:cubic-bezier(.4,0,.2,1)}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-destructive\/80:hover{background-color:hsl(var(--destructive) / .8)}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-primary\/80:hover{background-color:hsl(var(--primary) / .8)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary:hover{background-color:hsl(var(--secondary))}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-primary:hover{color:hsl(var(--primary))}.hover\:text-stone-900:hover{--tw-text-opacity: 1;color:rgb(28 25 23 / var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:bg-accent:focus{background-color:hsl(var(--accent))}.focus\:text-accent-foreground:focus{color:hsl(var(--accent-foreground))}.focus\:opacity-100:focus{opacity:1}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.focus-visible\:ring-offset-background:focus-visible{--tw-ring-offset-color: hsl(var(--background))}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:opacity-100{opacity:1}.group.destructive .group-\[\.destructive\]\:border-muted\/40{border-color:hsl(var(--muted) / .4)}.group.destructive .group-\[\.destructive\]\:text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity))}.group.destructive .group-\[\.destructive\]\:hover\:border-destructive\/30:hover{border-color:hsl(var(--destructive) / .3)}.group.destructive .group-\[\.destructive\]\:hover\:bg-destructive:hover{background-color:hsl(var(--destructive))}.group.destructive .group-\[\.destructive\]\:hover\:text-destructive-foreground:hover{color:hsl(var(--destructive-foreground))}.group.destructive .group-\[\.destructive\]\:hover\:text-red-50:hover{--tw-text-opacity: 1;color:rgb(254 242 242 / var(--tw-text-opacity))}.group.destructive .group-\[\.destructive\]\:focus\:ring-destructive:focus{--tw-ring-color: hsl(var(--destructive))}.group.destructive .group-\[\.destructive\]\:focus\:ring-red-400:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(248 113 113 / var(--tw-ring-opacity))}.group.destructive .group-\[\.destructive\]\:focus\:ring-offset-red-600:focus{--tw-ring-offset-color: #dc2626}.peer:disabled~.peer-disabled\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\:opacity-70{opacity:.7}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=checked\]\:translate-x-5[data-state=checked]{--tw-translate-x: 1.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=unchecked\]\:translate-x-0[data-state=unchecked],.data-\[swipe\=cancel\]\:translate-x-0[data-swipe=cancel]{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[swipe\=end\]\:translate-x-\[var\(--radix-toast-swipe-end-x\)\][data-swipe=end]{--tw-translate-x: var(--radix-toast-swipe-end-x);transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[swipe\=move\]\:translate-x-\[var\(--radix-toast-swipe-move-x\)\][data-swipe=move]{--tw-translate-x: var(--radix-toast-swipe-move-x);transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes accordion-up{0%{height:var(--radix-accordion-content-height)}to{height:0}}.data-\[state\=closed\]\:animate-accordion-up[data-state=closed]{animation:accordion-up .2s ease-out}@keyframes collapsible-up{0%{height:var(--radix-collapsible-content-height)}to{height:0}}.data-\[state\=closed\]\:animate-collapsible-up[data-state=closed]{animation:collapsible-up .2s ease-out}@keyframes accordion-down{0%{height:0}to{height:var(--radix-accordion-content-height)}}.data-\[state\=open\]\:animate-accordion-down[data-state=open]{animation:accordion-down .2s ease-out}@keyframes collapsible-down{0%{height:0}to{height:var(--radix-collapsible-content-height)}}.data-\[state\=open\]\:animate-collapsible-down[data-state=open]{animation:collapsible-down .2s ease-out}.data-\[active\]\:bg-accent\/50[data-active]{background-color:hsl(var(--accent) / .5)}.data-\[state\=active\]\:bg-background[data-state=active]{background-color:hsl(var(--background))}.data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:hsl(var(--primary))}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:hsl(var(--accent))}.data-\[state\=open\]\:bg-accent\/50[data-state=open]{background-color:hsl(var(--accent) / .5)}.data-\[state\=open\]\:bg-secondary[data-state=open]{background-color:hsl(var(--secondary))}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:hsl(var(--muted))}.data-\[state\=unchecked\]\:bg-input[data-state=unchecked]{background-color:hsl(var(--input))}.data-\[state\=active\]\:text-foreground[data-state=active]{color:hsl(var(--foreground))}.data-\[state\=open\]\:text-muted-foreground[data-state=open]{color:hsl(var(--muted-foreground))}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[state\=active\]\:shadow-sm[data-state=active]{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\[swipe\=move\]\:transition-none[data-swipe=move]{transition-property:none}.data-\[state\=closed\]\:duration-300[data-state=closed]{transition-duration:.3s}.data-\[state\=open\]\:duration-500[data-state=open]{transition-duration:.5s}.data-\[motion\^\=from-\]\:animate-in[data-motion^=from-],.data-\[state\=open\]\:animate-in[data-state=open],.data-\[state\=visible\]\:animate-in[data-state=visible]{animation-name:enter;animation-duration:.15s;--tw-enter-opacity: initial;--tw-enter-scale: initial;--tw-enter-rotate: initial;--tw-enter-translate-x: initial;--tw-enter-translate-y: initial}.data-\[motion\^\=to-\]\:animate-out[data-motion^=to-],.data-\[state\=closed\]\:animate-out[data-state=closed],.data-\[state\=hidden\]\:animate-out[data-state=hidden],.data-\[swipe\=end\]\:animate-out[data-swipe=end]{animation-name:exit;animation-duration:.15s;--tw-exit-opacity: initial;--tw-exit-scale: initial;--tw-exit-rotate: initial;--tw-exit-translate-x: initial;--tw-exit-translate-y: initial}.data-\[motion\^\=from-\]\:fade-in[data-motion^=from-]{--tw-enter-opacity: 0}.data-\[motion\^\=to-\]\:fade-out[data-motion^=to-],.data-\[state\=closed\]\:fade-out-0[data-state=closed]{--tw-exit-opacity: 0}.data-\[state\=closed\]\:fade-out-80[data-state=closed]{--tw-exit-opacity: .8}.data-\[state\=hidden\]\:fade-out[data-state=hidden]{--tw-exit-opacity: 0}.data-\[state\=open\]\:fade-in-0[data-state=open],.data-\[state\=visible\]\:fade-in[data-state=visible]{--tw-enter-opacity: 0}.data-\[state\=closed\]\:zoom-out-95[data-state=closed]{--tw-exit-scale: .95}.data-\[state\=open\]\:zoom-in-90[data-state=open]{--tw-enter-scale: .9}.data-\[state\=open\]\:zoom-in-95[data-state=open]{--tw-enter-scale: .95}.data-\[motion\=from-end\]\:slide-in-from-right-52[data-motion=from-end]{--tw-enter-translate-x: 13rem}.data-\[motion\=from-start\]\:slide-in-from-left-52[data-motion=from-start]{--tw-enter-translate-x: -13rem}.data-\[motion\=to-end\]\:slide-out-to-right-52[data-motion=to-end]{--tw-exit-translate-x: 13rem}.data-\[motion\=to-start\]\:slide-out-to-left-52[data-motion=to-start]{--tw-exit-translate-x: -13rem}.data-\[side\=bottom\]\:slide-in-from-top-2[data-side=bottom]{--tw-enter-translate-y: -.5rem}.data-\[side\=left\]\:slide-in-from-right-2[data-side=left]{--tw-enter-translate-x: .5rem}.data-\[side\=right\]\:slide-in-from-left-2[data-side=right]{--tw-enter-translate-x: -.5rem}.data-\[side\=top\]\:slide-in-from-bottom-2[data-side=top]{--tw-enter-translate-y: .5rem}.data-\[state\=closed\]\:slide-out-to-bottom[data-state=closed]{--tw-exit-translate-y: 100%}.data-\[state\=closed\]\:slide-out-to-left[data-state=closed]{--tw-exit-translate-x: -100%}.data-\[state\=closed\]\:slide-out-to-left-1\/2[data-state=closed]{--tw-exit-translate-x: -50%}.data-\[state\=closed\]\:slide-out-to-right[data-state=closed],.data-\[state\=closed\]\:slide-out-to-right-full[data-state=closed]{--tw-exit-translate-x: 100%}.data-\[state\=closed\]\:slide-out-to-top[data-state=closed]{--tw-exit-translate-y: -100%}.data-\[state\=closed\]\:slide-out-to-top-\[48\%\][data-state=closed]{--tw-exit-translate-y: -48%}.data-\[state\=open\]\:slide-in-from-bottom[data-state=open]{--tw-enter-translate-y: 100%}.data-\[state\=open\]\:slide-in-from-left[data-state=open]{--tw-enter-translate-x: -100%}.data-\[state\=open\]\:slide-in-from-left-1\/2[data-state=open]{--tw-enter-translate-x: -50%}.data-\[state\=open\]\:slide-in-from-right[data-state=open]{--tw-enter-translate-x: 100%}.data-\[state\=open\]\:slide-in-from-top[data-state=open]{--tw-enter-translate-y: -100%}.data-\[state\=open\]\:slide-in-from-top-\[48\%\][data-state=open]{--tw-enter-translate-y: -48%}.data-\[state\=open\]\:slide-in-from-top-full[data-state=open]{--tw-enter-translate-y: -100%}.data-\[state\=closed\]\:duration-300[data-state=closed]{animation-duration:.3s}.data-\[state\=open\]\:duration-500[data-state=open]{animation-duration:.5s}.group[data-state=open] .group-data-\[state\=open\]\:rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:-rotate-90:is(.dark *){--tw-rotate: -90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:rotate-0:is(.dark *){--tw-rotate: 0deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:scale-0:is(.dark *){--tw-scale-x: 0;--tw-scale-y: 0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:scale-100:is(.dark *){--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.dark\:border-destructive:is(.dark *){border-color:hsl(var(--destructive))}.dark\:border-stone-200:is(.dark *){--tw-border-opacity: 1;border-color:rgb(231 229 228 / var(--tw-border-opacity))}.dark\:border-stone-400:is(.dark *){--tw-border-opacity: 1;border-color:rgb(168 162 158 / var(--tw-border-opacity))}.dark\:border-stone-500:is(.dark *){--tw-border-opacity: 1;border-color:rgb(120 113 108 / var(--tw-border-opacity))}.dark\:border-stone-700:is(.dark *){--tw-border-opacity: 1;border-color:rgb(68 64 60 / var(--tw-border-opacity))}.dark\:bg-stone-950:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(12 10 9 / var(--tw-bg-opacity))}.dark\:text-gray-200:is(.dark *){--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity))}.dark\:text-stone-200:is(.dark *){--tw-text-opacity: 1;color:rgb(231 229 228 / var(--tw-text-opacity))}.dark\:text-white:is(.dark *){--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:hover\:text-stone-200:hover:is(.dark *){--tw-text-opacity: 1;color:rgb(231 229 228 / var(--tw-text-opacity))}@media (min-width: 640px){.sm\:bottom-0{bottom:0}.sm\:right-0{right:0}.sm\:top-auto{top:auto}.sm\:ml-2{margin-left:.5rem}.sm\:mt-0{margin-top:0}.sm\:flex{display:flex}.sm\:w-24{width:6rem}.sm\:w-32{width:8rem}.sm\:w-36{width:9rem}.sm\:w-40{width:10rem}.sm\:w-48{width:12rem}.sm\:w-56{width:14rem}.sm\:w-60{width:15rem}.sm\:w-64{width:16rem}.sm\:max-w-5xl{max-width:64rem}.sm\:max-w-\[600px\]{max-width:600px}.sm\:max-w-sm{max-width:24rem}.sm\:flex-row{flex-direction:row}.sm\:flex-col{flex-direction:column}.sm\:justify-end{justify-content:flex-end}.sm\:justify-center{justify-content:center}.sm\:gap-2\.5{gap:.625rem}.sm\:space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.sm\:rounded-lg{border-radius:var(--radius)}.sm\:p-2{padding:.5rem}.sm\:pt-0{padding-top:0}.sm\:text-left{text-align:left}.data-\[state\=open\]\:sm\:slide-in-from-bottom-full[data-state=open]{--tw-enter-translate-y: 100%}}@media (min-width: 768px){.md\:absolute{position:absolute}.md\:mt-0{margin-top:0}.md\:mt-5{margin-top:1.25rem}.md\:block{display:block}.md\:hidden{display:none}.md\:w-\[200px\]{width:200px}.md\:w-\[250px\]{width:250px}.md\:w-\[350px\]{width:350px}.md\:w-\[35em\]{width:35em}.md\:w-\[45em\]{width:45em}.md\:w-\[var\(--radix-navigation-menu-viewport-width\)\]{width:var(--radix-navigation-menu-viewport-width)}.md\:w-auto{width:auto}.md\:max-w-\[35em\]{max-width:35em}.md\:max-w-\[420px\]{max-width:420px}.md\:grid-cols-\[180px_1fr\]{grid-template-columns:180px 1fr}.md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:space-x-10>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(2.5rem * var(--tw-space-x-reverse));margin-left:calc(2.5rem * calc(1 - var(--tw-space-x-reverse)))}.md\:space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.md\:p-3{padding:.75rem}}@media (min-width: 1024px){.lg\:h-\[60px\]{height:60px}.lg\:grid-cols-\[200px_1fr\]{grid-template-columns:200px 1fr}.lg\:gap-6{gap:1.5rem}.lg\:p-6{padding:1.5rem}.lg\:px-4{padding-left:1rem;padding-right:1rem}.lg\:px-6{padding-left:1.5rem;padding-right:1.5rem}}@media (min-width: 1536px){@media (min-width: 768px){.\32xl\:md\:grid-cols-\[280px_1fr\]{grid-template-columns:280px 1fr}}}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&\>span\]\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\[\&\>svg\+div\]\:translate-y-\[-3px\]>svg+div{--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>svg\]\:absolute>svg{position:absolute}.\[\&\>svg\]\:left-4>svg{left:1rem}.\[\&\>svg\]\:top-4>svg{top:1rem}.\[\&\>svg\]\:size-3\.5>svg{width:.875rem;height:.875rem}.\[\&\>svg\]\:text-destructive>svg{color:hsl(var(--destructive))}.\[\&\>svg\]\:text-foreground>svg{color:hsl(var(--foreground))}.\[\&\>svg\~\*\]\:pl-7>svg~*{padding-left:1.75rem}.\[\&\>tr\]\:last\:border-b-0:last-child>tr{border-bottom-width:0px}.\[\&\[data-state\=open\]\>svg\]\:rotate-180[data-state=open]>svg{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&_p\]\:leading-relaxed p{line-height:1.625}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0px}.\[\&_tr\]\:border-b tr{border-bottom-width:1px}
diff --git a/ui/dist/imgs/providers/aliyun.svg b/ui/dist/imgs/providers/aliyun.svg
deleted file mode 100644
index 7d0b70e0..00000000
--- a/ui/dist/imgs/providers/aliyun.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/aws.svg b/ui/dist/imgs/providers/aws.svg
deleted file mode 100644
index 9f211f19..00000000
--- a/ui/dist/imgs/providers/aws.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/cloudflare.svg b/ui/dist/imgs/providers/cloudflare.svg
deleted file mode 100644
index b6f07b50..00000000
--- a/ui/dist/imgs/providers/cloudflare.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/godaddy.svg b/ui/dist/imgs/providers/godaddy.svg
deleted file mode 100644
index a859a7ae..00000000
--- a/ui/dist/imgs/providers/godaddy.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/huaweicloud.svg b/ui/dist/imgs/providers/huaweicloud.svg
deleted file mode 100644
index 552e59e7..00000000
--- a/ui/dist/imgs/providers/huaweicloud.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/k8s.svg b/ui/dist/imgs/providers/k8s.svg
deleted file mode 100644
index b7f555f7..00000000
--- a/ui/dist/imgs/providers/k8s.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/letsencrypt.svg b/ui/dist/imgs/providers/letsencrypt.svg
deleted file mode 100644
index 3a6c2312..00000000
--- a/ui/dist/imgs/providers/letsencrypt.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/local.svg b/ui/dist/imgs/providers/local.svg
deleted file mode 100644
index 2f59af07..00000000
--- a/ui/dist/imgs/providers/local.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/namesilo.svg b/ui/dist/imgs/providers/namesilo.svg
deleted file mode 100644
index e0cc8da4..00000000
--- a/ui/dist/imgs/providers/namesilo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/qiniu.svg b/ui/dist/imgs/providers/qiniu.svg
deleted file mode 100644
index d3b98877..00000000
--- a/ui/dist/imgs/providers/qiniu.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/ssh.svg b/ui/dist/imgs/providers/ssh.svg
deleted file mode 100644
index 8dea9e89..00000000
--- a/ui/dist/imgs/providers/ssh.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/tencent.svg b/ui/dist/imgs/providers/tencent.svg
deleted file mode 100644
index 76e54dbb..00000000
--- a/ui/dist/imgs/providers/tencent.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/webhook.svg b/ui/dist/imgs/providers/webhook.svg
deleted file mode 100644
index 2ca5bff3..00000000
--- a/ui/dist/imgs/providers/webhook.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/imgs/providers/zerossl.svg b/ui/dist/imgs/providers/zerossl.svg
deleted file mode 100644
index 8563aece..00000000
--- a/ui/dist/imgs/providers/zerossl.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui/dist/vite.svg b/ui/dist/vite.svg
deleted file mode 100644
index 2d1e68d6..00000000
--- a/ui/dist/vite.svg
+++ /dev/null
@@ -1,28 +0,0 @@
-
\ No newline at end of file
diff --git a/ui/public/imgs/providers/httpreq.svg b/ui/public/imgs/providers/httpreq.svg
new file mode 100644
index 00000000..621de609
--- /dev/null
+++ b/ui/public/imgs/providers/httpreq.svg
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/public/imgs/providers/pdns.svg b/ui/public/imgs/providers/pdns.svg
new file mode 100644
index 00000000..39a111e7
--- /dev/null
+++ b/ui/public/imgs/providers/pdns.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/src/components/certimate/AccessEdit.tsx b/ui/src/components/certimate/AccessEdit.tsx
index c49bad72..6d589cee 100644
--- a/ui/src/components/certimate/AccessEdit.tsx
+++ b/ui/src/components/certimate/AccessEdit.tsx
@@ -14,6 +14,8 @@ import AccessAwsForm from "./AccessAwsForm";
import AccessCloudflareForm from "./AccessCloudflareForm";
import AccessNamesiloForm from "./AccessNamesiloForm";
import AccessGodaddyForm from "./AccessGodaddyForm";
+import AccessPdnsForm from "./AccessPdnsForm";
+import AccessHttpreqForm from "./AccessHttpreqForm";
import AccessLocalForm from "./AccessLocalForm";
import AccessSSHForm from "./AccessSSHForm";
import AccessWebhookForm from "./AccessWebhookForm";
@@ -125,6 +127,28 @@ const AccessEdit = ({ trigger, op, data, className }: AccessEditProps) => {
/>
);
break;
+ case "pdns":
+ form = (
+ {
+ setOpen(false);
+ }}
+ />
+ );
+ break;
+ case "httpreq":
+ form = (
+ {
+ setOpen(false);
+ }}
+ />
+ );
+ break;
case "local":
form = (
void;
+};
+
+const AccessHttpreqForm = ({ data, op, onAfterReq }: AccessHttpreqFormProps) => {
+ const { addAccess, updateAccess } = useConfig();
+ const { t } = useTranslation();
+ const formSchema = z.object({
+ id: z.string().optional(),
+ name: z
+ .string()
+ .min(1, "access.authorization.form.name.placeholder")
+ .max(64, t("common.errmsg.string_max", { max: 64 })),
+ configType: accessFormType,
+ endpoint: z.string().url("common.errmsg.url_invalid"),
+ mode: z
+ .enum(["RAW", ""]),
+ username: z
+ .string()
+ .min(1, "access.authorization.form.access_key_secret.placeholder")
+ .max(128, t("common.errmsg.string_max", { max: 128 })),
+ password: z
+ .string()
+ .min(1, "access.authorization.form.access_key_secret.placeholder")
+ .max(128, t("common.errmsg.string_max", { max: 128 })),
+ });
+
+ let config: HttpreqConfig = {
+ endpoint: "",
+ mode: "",
+ username: "",
+ password: "",
+ };
+ if (data) config = data.config as HttpreqConfig;
+
+ const form = useForm>({
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ id: data?.id,
+ name: data?.name || "",
+ configType: "httpreq",
+ endpoint: config.endpoint,
+ mode: config.mode === "RAW" ? "RAW" : "",
+ username: config.username,
+ password: config.password,
+ },
+ });
+
+ const onSubmit = async (data: z.infer) => {
+ const req: Access = {
+ id: data.id as string,
+ name: data.name,
+ configType: data.configType,
+ usage: getUsageByConfigType(data.configType),
+ config: {
+ endpoint: data.endpoint,
+ mode: data.mode,
+ username: data.username,
+ password: data.password,
+ },
+ };
+
+ try {
+ req.id = op == "copy" ? "" : req.id;
+ const rs = await save(req);
+
+ onAfterReq();
+
+ req.id = rs.id;
+ req.created = rs.created;
+ req.updated = rs.updated;
+ if (data.id && op == "edit") {
+ updateAccess(req);
+ return;
+ }
+
+ addAccess(req);
+ } catch (e) {
+ const err = e as ClientResponseError;
+
+ Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
+ form.setError(key as keyof z.infer, {
+ type: "manual",
+ message: value.message,
+ });
+ });
+
+ return;
+ }
+ };
+ const i18n_prefix = "access.authorization.form.httpreq";
+ return (
+ <>
+
+ >
+ );
+};
+
+export default AccessHttpreqForm;
+
diff --git a/ui/src/components/certimate/AccessPdnsForm.tsx b/ui/src/components/certimate/AccessPdnsForm.tsx
new file mode 100644
index 00000000..a3c0813f
--- /dev/null
+++ b/ui/src/components/certimate/AccessPdnsForm.tsx
@@ -0,0 +1,195 @@
+import { useForm } from "react-hook-form";
+import { useTranslation } from "react-i18next";
+import z from "zod";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { ClientResponseError } from "pocketbase";
+
+import { Button } from "@/components/ui/button";
+import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
+import { Input } from "@/components/ui/input";
+import { PbErrorData } from "@/domain/base";
+import { Access, PdnsConfig, accessFormType, getUsageByConfigType } from "@/domain/access";
+import { save } from "@/repository/access";
+import { useConfig } from "@/providers/config";
+
+type AccessPdnsFormProps = {
+ op: "add" | "edit" | "copy";
+ data?: Access;
+ onAfterReq: () => void;
+};
+
+const AccessPdnsForm = ({ data, op, onAfterReq }: AccessPdnsFormProps) => {
+ const { addAccess, updateAccess } = useConfig();
+ const { t } = useTranslation();
+ const formSchema = z.object({
+ id: z.string().optional(),
+ name: z
+ .string()
+ .min(1, "access.authorization.form.name.placeholder")
+ .max(64, t("common.errmsg.string_max", { max: 64 })),
+ configType: accessFormType,
+ apiUrl: z.string().url("common.errmsg.url_invalid"),
+ apiKey: z
+ .string()
+ .min(1, "access.authorization.form.access_key_secret.placeholder")
+ .max(64, t("common.errmsg.string_max", { max: 64 })),
+ });
+
+ let config: PdnsConfig = {
+ apiUrl: "",
+ apiKey: "",
+ };
+ if (data) config = data.config as PdnsConfig;
+
+ const form = useForm>({
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ id: data?.id,
+ name: data?.name || "",
+ configType: "pdns",
+ apiUrl: config.apiUrl,
+ apiKey: config.apiKey,
+ },
+ });
+
+ const onSubmit = async (data: z.infer) => {
+ const req: Access = {
+ id: data.id as string,
+ name: data.name,
+ configType: data.configType,
+ usage: getUsageByConfigType(data.configType),
+ config: {
+ apiUrl: data.apiUrl,
+ apiKey: data.apiKey,
+ },
+ };
+
+ try {
+ req.id = op == "copy" ? "" : req.id;
+ const rs = await save(req);
+
+ onAfterReq();
+
+ req.id = rs.id;
+ req.created = rs.created;
+ req.updated = rs.updated;
+ if (data.id && op == "edit") {
+ updateAccess(req);
+ return;
+ }
+
+ addAccess(req);
+ } catch (e) {
+ const err = e as ClientResponseError;
+
+ Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
+ form.setError(key as keyof z.infer, {
+ type: "manual",
+ message: value.message,
+ });
+ });
+
+ return;
+ }
+ };
+
+ return (
+ <>
+
+ >
+ );
+};
+
+export default AccessPdnsForm;
+
diff --git a/ui/src/components/certimate/DeployList.tsx b/ui/src/components/certimate/DeployList.tsx
index b3a1b62e..6c3caf71 100644
--- a/ui/src/components/certimate/DeployList.tsx
+++ b/ui/src/components/certimate/DeployList.tsx
@@ -326,7 +326,7 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro
{trigger}
- {t("history.page.title")}
+ {t("domain.deployment.tab")}
@@ -889,3 +889,4 @@ const DeployToKubernetes = () => {
>
);
};
+
diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts
index 9462fad1..988374b8 100644
--- a/ui/src/domain/access.ts
+++ b/ui/src/domain/access.ts
@@ -9,6 +9,8 @@ export const accessTypeMap: Map = new Map([
["cloudflare", ["common.provider.cloudflare", "/imgs/providers/cloudflare.svg"]],
["namesilo", ["common.provider.namesilo", "/imgs/providers/namesilo.svg"]],
["godaddy", ["common.provider.godaddy", "/imgs/providers/godaddy.svg"]],
+ ["pdns", ["common.provider.pdns", "/imgs/providers/pdns.svg"]],
+ ["httpreq", ["common.provider.httpreq", "/imgs/providers/httpreq.svg"]],
["local", ["common.provider.local", "/imgs/providers/local.svg"]],
["ssh", ["common.provider.ssh", "/imgs/providers/ssh.svg"]],
["webhook", ["common.provider.webhook", "/imgs/providers/webhook.svg"]],
@@ -29,6 +31,8 @@ export const accessFormType = z.union(
z.literal("cloudflare"),
z.literal("namesilo"),
z.literal("godaddy"),
+ z.literal("pdns"),
+ z.literal("httpreq"),
z.literal("local"),
z.literal("ssh"),
z.literal("webhook"),
@@ -54,6 +58,8 @@ export type Access = {
| CloudflareConfig
| NamesiloConfig
| GodaddyConfig
+ | PdnsConfig
+ | HttpreqConfig
| LocalConfig
| SSHConfig
| WebhookConfig
@@ -104,6 +110,18 @@ export type GodaddyConfig = {
apiSecret: string;
};
+export type PdnsConfig = {
+ apiUrl: string;
+ apiKey: string;
+};
+
+export type HttpreqConfig = {
+ endpoint: string;
+ mode: string;
+ username: string;
+ password: string;
+};
+
export type LocalConfig = Record;
export type SSHConfig = {
@@ -142,6 +160,8 @@ export const getUsageByConfigType = (configType: string): AccessUsage => {
case "cloudflare":
case "namesilo":
case "godaddy":
+ case "pdns":
+ case "httpreq":
return "apply";
default:
diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json
index de48aa2a..15ae27ca 100644
--- a/ui/src/i18n/locales/en/nls.access.json
+++ b/ui/src/i18n/locales/en/nls.access.json
@@ -38,6 +38,14 @@
"access.authorization.form.godaddy_api_key.placeholder": "Please enter GO_DADDY_API_KEY",
"access.authorization.form.godaddy_api_secret.label": "GO_DADDY_API_SECRET",
"access.authorization.form.godaddy_api_secret.placeholder": "Please enter GO_DADDY_API_SECRET",
+ "access.authorization.form.pdns_api_url.label": "PDNS_API_URL",
+ "access.authorization.form.pdns_api_url.placeholder": "Please enter PDNS_API_URL",
+ "access.authorization.form.pdns_api_key.label": "PDNS_API_KEY",
+ "access.authorization.form.pdns_api_key.placeholder": "Please enter PDNS_API_KEY",
+ "access.authorization.form.httpreq_endpoint.label": "HTTPREQ_ENDPOINT",
+ "access.authorization.form.httpreq_endpoint.placeholder": "Please enter HTTPREQ_ENDPOINT",
+ "access.authorization.form.httpreq_mode.label": "HTTPREQ_MODE",
+ "access.authorization.form.httpreq_mode.placeholder": "Please enter HTTPREQ_MODE(RAW or '')",
"access.authorization.form.namesilo_api_key.label": "NAMESILO_API_KEY",
"access.authorization.form.namesilo_api_key.placeholder": "Please enter NAMESILO_API_KEY",
"access.authorization.form.username.label": "Username",
diff --git a/ui/src/i18n/locales/en/nls.common.json b/ui/src/i18n/locales/en/nls.common.json
index 8fa0aab0..358639e0 100644
--- a/ui/src/i18n/locales/en/nls.common.json
+++ b/ui/src/i18n/locales/en/nls.common.json
@@ -66,6 +66,8 @@
"common.provider.cloudflare": "Cloudflare",
"common.provider.namesilo": "Namesilo",
"common.provider.godaddy": "GoDaddy",
+ "common.provider.pdns": "PowerDNS",
+ "common.provider.httpreq": "Http Request",
"common.provider.local": "Local Deployment",
"common.provider.ssh": "SSH Deployment",
"common.provider.webhook": "Webhook",
diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json
index df0b2fa2..70e2074f 100644
--- a/ui/src/i18n/locales/zh/nls.access.json
+++ b/ui/src/i18n/locales/zh/nls.access.json
@@ -39,6 +39,14 @@
"access.authorization.form.godaddy_api_secret.label": "GO_DADDY_API_SECRET",
"access.authorization.form.godaddy_api_secret.placeholder": "请输入 GO_DADDY_API_SECRET",
"access.authorization.form.namesilo_api_key.label": "NAMESILO_API_KEY",
+ "access.authorization.form.pdns_api_url.label": "PDNS_API_URL",
+ "access.authorization.form.pdns_api_url.placeholder": "请输入 PDNS_API_URL",
+ "access.authorization.form.pdns_api_key.label": "PDNS_API_KEY",
+ "access.authorization.form.pdns_api_key.placeholder": "请输入 PDNS_API_KEY",
+ "access.authorization.form.httpreq_endpoint.label": "HTTP 请求端点",
+ "access.authorization.form.httpreq_endpoint.placeholder": "请输入 请求端点",
+ "access.authorization.form.httpreq_mode.label": "模式",
+ "access.authorization.form.httpreq_mode.placeholder": "请输入模式( RAW or '')",
"access.authorization.form.namesilo_api_key.placeholder": "请输入 NAMESILO_API_KEY",
"access.authorization.form.username.label": "用户名",
"access.authorization.form.username.placeholder": "请输入用户名",
diff --git a/ui/src/i18n/locales/zh/nls.common.json b/ui/src/i18n/locales/zh/nls.common.json
index 2568b23e..f6179636 100644
--- a/ui/src/i18n/locales/zh/nls.common.json
+++ b/ui/src/i18n/locales/zh/nls.common.json
@@ -66,6 +66,8 @@
"common.provider.cloudflare": "Cloudflare",
"common.provider.namesilo": "Namesilo",
"common.provider.godaddy": "GoDaddy",
+ "common.provider.pdns": "PowerDNS",
+ "common.provider.httpreq": "Http Request",
"common.provider.local": "本地部署",
"common.provider.ssh": "SSH 部署",
"common.provider.webhook": "Webhook",
@@ -75,3 +77,4 @@
"common.provider.telegram": "Telegram",
"common.provider.lark": "飞书"
}
+