Compare commits

...

9 Commits

Author SHA1 Message Date
RHQYZ
bc69ab43f5
Merge 94408e8a9f51e20bfebcdae9feae8d0c6f3526f9 into 1f6b33f4f6a3c2ed758a1294e5d51505394a90ec 2025-02-11 11:32:01 +00:00
Fu Diwei
94408e8a9f refactor: clean code 2025-02-11 19:31:24 +08:00
Fu Diwei
f3c7d096bc fix(ui): missing css 2025-02-11 19:17:38 +08:00
Fu Diwei
774ed5d31e feat: reserved field challengeType for apply node config 2025-02-11 19:03:58 +08:00
Fu Diwei
b07174b533 feat: cascade delete related runs and outputs when delete workflow 2025-02-11 16:45:51 +08:00
Yoan.liu
1f6b33f4f6 update version 2025-02-08 09:00:15 +08:00
Yoan.liu
049707acdc
Merge pull request #438 from hujingnb/fix/k8s_secret
fix: k8s secret not updated
2025-02-08 08:56:52 +08:00
hujing
e019bfe136 fix: k8s secret not updated 2025-01-31 00:50:40 +08:00
Yoan.liu
57f8db010b
Merge pull request #433 from fudiwei/feat/new-workflow
feat: more providers
2025-01-24 10:26:30 +08:00
23 changed files with 271 additions and 87 deletions

View File

