首页/新闻资讯/正文详情

Webiny Webhooks Admin UI 实现指南:基于三层架构与 WebinySdk 构建完整管理界面

发布时间:2026/9/28 3:09:20 来源:云帆数科 栏目:资讯中心
Webiny Webhooks Admin UI 实现指南:基于三层架构与 WebinySdk 构建完整管理界面
CMS后端前端【免费下载链接】webiny-jsOpen-source, self-hosted CMS platform on AWS serverless (Lambda, DynamoDB, S3). TypeScript framework with multi-tenancy, lifecycle hooks, GraphQL API, and AI-assisted development via MCP server. Built for developers at large organizations.项目地址https://gitcode.com/gh_mirrors/we/webiny-js点击查看免费下载本文以 Webiny 开源仓库中的 Webhooks Admin UI 实施计划 为骨架结合仓库内已落地实现的源码packages/webhooks/src/admin/、packages/sdk/src/WebhooksSdk.ts、packages/feature/src/admin/展开。读者将掌握如何在 Webiny 中按照 Gateway → UseCase → Presenter 三层模式组织一个完整的管理端功能Webhook 列表、创建/编辑表单、投递日志与权限配置并理解其背后的 DI依赖注入、MobX 响应式状态与 React 视图如何协同工作。一、方案总览目标、架构与技术栈该实施计划的目标是在 Webiny 管理端Admin UI中构建 Webhooks 管理界面覆盖四类核心能力列表List分页展示 Webhook支持搜索、排序、筛选、多选、删除、手动触发Trigger表单Form创建与编辑 Webhook名称、slug、endpointUrl、描述、启用状态、订阅事件并展示只读的签名密钥Signing Secret投递日志Delivery Log以抽屉/独立页面查看每个 Webhook 的历史投递记录支持重发Resend与查看投递详情payload、headers、response权限Permissions通过 Webiny 管理端权限体系控制 read/create/edit/delete 能力。架构采用 Webiny 管理端标准的三层模式Gateway网关封装对WebinySdksdk.webhooks.*的调用统一处理Result的成败分支UseCase用例业务逻辑入口委托给 Gateway薄封装层Presenter表现者持有 MobX 响应式状态向 React 视图暴露vmViewModel与actions列表视图复用共享的ListPresenterIDataSource表单视图使用FormModel。所有依赖注入均通过createAbstraction/createFeature完成即webiny/feature/admin提供的 DI 抽象与 Feature 注册机制。技术栈为 TypeScript MobX React核心依赖包括webiny/feature/admin、webiny/sdk、webiny/admin-ui、webiny/app-admin。文件统一放置在packages/webhooks/src/admin/目录下下文简称admin/这与仓库实际结构一致——源码树 中features/、presentation/、shared/、WebhookRoutes.tsx、Webhooks.tsx、routes.ts、permissions.ts均已按此布局落地。二、贯穿全局的编码约定Conventions计划对所有 Feature 提出了统一约束理解这些约定有助于直接阅读仓库代码导入规范每个具名导入独占一行createAbstraction与createFeature均来自webiny/feature/adminWebinySdk从webiny/app-admin/features/webinySdk/abstractions.js导入Webhook、WebhookDelivery、WebhookEvent等类型直接从webiny/sdk导入无需自定义 DTO。文件规范一个文件只放一个类文件底部通过export const X Abstraction.createImplementation(...)导出实现使用命名空间模式export namespace Foo { export type Interface IFoo; }把抽象与其接口类型组织在一起。作用域ScopeGateway 使用单例作用域.inSingletonScope()UseCase 使用默认的 transient 作用域。Feature 约束每个createFeature必须提供resolve函数。注释与导出单行注释用//多行用/* */注释以句号结尾禁止默认导出。三、Task 1Foundation——共享类型、路由与权限底座Foundation 层没有外部依赖为后续所有任务提供地基共 8 个文件admin/shared/types.ts admin/routes.ts admin/features/permissions/abstractions.ts admin/features/permissions/feature.ts admin/features/permissions/index.ts admin/presentation/security/usePermissions.ts admin/presentation/security/HasPermission.tsx3.1 共享类型直接从 SDK 复用杜绝自定义 DTOshared/types.ts的核心思想是管理端与 API 层共用webiny/sdk的类型契约避免在管理端重复定义数据结构。其导出集合包括实体类型Webhook、WebhookDelivery、WebhookEvent、列表参数与结果类型ListWebhooksParams/Result、ListWebhookDeliveriesParams/Result以及写操作参数类型CreateWebhookParams、UpdateWebhookParams。这些类型在仓库中确实由 SDK 提供WebhooksSdk.ts 定义了WebhooksSdk类其方法签名正是这些类型参数的载体例如async listWebhooks(params?: ListWebhooksParams) : PromiseResultListWebhooksResult, HttpError | ApiError | NetworkError | ValidationError async createWebhook(params: CreateWebhookParams) : PromiseResultWebhook, ... async triggerWebhook(params: TriggerWebhookParams) : PromiseResultWebhookDelivery, ...所有方法统一返回ResultT, E联合类型这也是后续 Gateway 中result.isFail()分支判断的契约来源。3.2 路由定义基于webiny/app-admin的 Routeroutes.ts使用webiny/app-admin导出的Route声明两条核心路由export const Routes { List: new Route({ name: Webhooks/List, path: /webhooks }), Form: new Route({ name: Webhooks/Form, path: /webhooks/:id, params: zod ({ id: zod.string() }) }) };其中/webhooks/:id使用 zod 校验路径参数id创建新 Webhook 时以特殊值new作为id传入表单 Presenter 通过id new判断isNew。仓库中实际落地版本在此基础上扩展出了Deliveries/webhooks/deliveries与Settings/webhooks/settings两条路由见 routes.ts说明投递日志在最终实现中从抽屉演进为了独立页面。3.3 权限体系Schema → Abstraction → Feature → Hook/组件权限底座由四块拼成全部围绕一个权限 Schema 展开。仓库中该 Schema 位于 admin/permissions.tsexport const WEBHOOK_PERMISSIONS_SCHEMA createPermissionSchema({ prefix: webhooks, fullAccess: true, entities: [ { id: webhook, permission: webhooks.webhook, scopes: [full], actions: [{ name: rwd }] } ] });abstractions.ts用createPermissionsAbstraction(WEBHOOK_PERMISSIONS_SCHEMA)创建WebhookPermissions抽象单例并以命名空间导出Interface Permissionstypeof WEBHOOK_PERMISSIONS_SCHEMAfeature.ts用createPermissionsFeature(WEBHOOK_PERMISSIONS_SCHEMA, WebhookPermissions)把 Schema 与抽象注册进 DI 容器usePermissions.ts用createUsePermissions(WebhookPermissions)生成usePermissionsHookHasPermission.tsx用createHasPermission(WebhookPermissions, WEBHOOK_PERMISSIONS_SCHEMA)生成权限守卫组件接受entitywebhook属性用于包裹路由与菜单。对应文件已落地于 packages/webhooks/src/admin/presentation/security/。后续 Presenter 中通过permissions.canRead(webhook)、permissions.canCreate(webhook)、permissions.canEdit(webhook)、permissions.canDelete(webhook)读取能力位视图层据此渲染/隐藏按钮。四、Task 2Webhook CRUD Features——五连 Feature 的标准范式Task 2 定义五个无头headlessFeaturelistWebhooks、getWebhook、createWebhook、updateWebhook、deleteWebhook。每个 Feature 遵循完全相同的五文件范式{abstractions, XxxGateway, XxxUseCase, feature, index}.ts五个 Feature 之间互不依赖可并行开发共 5 × 5 25 个文件。4.1 abstractions抽象即契约以listWebhooks为例抽象文件定义三层契约网关入参/出参ListWebhooksGatewayParamswhere?: { enabled?: boolean }、limit?: number、after?: string与ListWebhooksGatewayResultdata: Webhook[]meta: { cursor, hasMoreItems, totalCount }后者即游标分页元数据网关抽象IListWebhooksGatewaycreateAbstractionIListWebhooksGateway(ListWebhooksGateway)用例抽象IListWebhooksUseCasecreateAbstractionIListWebhooksUseCase(ListWebhooksUseCase)。每个抽象都用export namespace X { export type Interface IX; }绑定接口类型实现类以X.Interface作为类型标注。4.2 GatewaySDK 调用的唯一出口Gateway 是三层中唯一直接接触WebinySdk的地方负责把 SDK 的Result风格返回值翻译成管理端友好的错误抛出class ListWebhooksGatewayImpl implements GatewayAbstraction.Interface { constructor(private readonly sdk: WebinySdk.Interface) {} async execute(params: ListWebhooksGatewayParams): PromiseListWebhooksGatewayResult { const result await this.sdk.webhooks.listWebhooks({ where: params.where, limit: params.limit, after: params.after }); if (result.isFail()) { throw new Error(result.error.message); } return { data: result.value.data, meta: result.value.meta }; } } export const ListWebhooksGateway GatewayAbstraction.createImplementation({ implementation: ListWebhooksGatewayImpl, dependencies: [WebinySdk] });关键点构造函数以private readonly sdk: WebinySdk.Interface注入 SDK 抽象通过createImplementation的dependencies: [WebinySdk]声明依赖result.isFail()失败分支统一抛Error成功分支才解包result.value——这一模式在getWebhook、createWebhook、updateWebhook、deleteWebhook返回Promiseboolean中完全一致。4.3 UseCase委托网关的薄封装UseCase 不直接访问 SDK而是注入 Gateway 抽象并把执行委托给它class ListWebhooksUseCaseImpl implements UseCaseAbstraction.Interface { constructor(private readonly gateway: ListWebhooksGateway.Interface) {} async execute(params: ListWebhooksGatewayParams): PromiseListWebhooksGatewayResult { return this.gateway.execute(params); } } export const ListWebhooksUseCase UseCaseAbstraction.createImplementation({ implementation: ListWebhooksUseCaseImpl, dependencies: [ListWebhooksGateway] });createWebhook的入参结构定义了 Webhook 的完整字段集合name、endpointUrl、events: string[]为必填slug、description、enabled为可选updateWebhook则全部字段可选name?、slug?、endpointUrl?、description?、enabled?、events?更新网关以{ id, ...input }透传给 SDK。4.4 featureDI 容器注册与解析Feature 文件负责把抽象与实现注册进容器并声明resolve输出export const ListWebhooksFeature createFeature({ name: Webhooks/ListWebhooks, register(container) { container.register(ListWebhooksUseCase); container.register(ListWebhooksGateway).inSingletonScope(); }, resolve(container) { return { useCase: container.resolve(UseCaseAbstraction) }; } });注意这里的作用域约定UseCase 用默认transient作用域每次解析创建新实例Gateway 显式.inSingletonScope()。index.ts统一导出XxxUseCase抽象与XxxFeature供上层引用。4.5 仓库落地形态对照仓库 packages/webhooks/src/admin/features/ 中不仅完整实现了计划中的五个 CRUD Feature还额外演进出了getWebhookSettings、updateWebhookSettings两个设置类 Feature印证了这套五文件范式的可复制性。另外仓库中ListWebhooks目录多了一个ListWebhooksRepository.ts说明后续迭代中加入了 Repository 层但这属于实现演进不影响本文介绍的标准范式。五、Task 3Delivery Event Features——投递与事件能力Task 3 再增加四个无头 FeaturelistWebhookDeliveries、resendWebhookDelivery、triggerWebhook、listAvailableEvents同样彼此无依赖、可并行开发。这些能力支撑列表页的手动触发和表单页/日志页的投递记录。listWebhookDeliveries入参为{ webhookId: string; limit?: number; after?: string }返回与列表同构的data: WebhookDelivery[] 游标meta。网关调用sdk.webhooks.listWebhookDeliveries({ webhookId, limit, after })。注意入参比列表多一个必填的webhookId用于按 Webhook 过滤投递记录。resendWebhookDeliveryexecute(id: string): Promiseboolean网关调用sdk.webhooks.resendWebhookDelivery({ id })用于日志页对失败投递执行重发。triggerWebhookexecute(id: string, payload: Recordstring, unknown): PromiseWebhookDelivery网关调用sdk.webhooks.triggerWebhook({ id, payload })。它返回一次新的WebhookDelivery——因为手动触发本身就是一次真实投递会立即产生一条可查看的记录。列表页 Presenter 中以triggerWebhook(id, { test: true })方式调用随后刷新列表。listAvailableEventsexecute(): PromiseWebhookEvent[]网关调用sdk.webhooks.listAvailableWebhookEvents()无参数。表单页用它渲染可订阅事件的选项列表新建与编辑时都会加载。六、Task 4WebhookList 表现层——复用共享 ListPresenter列表表现层依赖 Task 1-3由 6 个文件组成admin/presentation/WebhookList/{abstractions, WebhookListDataSource, WebhookListPresenter, feature, index}.ts admin/presentation/WebhookList/components/WebhookListView.tsx6.1 视图模型与动作契约IWebhookListViewModel将共享列表的状态IListViewModelWebhook与权限位canRead、canCreate、canEdit、canDelete打包成单一vmIWebhookListActions在共享列表动作search、sort、filter、selection、loadMore、refresh之上追加两个领域动作export interface IWebhookListActions extends IListActions { deleteWebhook(id: string): Promisevoid; triggerWebhook(id: string): Promisevoid; }6.2 IDataSource列表数据源契约WebhookListDataSource实现IDataSourceWebhook是连接共享ListPresenter与ListWebhooksUseCase的适配器。它内部持有三份响应式状态_rows、_meta{ cursor, hasMoreItems, totalCount }、_loading构造时通过makeAutoObservable配置——listWebhooksUseCase标记为false不观察依赖rows标记为computed。两个关键方法query(params)首次/刷新加载把params.filters映射为where、params.limit映射为limit、params.cursor映射为after调用 UseCase 后runInAction中整体替换_rows与_metaloadMore(params)仅在hasMoreItems !loading时继续以this._meta.cursor ?? undefined作为after并在runInAction中以[...this._rows, ...result.data]追加而非替换。这套模式把游标分页细节完全收纳在数据源内部共享ListPresenter无需关心具体数据来自哪里。6.3 Presenter组合共享 ListPresenter 与领域动作WebhookListPresenterImpl构造函数注入五个依赖ListPresenter.InterfaceWebhook、ListWebhooksUseCase、DeleteWebhookUseCase、TriggerWebhookUseCase、WebhookPermissions。vm为computed实时组合listPresenter.vm与权限位。init()是装配点创建WebhookListDataSource实例并配置共享列表的初始排序与分页this.listPresenter.init({ dataSource, initialSort: { field: createdOn, direction: DESC }, limit: 20 });actions采用显式委托search/sort/filter/selection/loadMore/refresh 全部转发给listPresenter.actions而领域动作则在 UseCase 执行后触发刷新deleteWebhook: async (id: string) { await this.deleteWebhookUseCase.execute(id); await this.listPresenter.actions.refresh(); }, triggerWebhook: async (id: string) { await this.triggerWebhookUseCase.execute(id, { test: true }); await this.listPresenter.actions.refresh(); }6.4 视图作用域容器 observer 组件WebhookListView是列表页入口组件体现了按视图隔离依赖的作用域容器模式用useMemo基于根容器createChildContainer()创建子容器在子容器中register五个 FeatureListWebhooksFeature、DeleteWebhookFeature、TriggerWebhookFeature、WebhookPermissionsFeature、WebhookListPresenterFeature再用DiContainerProvider包裹内部组件。内部组件通过useFeature(WebhookListPresenterFeature)拿到 Presenter在useEffect中调用presenter.init()。视图骨架的关键结构最终 UI 细节以浏览器可见后打磨为准顶栏Heading level{5}显示标题Webhooks右侧在vm.permissions.canCreate为真时渲染Create Webhook按钮点击navigate(Routes.Form, { id: new })跳转新建主体预留DataTable挂载点计划中的列为name、endpointUrl、enabled、createdOn行操作包含 Edit、Trigger、Delete。仓库中的落地实现见 WebhookListView.tsx且组件拆分更细CreateWebhookButton、WebhookDeliveriesButton、WebhookListContent还新增了投递日志入口按钮。七、Task 5WebhookForm 表现层——FormModel 生命周期管理表单表现层依赖 Task 1-3由 5 个文件组成admin/presentation/WebhookForm/{abstractions, WebhookFormPresenter, feature, index}.ts admin/presentation/WebhookForm/components/WebhookFormView.tsx7.1 视图模型IWebhookFormViewModel比列表更丰富覆盖表单的完整状态export interface IWebhookFormViewModel { loading: boolean; saving: boolean; isNew: boolean; webhook: Webhook | null; showDeliveries: boolean; availableEvents: WebhookEvent[]; permissions: { canEdit: boolean; canDelete: boolean; }; }IWebhookFormActions提供save()、deleteWebhook()、openDeliveries()、closeDeliveries()四个动作init(id: string)负责初始化。7.2 Presenter并行加载与新建/编辑分流WebhookFormPresenterImpl构造函数注入 7 个依赖FormModelFactory.Interface、GetWebhookUseCase、CreateWebhookUseCase、UpdateWebhookUseCase、DeleteWebhookUseCase、ListAvailableEventsUseCase、WebhookPermissions。init(id)是生命周期核心处理两条路径async init(id: string): Promisevoid { this._loading true; this._isNew id new; this._webhookId id new ? null : id; const eventsPromise this.listAvailableEventsUseCase.execute(); if (!this._isNew) { const [webhook, events] await Promise.all([ this.getWebhookUseCase.execute(id), eventsPromise ]); runInAction(() { this._webhook webhook; this._availableEvents events; this._loading false; }); } else { const events await eventsPromise; runInAction(() { this._availableEvents events; this._loading false; }); } }要点通过id new区分新建/编辑这依赖路由层传入的特殊值可订阅事件列表无论新建还是编辑都会加载且编辑场景下与 Webhook 详情用Promise.all并行拉取缩短等待时间所有状态变更包在runInAction中保证 MobX 事务一致性。actions.save()当前是骨架置_saving true后真正的 FormModel 提交与 create/update 分流需要在验证FormModelFactory运行时 API 后接入init()与save()deleteWebhook()仅在非新建且有_webhookId时执行删除。7.3 视图与仓库落地WebhookFormView与列表页同构子容器注册GetWebhookFeature、CreateWebhookFeature、UpdateWebhookFeature、DeleteWebhookFeature、ListAvailableEventsFeature、WebhookPermissionsFeature、WebhookFormPresenterFeature内部组件在useEffect中presenter.init(id)其中id来自useRouter().paramsloading时渲染OverlayLoader。顶栏逻辑新建时标题为Create Webhook编辑时显示vm.webhook?.name非新建场景显示Deliveries按钮actions.openDeliveries()vm.permissions.canEdit为真时显示 Save 按钮disabled{vm.saving}文案随saving在Saving...与Save间切换。表单字段预留为name、slug、endpointUrl、description、enabled、events已有 Webhook 的签名密钥Signing Secret以只读方式展示——仓库中已落地为独立的 SigningSecret.tsx 组件。八、Task 6WebhookDeliveries 表现层——投递日志投递日志表现层依赖 Task 1 与 Task 3计划以抽屉Drawer形式呈现由 6 个文件组成admin/presentation/WebhookDeliveries/{abstractions, WebhookDeliveriesDataSource, WebhookDeliveriesPresenter, feature, index}.ts admin/presentation/WebhookDeliveries/components/WebhookDeliveriesDrawer.tsx8.1 契约IWebhookDeliveriesViewModel由两部分组成共享列表状态IListViewModelWebhookDelivery与当前选中的投递详情selectedDelivery: WebhookDelivery | null。IWebhookDeliveriesActions在共享动作之外增加resend(id)与selectDelivery(delivery | null)。8.2 数据源与 PresenterWebhookDeliveriesDataSource与列表数据源结构几乎一致区别在于构造函数多注入一个webhookIdquery/loadMore始终以该webhookId调用ListWebhookDeliveriesUseCase——数据源按 Webhook 隔离投递记录。WebhookDeliveriesPresenterImpl注入三个依赖ListPresenter.InterfaceWebhookDelivery、ListWebhookDeliveriesUseCase、ResendWebhookDeliveryUseCase。init(webhookId)同样装配共享列表this.listPresenter.init({ dataSource: new WebhookDeliveriesDataSource(this.listDeliveriesUseCase, webhookId), initialSort: { field: createdOn, direction: DESC }, limit: 20 });resend(id)执行重发 UseCase 后刷新列表selectDelivery(delivery)直接写入_selectedDeliveryMobX 自动观察。8.3 抽屉组件WebhookDeliveriesDrawer接收{ webhookId, open, onClose }三个 props仅在open时presenter.init(webhookId)useEffect依赖[presenter, webhookId, open]。子容器只注册三个 FeatureListWebhookDeliveriesFeature、ResendWebhookDeliveryFeature、WebhookDeliveriesPresenterFeature。抽屉内容预留投递列表每行eventType、status、createdOn、responseStatus带状态徽标与重发按钮和选中投递详情payload、headers、response。实现演进说明仓库最终把投递日志从抽屉升级为独立路由页面 WebhookDeliveriesPage并拆出DeliveryAccordionRow、DeliveryFilters、DeliveryDetailContent、DeliveryBottomInfoBar、statusVariant等组件同时在 routes.ts 增加了Webhooks/Deliveries路由/webhooks/deliveries可选参数webhookId。这印证了先以结构骨架打通数据流再在浏览器中打磨 UI的计划策略。九、Task 7Extension 装配——把一切接进 AdminTask 7 依赖全部前置任务负责顶层装配共 3 个文件admin/Extension.tsx admin/WebhookRoutes.tsx src/exports/admin/webhooks.ts9.1 WebhookRoutes路由 菜单 权限守卫WebhookRoutes使用AdminConfig声明路由与菜单并用HasPermission整体守卫export const WebhookRoutes () { const { getLink } useRouter(); return ( AdminConfig HasPermission entitywebhook Route route{Routes.List} element{ AdminLayout titleWebhooksWebhookListView //AdminLayout } / Route route{Routes.Form} element{ AdminLayout titleWebhooksWebhookFormView //AdminLayout } / Menu namewebhooks aftersettings element{ Menu.Link textWebhooks to{getLink(Routes.List)} / } / /HasPermission /AdminConfig ); };要点两条路由都包在AdminLayout titleWebhooks中获得统一的管理端布局菜单项namewebhooks、aftersettings控制菜单位置整个区块被HasPermission entitywebhook包裹无权限用户看不到路由入口与菜单。9.2 ExtensionFeature 总注册Extension组件把所有 Feature 一次性注册进根容器分为三层export const Extension () { return ( {/* Headless features. */} RegisterFeature feature{ListWebhooksFeature} / RegisterFeature feature{GetWebhookFeature} / RegisterFeature feature{CreateWebhookFeature} / RegisterFeature feature{UpdateWebhookFeature} / RegisterFeature feature{DeleteWebhookFeature} / RegisterFeature feature{ListWebhookDeliveriesFeature} / RegisterFeature feature{TriggerWebhookFeature} / RegisterFeature feature{ResendWebhookDeliveryFeature} / RegisterFeature feature{ListAvailableEventsFeature} / RegisterFeature feature{WebhookPermissionsFeature} / {/* Presentation features. */} RegisterFeature feature{WebhookListPresenterFeature} / RegisterFeature feature{WebhookFormPresenterFeature} / RegisterFeature feature{WebhookDeliveriesPresenterFeature} / {/* Routes menu. */} WebhookRoutes / {/* Security permissions UI. */} AdminConfig Security.Permissions namewebhooks titleWebhooks descriptionManage webhook permissions. schema{WEBHOOK_PERMISSIONS_SCHEMA} / /AdminConfig / ); };Security.Permissions把权限 Schema 注册进管理端安全设置界面运维人员即可在 UI 中配置 Webhooks 权限。仓库落地文件为 Webhooks.tsx对外导出名称为Webhooks见 index.ts。9.3 导出与提交流程src/exports/admin/webhooks.ts只做一件事export { Extension } from ../../admin/Extension.js;。随后执行计划规定的提交流程git add . yarn /dev/null 21 node scripts/generateTsConfigsInPackages.js yarn adio yarn format /dev/null 21 yarn lint yarn webiny sync-dependencies git add .这些命令对应仓库根目录的脚本体系scripts/generateTsConfigsInPackages.js为各包生成 tsconfigyarn adiowebiny.config 提供的 lint 命令检查代码规范yarn webiny sync-dependencies同步依赖版本。十、计划中的明确边界与后续事项Notes实施计划末尾对已知边界做了诚实标注这对任何 Agent 或开发者执行计划都至关重要UI 组件是结构骨架DataTable列定义、FormModel字段渲染、Drawer内容都将在功能接线完成、浏览器可见后再细化。Presenters 与数据流是完整的——这意味着数据正确性的验证可以先行视觉层可后置迭代。仓库实现印证了这一节奏骨架已演进出WebhookDeliveriesPage、DeliveryFilters、SigningSecret等完整组件。FormModel 集成待运行时验证WebhookFormPresenter中的buildForm()需要在确认FormModelFactory运行时 API 后接入init()与actions.save()字段定义以 specdocs/superpowers/specs/2026-05-16-webhooks-admin-ui-design.md为准。Features 层不做单元测试网关与用例是薄委托层gateway → SDK、usecase → gateway测试它们等于测试框架本身。Presenter 测试留待后续阶段补充。十一、结语从计划到落地的一手参照本文所述三层范式在仓库中并非纸面设计——packages/webhooks/src/admin/下 13 个 Feature、3 个表现层 Presenter、完整的安全与路由装配均已落地且在此过程中演进出了 Settings 类 Feature、独立投递日志页与更细的组件拆分。阅读本指南时可对照以下文件深化理解实现骨架packages/webhooks/src/admin/SDK 契约WebhooksSdk.ts 与 sdk/src/methods/webhooks/权限 Schemaadmin/permissions.ts路由定义admin/routes.tsDI 基础设施packages/feature/src/admin/对希望在 Webiny 中新增一个管理端模块的团队而言这份计划的五文件 Feature 范式 共享 ListPresenter/FormModel 作用域容器 权限 Schema组合本身就是一套可复制的最小可行方法论先以 Gateway/UseCase 打通数据再用 Presenter 承载状态最后让 React 视图保持纯粹——这正是 Webiny 管理端架构在源码层面的真实写照。赞分享CMS后端前端【免费下载链接】webiny-jsOpen-source, self-hosted CMS platform on AWS serverless (Lambda, DynamoDB, S3). TypeScript framework with multi-tenancy, lifecycle hooks, GraphQL API, and AI-assisted development via MCP server. Built for developers at large organizations.项目地址https://gitcode.com/gh_mirrors/we/webiny-js点击查看免费下载相关推荐为什么你的团队需要mention-bot5个提升协作效率的理由为什么你的团队需要mention bot5个提升协作效率的理由 在大型GitHub项目中团队成员往往难以追踪所有代码变更和拉取请求导致重要PR长时间无人审开发工具nanoMODBUS架构深度解析企业级工业通信的轻量化解决方案nanoMODBUS架构深度解析企业级工业通信的轻量化解决方案 在工业物联网和边缘计算快速发展的今天资源受限的嵌入式系统面临着工业通信协议集成的严峻挑战。传CMS后端前端Keystone 6 自定义 Admin UI 页面基于 /admin/pages 目录构建自定义管理页面的完整实战指南Keystone 6 自定义 Admin UI 页面基于 /admin/pages 目录构建自定义管理页面的完整实战指南 导读 Keystone 6 的 Ad后端上一篇gojsonpointer 详解go-openapi/jsonpointer 的 JSON Pointer 实现及其在 OpenShift 测试套件中的应用下一篇gallery扩展开发如何为数字展馆添加新的交互功能与特效创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

