feat: video generation console, admin settings and plugin catalog - #12
Merged
Merged
Conversation
The reference-image roles users pick in the console were dropped at the queue boundary, so video plugins always received images in array order and a first/last frame pair could silently land in the wrong slot. MediaInputImage now carries the stored role, the worker forwards it as extra.imageRoles only when every image has a role the plugin can place (a partial list, an untagged legacy row, or a prompt_image/source_video keeps today's positional behaviour instead of being rejected upstream), and Veo resolves the list into image/lastFrame/referenceImages.
A rejected generation only surfaced an error code, so users saw PROVIDER_REJECTED with no way to tell what to fix. jobDto now returns the already-trimmed provider_error.detail as errorMessage, capped at 300 chars, and reads that one field instead of spreading the object: HTTP status, provider reference ids and any other transport metadata stay server-side.
…tors Video controls used to hardcode one dropdown set, which broke as soon as two plugins spelled the same parameter differently (Veo takes string enums, Seedance integer seconds). generation-params now resolves every field through the selected model's declared descriptors with an alias table, so wire keys and value types come from the descriptor itself and the panel renders only what a model actually supports; the store holds a videoParams map instead of four fixed fields, so switching models needs no reset and the model choice is remembered per 图像/视频 tab. Reference images are staged under the role the chosen model reserves for them (首帧 / 尾帧 / 参考图) and reconcileStagedRoles re-assigns roles on model change, blocking submit rather than silently dropping an overflow. An active-jobs board reports queue position, phase, elapsed time, cancel-in flight and the new job errorMessage; media-frame renders image and video outputs behind one surface.
The grid assumed every asset is a downloadable still. It now renders through media-frame, adds an 全部/图像/视频 segmented filter and reads the preview target from the fetched list so deep links survive a page change. The kind filter is applied client-side over the fetched rows only, because GET /api/library ignores `kind` and returns a fixed 50-row page.
…min shell The /setup wizard stayed reachable after onboarding and its steps were the only editor for site, SMTP, object-storage and runtime limits. Those panels now live at /admin/settings behind the admin guard, and a new /setup/layout redirects a completed setup to it (or to /login), closing the wizard. /admin/plugins catalogs the built-in media provider templates with their credential schema and hosts the create/edit dialog, leaving /admin/providers as the list, delete and connectivity test. provider-templates.ts mirrors the server's plugin-identity matching so a model form only offers a credential whose plugin and version the API would accept.
…the shipped flow /history still 301'd to /generate?tab=history, but the console now splits into 图像/视频 only, so the tab was dead; it points at /library as a temporary redirect instead. The landing page advertised prompt "thinking", a 68% progress tile and other states the product never had, and omitted what it does do; it now walks the real path (model, aspect ratio, reference images, queue with retry and cancel, library, code login, self-hosted admin) with the actual limits stated.
…tests packages/contracts runs tsc over src/endpoints.test.ts, which imports node:test and node:assert/strict, but it was the only package with a typecheck script that never declared @types/node. Locally tsc still passed because ambient types resolve through a stray root node_modules/@types/node; CI's clean frozen install has none, so the run died with TS2307 before checking any later package.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
jobDtosurfaces the already-sanitisedprovider_error.detail, trimmed and capped at 300 chars; status codes and provider reference ids stay server-side. A new active-jobs board shows queue status, phase, elapsed time, cancel-in-flight and that message; the library renders image and video through a sharedmedia-framewith an 全部/图像/视频 filter./setupwizard into/admin/settings, and a new/setup/layoutcloses the wizard once setup is complete./admin/pluginscatalogs the built-in provider templates and their credential schema with a shared create/edit dialog, andprovider-templates.tsmirrors the server's plugin-identity rule so a model form only offers pairings the API would accept./historyno longer redirects to the removed/generate?tab=history; the landing page now describes the shipped flow and its real limits.packages/contractsdeclares@types/node— it typecheckssrc/endpoints.test.ts(node:test,node:assert/strict) without declaring it, which passed locally only because ambient types resolved through a stray rootnode_modules/@types/nodeand failed CI's clean frozen install with TS2307.Commits
68231ad4f6f06f797abb54bc899e1c93d2267e350f49a5233Test plan
pnpm typecheck— clean across all workspace projectspnpm test— 0 failures everywhere (api 84, providers 95, worker 25, domain 7, database 5, contracts 3), including the new Veo role-placement / role-fallback tests and the job-DTO leakage + truncation testtsc --noEmit --typeRoots $PWD/node_modules/@typespasses inpackages/contracts, and an empty typeRoots reproduces the exact CI TS2307 errorspnpm install --frozen-lockfilesucceeds with the updated lockfile49a5233: Media quality (no external services) plus all four image builds and the PostgreSQL rotation check/setupredirects to/admin/settingsoncesetupComplete, and a non-admin is sent to/loginGET /api/libraryignoreskind, so filtering is client-side over the fetched 50-row page)Notes for review
admin-provider-credential-dialog.tsxposts a pasted Google service-account JSON (includingprivate_key) ascredential. The API side is unchanged in this PR — please confirm it encrypts at rest and never echoes the value back.apps/web-next/src/shared/types/index.tscontinues to hand-mirror the API DTOs (errorMessage,Asset.fps/codec/hasAudio/posterAssetId, optionalVideoGenerationOutput.imageUrl); web-next has no test suite andpnpm lintis currently a no-op, so drift here is only caught by hand.