@ -5,7 +5,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
"time"
@ -59,7 +59,7 @@ func (s *CertificateService) InitSchedule(ctx context.Context) error {
return nil
}
func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) ([]byte, error) {
func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) (*dtos.CertificateArchiveFileResp, error) {
certificate, err := s.certRepo.GetById(ctx, req.CertificateId)
if err != nil {
return nil, err
@ -69,6 +69,10 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific
zipWriter := zip.NewWriter(&buf)
defer zipWriter.Close()
resp := &dtos.CertificateArchiveFileResp{
FileFormat: "zip",
}
switch strings.ToUpper(req.Format) {
case "", "PEM":
{
@ -97,7 +101,8 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific
return nil, err
}
return buf.Bytes(), nil
resp.FileBytes = buf.Bytes()
return resp, nil
}
case "PFX":
@ -134,7 +139,8 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific
return nil, err
}
return buf.Bytes(), nil
resp.FileBytes = buf.Bytes()
return resp, nil
}
case "JKS":
@ -171,7 +177,8 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific
return nil, err
}
return buf.Bytes(), nil
resp.FileBytes = buf.Bytes()
return resp, nil
}
default:
@ -180,25 +187,30 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific
}
func (s *CertificateService) ValidateCertificate(ctx context.Context, req *dtos.CertificateValidateCertificateReq) (*dtos.CertificateValidateCertificateResp, error) {
info, err := certs.ParseCertificateFromPEM(req.Certificate)
certX509, err := certs.ParseCertificateFromPEM(req.Certificate)
if err != nil {
return nil, err
} else if time.Now().After(certX509.NotAfter) {
return nil, fmt.Errorf("certificate has expired at %s", certX509.NotAfter.UTC().Format(time.RFC3339))
}
return &dtos.CertificateValidateCertificateResp{
IsValid: true,
Domains: strings.Join(certX509.DNSNames, ";"),
}, nil
}
func (s *CertificateService) ValidatePrivateKey(ctx context.Context, req *dtos.CertificateValidatePrivateKeyReq) (*dtos.CertificateValidatePrivateKeyResp, error) {
_, err := certcrypto.ParsePEMPrivateKey([]byte(req.PrivateKey))
if err != nil {
return nil, err
}
if time.Now().After(info.NotAfter) {
return nil, errors.New("证书已过期")
}
return &dtos.CertificateValidateCertificateResp{
Domains: strings.Join(info.DNSNames, ";"),
return &dtos.CertificateValidatePrivateKeyResp{
IsValid: true,
}, nil
}
func (s *CertificateService) ValidatePrivateKey(ctx context.Context, req *dtos.CertificateValidatePrivateKeyReq) error {
_, err := certcrypto.ParsePEMPrivateKey([]byte(req.PrivateKey))
return err
}
func buildExpireSoonNotification(certificates []*domain.Certificate) *struct {
Subject string
Message string

View File

@ -5,22 +5,24 @@ type CertificateArchiveFileReq struct {
Format string `json:"format"`
}
type CertificateArchiveFileResp struct {
FileBytes []byte `json:"fileBytes"`
FileFormat string `json:"fileFormat"`
}
type CertificateValidateCertificateReq struct {
Certificate string `json:"certificate"`
}
type CertificateValidateCertificateResp struct {
Domains string `json:"domains"`
IsValid bool `json:"isValid"`
Domains string `json:"domains,omitempty"`
}
type CertificateValidatePrivateKeyReq struct {
PrivateKey string `json:"privateKey"`
}
type CertificateUploadReq struct {
WorkflowId string `json:"workflowId"`
WorkflowNodeId string `json:"workflowNodeId"`
CertificateId string `json:"certificateId"`
Certificate string `json:"certificate"`
PrivateKey string `json:"privateKey"`
type CertificateValidatePrivateKeyResp struct {
IsValid bool `json:"isValid"`
}

View File

@ -64,6 +64,7 @@ type WorkflowNode struct {
type WorkflowNodeConfigForApply struct {
Domains string `json:"domains"` // 域名列表,以半角逗号分隔
ContactEmail string `json:"contactEmail"` // 联系邮箱
ChallengeType string `json:"challengeType"` // TODO: 验证方式。目前仅支持 dns-01
Provider string `json:"provider"` // DNS 提供商
ProviderAccessId string `json:"providerAccessId"` // DNS 提供商授权记录 ID
ProviderConfig map[string]any `json:"providerConfig"` // DNS 提供商额外配置

View File

@ -131,6 +131,11 @@ func (d *K8sSecretDeployer) Deploy(ctx context.Context, certPem string, privkeyP
secretPayload.ObjectMeta.Annotations[k] = v
}
}
if secretPayload.Data == nil {
secretPayload.Data = make(map[string][]byte)
}
secretPayload.Data[d.config.SecretDataKeyForCrt] = []byte(certPem)
secretPayload.Data[d.config.SecretDataKeyForKey] = []byte(privkeyPem)
secretPayload, err = client.CoreV1().Secrets(d.config.Namespace).Update(context.TODO(), secretPayload, k8sMeta.UpdateOptions{})
if err != nil {
return nil, xerrors.Wrap(err, "failed to update k8s secret")

View File

@ -11,9 +11,9 @@ import (
)
type certificateService interface {
ArchiveFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) ([]byte, error)
ArchiveFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) (*dtos.CertificateArchiveFileResp, error)
ValidateCertificate(ctx context.Context, req *dtos.CertificateValidateCertificateReq) (*dtos.CertificateValidateCertificateResp, error)
ValidatePrivateKey(ctx context.Context, req *dtos.CertificateValidatePrivateKeyReq) error
ValidatePrivateKey(ctx context.Context, req *dtos.CertificateValidatePrivateKeyReq) (*dtos.CertificateValidatePrivateKeyResp, error)
}
type CertificateHandler struct {
@ -38,10 +38,10 @@ func (handler *CertificateHandler) archiveFile(e *core.RequestEvent) error {
return resp.Err(e, err)
}
if bt, err := handler.service.ArchiveFile(e.Request.Context(), req); err != nil {
if res, err := handler.service.ArchiveFile(e.Request.Context(), req); err != nil {
return resp.Err(e, err)
} else {
return resp.Ok(e, bt)
return resp.Ok(e, res)
}
}
@ -51,10 +51,10 @@ func (handler *CertificateHandler) validateCertificate(e *core.RequestEvent) err
return resp.Err(e, err)
}
if rs, err := handler.service.ValidateCertificate(e.Request.Context(), req); err != nil {
if res, err := handler.service.ValidateCertificate(e.Request.Context(), req); err != nil {
return resp.Err(e, err)
} else {
return resp.Ok(e, rs)
return resp.Ok(e, res)
}
}
@ -64,9 +64,9 @@ func (handler *CertificateHandler) validatePrivateKey(e *core.RequestEvent) erro
return resp.Err(e, err)
}
if err := handler.service.ValidatePrivateKey(e.Request.Context(), req); err != nil {
if res, err := handler.service.ValidatePrivateKey(e.Request.Context(), req); err != nil {
return resp.Err(e, err)
} else {
return resp.Ok(e, nil)
return resp.Ok(e, res)
}
}

View File

@ -142,11 +142,11 @@ func (w *WorkflowDispatcher) Shutdown() {
w.workerMutex.Lock()
for _, worker := range w.workers {
worker.Cancel()
delete(w.workers, worker.Data.WorkflowId)
delete(w.workerIdMap, worker.Data.RunId)
}
w.workerMutex.Unlock()
w.wg.Wait()
w.workers = make(map[string]*workflowWorker)
w.workerIdMap = make(map[string]string)
}
func (w *WorkflowDispatcher) enqueueWorker(data *WorkflowWorkerData) {

View File

@ -0,0 +1,58 @@
package migrations
import (
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("qjp8lygssgwyqyz")
if err != nil {
return err
}
// update field
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
"cascadeDelete": true,
"collectionId": "tovyif5ax6j62ur",
"hidden": false,
"id": "m8xfsyyy",
"maxSelect": 1,
"minSelect": 0,
"name": "workflowId",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
}`)); err != nil {
return err
}
return app.Save(collection)
}, func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("qjp8lygssgwyqyz")
if err != nil {
return err
}
// update field
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
"cascadeDelete": false,
"collectionId": "tovyif5ax6j62ur",
"hidden": false,
"id": "m8xfsyyy",
"maxSelect": 1,
"minSelect": 0,
"name": "workflowId",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
}`)); err != nil {
return err
}
return app.Save(collection)
})
}