Bootstrap Icons 的 camera-video-fill 图标:源码结构、字体映射与使用指南
Bootstrap Icons 的 camera-video-fill 图标:源码结构、字体映射与使用指南

前端 【免费下载链接】icons Official open source SVG icon library for Bootstrap. 项目地址: https://gitcode.com/gh_mirrors/ic/icons 点击查看 免费下载 本篇技术指南以 Bootstrap Icons 官方开源仓库中的 camera-video-fill(实心摄像机视频&… · 2026/9/28 3:09:20

怎样做自己的用编程做自己的小程序? 原创
怎样做自己的用编程做自己的小程序? 原创

大家可以下载一个TRAE CN的软件 这个软件中呢可以有a i帮写 只需要把指令给到ai ai就可以帮你完成整个的a p p中间可以加一些调整我这边给一些在我做小程序的时候遇到的一些问题 比如说你很长时间你没有打开这个软件 然后你发现你再一进去然后之前写的那些代码全都没有了 然… · 2026/9/28 3:09:20

chdman 把 4.4GB 压到 1.5GB:PS2/PS1 ISO 转 CHD 压缩完整教程
chdman 把 4.4GB 压到 1.5GB:PS2/PS1 ISO 转 CHD 压缩完整教程

chdman 把 4.4GB 压到 1.5GB:PS2/PS1 ISO 转 CHD 压缩完整教程 【免费下载链接】romm A beautiful, powerful, self-hosted ROM manager and player. 项目地址: https://gitcode.com/GitHub_Trending/rom/romm 用 chdman 做游戏 ROM 的 CHD 压缩,… · 2026/9/28 3:09:20

Spingboot启动预热的实现
Spingboot启动预热的实现

启动预热的适用场景启动预热适合以下情况:数据主要来自第三方接口,无法直接从本地数据库读取。第三方接口响应较慢,首次访问容易超时。一个页面需要调用多个第三方接口或逐项查询。数据读取频繁,但变化不频繁。希望服务启动后&… · 2026/9/28 3:40:12

Understanding Driving Risks using Large Language Models: Toward Elderly Driver Assessment
Understanding Driving Risks using Large Language Models: Toward Elderly Driver Assessment

文章主要内容总结 本文研究了多模态大语言模型(具体为ChatGPT-4o)利用静态行车记录仪图像进行类人交通场景解读的潜力,重点聚焦与老年司机评估相关的三项任务:交通密度评估、交叉口可见性评估和停车标志识别。这些任务需上下文推理而非简单目标检测。研究采用零样本、少样… · 2026/9/28 3:32:43

Leveraging Large Language Models for Classifying App Users‘ Feedback
Leveraging Large Language Models for Classifying App Users‘ Feedback

文章主要内容总结 本文聚焦于利用大型语言模型(LLMs)解决应用用户反馈分类的挑战,传统方法依赖有监督机器学习,但受限于标注数据集的规模和质量。研究通过三个核心实验评估了4种先进LLMs(GPT-3.5-Turbo、GPT-4o、Flan-T5、Llama3-70b)的性能: LLMs在用户反馈分类中的基… · 2026/9/28 3:32:43