View File

@ -0,0 +1,92 @@
package migrations
import (
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("bqnxb95f2cooowp")
if err != nil {
return err
}
// update field
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
"cascadeDelete": true,
"collectionId": "tovyif5ax6j62ur",
"hidden": false,
"id": "jka88auc",
"maxSelect": 1,
"minSelect": 0,
"name": "workflowId",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
}`)); err != nil {
return err
}
// update field
if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
"cascadeDelete": true,
"collectionId": "qjp8lygssgwyqyz",
"hidden": false,
"id": "relation821863227",
"maxSelect": 1,
"minSelect": 0,
"name": "runId",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
}`)); err != nil {
return err
}
return app.Save(collection)
}, func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("bqnxb95f2cooowp")
if err != nil {
return err
}
// update field
if err := collection.Fields.AddMarshaledJSONAt(1, []byte(`{
"cascadeDelete": false,
"collectionId": "tovyif5ax6j62ur",
"hidden": false,
"id": "jka88auc",
"maxSelect": 1,
"minSelect": 0,
"name": "workflowId",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
}`)); err != nil {
return err
}
// update field
if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{
"cascadeDelete": false,
"collectionId": "qjp8lygssgwyqyz",
"hidden": false,
"id": "relation821863227",
"maxSelect": 1,
"minSelect": 0,
"name": "runId",
"presentable": false,
"required": false,
"system": false,
"type": "relation"
}`)); err != nil {
return err
}
return app.Save(collection)
})
}

View File

@ -3,10 +3,14 @@ import { ClientResponseError } from "pocketbase";
import { type CertificateFormatType } from "@/domain/certificate";
import { getPocketBase } from "@/repository/_pocketbase";
type ArchiveRespData = {
fileBytes: string;
};
export const archive = async (certificateId: string, format?: CertificateFormatType) => {
const pb = getPocketBase();
const resp = await pb.send<BaseResponse<string>>(`/api/certificates/${encodeURIComponent(certificateId)}/archive`, {
const resp = await pb.send<BaseResponse<ArchiveRespData>>(`/api/certificates/${encodeURIComponent(certificateId)}/archive`, {
method: "POST",
headers: {
"Content-Type": "application/json",
@ -24,6 +28,7 @@ export const archive = async (certificateId: string, format?: CertificateFormatT
};
type ValidateCertificateResp = {
isValid: boolean;
domains: string;
};
@ -46,9 +51,13 @@ export const validateCertificate = async (certificate: string) => {
return resp;
};
type ValidatePrivateKeyResp = {
isValid: boolean;
};
export const validatePrivateKey = async (privateKey: string) => {
const pb = getPocketBase();
const resp = await pb.send<BaseResponse>(`/api/certificates/validate/private-key`, {
const resp = await pb.send<BaseResponse<ValidatePrivateKeyResp>>(`/api/certificates/validate/private-key`, {
method: "POST",
headers: {
"Content-Type": "application/json",

View File

@ -22,7 +22,7 @@ const CertificateDetail = ({ data, ...props }: CertificateDetailProps) => {
const handleDownloadClick = async (format: CertificateFormatType) => {
try {
const res = await archiveCertificate(data.id, format);
const bstr = atob(res.data);
const bstr = atob(res.data.fileBytes);
const u8arr = Uint8Array.from(bstr, (ch) => ch.charCodeAt(0));
const blob = new Blob([u8arr], { type: "application/zip" });
saveAs(blob, `${data.id}-${data.subjectAltNames}.zip`);

View File

@ -56,6 +56,7 @@ const ApplyNode = ({ node, disabled }: ApplyNodeProps) => {
const newNode = produce(node, (draft) => {
draft.config = {
...newValues,
challengeType: newValues.challengeType || "dns-01", // 默认使用 DNS-01 认证
};
draft.validated = true;
});

View File

@ -56,6 +56,7 @@ const MULTIPLE_INPUT_DELIMITER = ";";
const initFormModel = (): ApplyNodeConfigFormFieldValues => {
return {
challengeType: "dns-01",
keyAlgorithm: "RSA2048",
skipBeforeExpiryDays: 20,
};
@ -74,6 +75,7 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
.every((e) => validDomainName(e, { allowWildcard: true }));
}, t("common.errmsg.domain_invalid")),
contactEmail: z.string({ message: t("workflow_node.apply.form.contact_email.placeholder") }).email(t("common.errmsg.email_invalid")),
challengeType: z.string().nullish(),
provider: z.string({ message: t("workflow_node.apply.form.provider.placeholder") }).nonempty(t("workflow_node.apply.form.provider.placeholder")),
providerAccessId: z
.string({ message: t("workflow_node.apply.form.provider_access.placeholder") })
@ -235,6 +237,16 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
<EmailInput placeholder={t("workflow_node.apply.form.contact_email.placeholder")} />
</Form.Item>
<Form.Item name="challengeType" label={t("workflow_node.apply.form.challenge_type.label")} rules={[formRule]} hidden>
<Select
options={["DNS-01"].map((e) => ({
label: e,
value: e.toLowerCase(),
}))}
placeholder={t("workflow_node.apply.form.challenge_type.placeholder")}
/>
</Form.Item>
<Form.Item name="provider" label={t("workflow_node.apply.form.provider.label")} hidden rules={[formRule]}>
<ApplyDNSProviderSelect
allowClear

View File

@ -1 +1 @@
export const version = "v0.3.0-alpha.10";
export const version = "v0.3.0-alpha.11";

View File

@ -122,6 +122,7 @@ export type WorkflowNodeConfigForStart = {
export type WorkflowNodeConfigForApply = {
domains: string;
contactEmail: string;
challengeType: string;
provider: string;
providerAccessId: string;
providerConfig?: Record<string, unknown>;

View File

@ -1,13 +1,8 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
line-height: 1.5;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@ -15,8 +10,7 @@
body {
margin: 0;
display: flex;
place-items: center;
padding: 0;
min-width: 320px;
min-height: 100vh;
}

View File

@ -5,6 +5,7 @@ import dayjsUtc from "dayjs/plugin/utc";
import App from "./App";
import "./i18n";
import "./index.css";
import "./global.css";
dayjs.extend(dayjsUtc);

View File

@ -6,3 +6,11 @@ export const getPocketBase = () => {
pb = new PocketBase("/");
return pb;
};
export const COLLECTION_NAME_ADMIN = "_superusers";
export const COLLECTION_NAME_ACCESS = "access";
export const COLLECTION_NAME_CERTIFICATE = "certificate";
export const COLLECTION_NAME_SETTINGS = "settings";
export const COLLECTION_NAME_WORKFLOW = "workflow";
export const COLLECTION_NAME_WORKFLOW_RUN = "workflow_run";
export const COLLECTION_NAME_WORKFLOW_OUTPUT = "workflow_output";

View File

@ -1,12 +1,10 @@
import dayjs from "dayjs";
import { type AccessModel } from "@/domain/access";
import { getPocketBase } from "./_pocketbase";
const COLLECTION_NAME = "access";
import { COLLECTION_NAME_ACCESS, getPocketBase } from "./_pocketbase";
export const list = async () => {
return await getPocketBase().collection(COLLECTION_NAME).getFullList<AccessModel>({
return await getPocketBase().collection(COLLECTION_NAME_ACCESS).getFullList<AccessModel>({
filter: "deleted=null",
sort: "-created",
requestKey: null,
@ -15,15 +13,15 @@ export const list = async () => {
export const save = async (record: MaybeModelRecord<AccessModel>) => {
if (record.id) {
return await getPocketBase().collection(COLLECTION_NAME).update<AccessModel>(record.id, record);
return await getPocketBase().collection(COLLECTION_NAME_ACCESS).update<AccessModel>(record.id, record);
}
return await getPocketBase().collection(COLLECTION_NAME).create<AccessModel>(record);
return await getPocketBase().collection(COLLECTION_NAME_ACCESS).create<AccessModel>(record);
};
export const remove = async (record: MaybeModelRecordWithId<AccessModel>) => {
await getPocketBase()
.collection(COLLECTION_NAME)
.collection(COLLECTION_NAME_ACCESS)
.update<AccessModel>(record.id!, { deleted: dayjs.utc().format("YYYY-MM-DD HH:mm:ss") });
return true;
};

View File

@ -1,9 +1,7 @@
import { getPocketBase } from "./_pocketbase";
const COLLECTION_NAME = "_superusers";
import { COLLECTION_NAME_ADMIN, getPocketBase } from "./_pocketbase";
export const authWithPassword = (username: string, password: string) => {
return getPocketBase().collection(COLLECTION_NAME).authWithPassword(username, password);
return getPocketBase().collection(COLLECTION_NAME_ADMIN).authWithPassword(username, password);
};
export const getAuthStore = () => {
@ -12,6 +10,6 @@ export const getAuthStore = () => {
export const save = (data: { email: string } | { password: string; passwordConfirm: string }) => {
return getPocketBase()
.collection(COLLECTION_NAME)
.collection(COLLECTION_NAME_ADMIN)
.update(getAuthStore().record?.id || "", data);
};

View File

@ -2,9 +2,7 @@ import dayjs from "dayjs";
import { type RecordListOptions } from "pocketbase";
import { type CertificateModel } from "@/domain/certificate";
import { getPocketBase } from "./_pocketbase";
const COLLECTION_NAME = "certificate";
import { COLLECTION_NAME_CERTIFICATE, getPocketBase } from "./_pocketbase";
export type ListCertificateRequest = {
page?: number;
@ -35,7 +33,7 @@ export const list = async (request: ListCertificateRequest) => {
});
}
return pb.collection(COLLECTION_NAME).getList<CertificateModel>(page, perPage, options);
return pb.collection(COLLECTION_NAME_CERTIFICATE).getList<CertificateModel>(page, perPage, options);
};
export const listByWorkflowRunId = async (workflowRunId: string) => {
@ -48,7 +46,7 @@ export const listByWorkflowRunId = async (workflowRunId: string) => {
sort: "-created",
requestKey: null,
};
const items = await pb.collection(COLLECTION_NAME).getFullList<CertificateModel>(options);
const items = await pb.collection(COLLECTION_NAME_CERTIFICATE).getFullList<CertificateModel>(options);
return {
totalItems: items.length,
items: items,
@ -57,7 +55,7 @@ export const listByWorkflowRunId = async (workflowRunId: string) => {
export const remove = async (record: MaybeModelRecordWithId<CertificateModel>) => {
await getPocketBase()
.collection(COLLECTION_NAME)
.collection(COLLECTION_NAME_CERTIFICATE)
.update<CertificateModel>(record.id!, { deleted: dayjs.utc().format("YYYY-MM-DD HH:mm:ss") });
return true;
};

View File

@ -1,13 +1,11 @@
import { ClientResponseError } from "pocketbase";
import { type SettingsModel, type SettingsNames } from "@/domain/settings";
import { getPocketBase } from "./_pocketbase";
const COLLECTION_NAME = "settings";
import { COLLECTION_NAME_SETTINGS, getPocketBase } from "./_pocketbase";
export const get = async <T extends NonNullable<unknown>>(name: SettingsNames) => {
try {
const resp = await getPocketBase().collection(COLLECTION_NAME).getFirstListItem<SettingsModel<T>>(`name='${name}'`, {
const resp = await getPocketBase().collection(COLLECTION_NAME_SETTINGS).getFirstListItem<SettingsModel<T>>(`name='${name}'`, {
requestKey: null,
});
return resp;
@ -25,8 +23,8 @@ export const get = async <T extends NonNullable<unknown>>(name: SettingsNames) =
export const save = async <T extends NonNullable<unknown>>(record: MaybeModelRecordWithId<SettingsModel<T>>) => {
if (record.id) {
return await getPocketBase().collection(COLLECTION_NAME).update<SettingsModel<T>>(record.id, record);
return await getPocketBase().collection(COLLECTION_NAME_SETTINGS).update<SettingsModel<T>>(record.id, record);
}
return await getPocketBase().collection(COLLECTION_NAME).create<SettingsModel<T>>(record);
return await getPocketBase().collection(COLLECTION_NAME_SETTINGS).create<SettingsModel<T>>(record);
};

View File

@ -1,9 +1,7 @@
import { type RecordListOptions, type RecordSubscription } from "pocketbase";
import { type WorkflowModel } from "@/domain/workflow";
import { getPocketBase } from "./_pocketbase";
const COLLECTION_NAME = "workflow";
import { COLLECTION_NAME_WORKFLOW, getPocketBase } from "./_pocketbase";
export type ListWorkflowRequest = {
page?: number;
@ -26,11 +24,11 @@ export const list = async (request: ListWorkflowRequest) => {
options.filter = pb.filter("enabled={:enabled}", { enabled: request.enabled });
}
return await pb.collection(COLLECTION_NAME).getList<WorkflowModel>(page, perPage, options);
return await pb.collection(COLLECTION_NAME_WORKFLOW).getList<WorkflowModel>(page, perPage, options);
};
export const get = async (id: string) => {
return await getPocketBase().collection(COLLECTION_NAME).getOne<WorkflowModel>(id, {
return await getPocketBase().collection(COLLECTION_NAME_WORKFLOW).getOne<WorkflowModel>(id, {
requestKey: null,
});
};
@ -38,21 +36,21 @@ export const get = async (id: string) => {
export const save = async (record: MaybeModelRecord<WorkflowModel>) => {
if (record.id) {
return await getPocketBase()
.collection(COLLECTION_NAME)
.collection(COLLECTION_NAME_WORKFLOW)
.update<WorkflowModel>(record.id as string, record);
}
return await getPocketBase().collection(COLLECTION_NAME).create<WorkflowModel>(record);
return await getPocketBase().collection(COLLECTION_NAME_WORKFLOW).create<WorkflowModel>(record);
};
export const remove = async (record: MaybeModelRecordWithId<WorkflowModel>) => {
return await getPocketBase().collection(COLLECTION_NAME).delete(record.id);
return await getPocketBase().collection(COLLECTION_NAME_WORKFLOW).delete(record.id);
};
export const subscribe = async (id: string, cb: (e: RecordSubscription<WorkflowModel>) => void) => {
return getPocketBase().collection(COLLECTION_NAME).subscribe(id, cb);
return getPocketBase().collection(COLLECTION_NAME_WORKFLOW).subscribe(id, cb);
};
export const unsubscribe = async (id: string) => {
return getPocketBase().collection(COLLECTION_NAME).unsubscribe(id);
return getPocketBase().collection(COLLECTION_NAME_WORKFLOW).unsubscribe(id);
};

View File

@ -2,9 +2,7 @@
import { type WorkflowRunModel } from "@/domain/workflowRun";
import { getPocketBase } from "./_pocketbase";
const COLLECTION_NAME = "workflow_run";
import { COLLECTION_NAME_WORKFLOW_RUN, getPocketBase } from "./_pocketbase";
export type ListWorkflowRunsRequest = {
workflowId?: string;
@ -25,7 +23,7 @@ export const list = async (request: ListWorkflowRunsRequest) => {
}
return await getPocketBase()
.collection(COLLECTION_NAME)
.collection(COLLECTION_NAME_WORKFLOW_RUN)
.getList<WorkflowRunModel>(page, perPage, {
filter: getPocketBase().filter(filter, params),
sort: "-created",
@ -35,13 +33,13 @@ export const list = async (request: ListWorkflowRunsRequest) => {
};
export const remove = async (record: MaybeModelRecordWithId<WorkflowRunModel>) => {
return await getPocketBase().collection(COLLECTION_NAME).delete(record.id);
return await getPocketBase().collection(COLLECTION_NAME_WORKFLOW_RUN).delete(record.id);
};
export const subscribe = async (id: string, cb: (e: RecordSubscription<WorkflowRunModel>) => void) => {
return getPocketBase().collection(COLLECTION_NAME).subscribe(id, cb);
return getPocketBase().collection(COLLECTION_NAME_WORKFLOW_RUN).subscribe(id, cb);
};
export const unsubscribe = async (id: string) => {
return getPocketBase().collection(COLLECTION_NAME).unsubscribe(id);
return getPocketBase().collection(COLLECTION_NAME_WORKFLOW_RUN).unsubscribe(id);
};