Using Large Language Models for Legal Decision-Making in Austrian Value-Added Tax Law: An Experim...
Using Large Language Models for Legal Decision-Making in Austrian Value-Added Tax Law: An Experim...

文章主要内容总结 本文通过实验评估了大型语言模型(LLMs)在奥地利及欧盟增值税(VAT)法框架下辅助法律决策的能力。研究聚焦于两种提升LLM性能的方法——微调(fine-tuning)和检索增强生成(RAG),并在两类案例中进行验证:一是权威教科书案例,二是税务咨询公司的真实案… · 2026/9/28 3:32:43

学Java别走弯路,这5个方向最吃香
学Java别走弯路,这5个方向最吃香

学Java的人很多,但学明白的人不多。有人学了半年还在写控制台程序,有人一年就能独当一面。差别不在天赋,而在方向。Java生态太庞大了,什么都学等于什么都没学。选对方向,事半功倍。今天盘点当前最吃香的5个Java方向&am… · 2026/9/28 3:32:15

AlphaAgents: Large Language Model based Multi-Agents for Equity Portfolio Constructions
AlphaAgents: Large Language Model based Multi-Agents for Equity Portfolio Constructions

AlphaAgents相关总结与翻译 一、文章主要内容总结 (一)研究背景与问题 传统股票投资组合管理依赖人类分析师处理海量信息(如财务披露、财报、市场新闻等),存在信息处理效率低、易受认知偏差(如损失厌恶、过度自信)影响的问题,可能错失投资收益机会。尽管AI在数据处理… · 2026/9/28 3:32:08

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

制作网页比较方便的软件怎么选?一文搞懂避坑指南
制作网页比较方便的软件怎么选?一文搞懂避坑指南

制作网页比较方便的软件怎么选?一文搞懂避坑指南 很多老板一上来就问:做个网站多少钱?但我反问他:你的域名买了吗?服务器租了吗?他一脸懵。这就是典型的“域名服务器搞不懂”。别急,今天咱们不聊虚的,直接 一文搞懂 那些让你头秃的技术名词。… · 2026/9/28 0:00:06

婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量
婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量

婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量 找婚恋网站建站公司,最怕的就是被坑高价。很多同行跟我吐槽,报价单上写得模棱两可,功能栏里全是“高级定制”、“专属UI”,结果落地全是套壳。今天不聊虚的,直接甩几个我经手的 实战案例… · 2026/9/28 0:00:19

济南做网站多少钱:3个案例拆解,防黑源码下载全攻略
济南做网站多少钱:3个案例拆解,防黑源码下载全攻略

济南做网站多少钱:3个案例拆解,防黑源码下载全攻略 上周济南一个做建材的老板找我,脸都绿了。他的官网首页弹出了赌博广告,后台被植入了挖矿脚本。他慌得问我:“网站被黑挂马不知道怎么办?能不能直接找之前的外包公司要源码下载,看看哪里被动了手脚?… · 2026/9/28 0:00:25

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码