Add video canvas sidebar setting
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-04-07 00:30:47 +08:00
parent be8cb630f9
commit c74dffdcd6
3 changed files with 97 additions and 2 deletions

View File

@ -418,6 +418,7 @@ type SiteSettings = {
canvasEnabled: boolean;
agentEnabled: boolean;
canvasAgentModeEnabled: boolean;
videoCanvasSidebarEnabled: boolean;
agentCategoryTreeConfig: {
productCategories: string[];
audienceTags: string[];
@ -915,6 +916,7 @@ export function AdminSettingsClient() {
canvasEnabled: true,
agentEnabled: true,
canvasAgentModeEnabled: true,
videoCanvasSidebarEnabled: true,
agentCategoryTreeConfig: {
productCategories: [],
audienceTags: [],
@ -1014,6 +1016,8 @@ export function AdminSettingsClient() {
agentEnabled: (siteSettingsData as any).agentEnabled ?? true,
canvasAgentModeEnabled:
(siteSettingsData as any).canvasAgentModeEnabled ?? true,
videoCanvasSidebarEnabled:
(siteSettingsData as any).videoCanvasSidebarEnabled ?? true,
agentCategoryTreeConfig: {
productCategories: Array.isArray(
(siteSettingsData as any).agentCategoryTreeConfig?.productCategories
@ -8566,6 +8570,27 @@ export function AdminSettingsClient() {
/>
</div>
<div className="flex items-center justify-between rounded-lg border p-3">
<div className="space-y-0.5">
<Label htmlFor="videoCanvasSidebarEnabled">
视频画布模块侧边栏
</Label>
<div className="text-xs text-muted-foreground">
开启后,视频画布左侧显示“视频模块”分层侧边栏;关闭后只保留画布本体与节点快捷添加。
</div>
</div>
<Switch
id="videoCanvasSidebarEnabled"
checked={siteSettings.videoCanvasSidebarEnabled}
onCheckedChange={(checked) =>
setSiteSettings({
...siteSettings,
videoCanvasSidebarEnabled: checked,
})
}
/>
</div>
<div className="flex items-center justify-between rounded-lg border p-3">
<div className="space-y-0.5">
<Label htmlFor="aiDetailGenerationEnabled">

View File

@ -107,6 +107,7 @@ const STORAGE_FAILOVER_CONFIG_KEY = "storage_failover_config";
const REALTIME_CANVAS_CONFIG_KEY = "realtime_canvas_config";
const AGENT_CATEGORY_TREE_CONFIG_KEY = "agent_category_tree_config";
const CANVAS_AGENT_MODE_ENABLED_KEY = "canvas_agent_mode_enabled";
const VIDEO_CANVAS_SIDEBAR_ENABLED_KEY = "video_canvas_sidebar_enabled";
function normalizeHomeVariant(value: unknown): "classic" | "lovart" {
return value === "lovart" ? "lovart" : "classic";
@ -225,6 +226,10 @@ function normalizeCanvasAgentModeEnabled(value: unknown): boolean {
return value !== false;
}
function normalizeVideoCanvasSidebarEnabled(value: unknown): boolean {
return value !== false;
}
function normalizeAgentCategoryTreeConfig(value: unknown): AgentCategoryTreeConfig {
const raw =
value && typeof value === "object" && !Array.isArray(value)
@ -274,6 +279,7 @@ export async function GET() {
dulupayConfigSetting,
realtimeCanvasConfigSetting,
canvasAgentModeEnabledSetting,
videoCanvasSidebarEnabledSetting,
storageFailoverConfigSetting,
ossImageMigrationConfigSetting,
agentPresetLibraryConfigSetting,
@ -380,6 +386,12 @@ export async function GET() {
.where(eq(systemSettings.key, CANVAS_AGENT_MODE_ENABLED_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
.where(eq(systemSettings.key, VIDEO_CANVAS_SIDEBAR_ENABLED_KEY))
.limit(1)
.then(rows => rows[0]),
db
.select()
.from(systemSettings)
@ -491,6 +503,9 @@ export async function GET() {
const canvasAgentModeEnabled = normalizeCanvasAgentModeEnabled(
canvasAgentModeEnabledSetting?.value
);
const videoCanvasSidebarEnabled = normalizeVideoCanvasSidebarEnabled(
videoCanvasSidebarEnabledSetting?.value
);
const storageFailoverConfig = normalizeStorageFailoverConfig(
storageFailoverConfigSetting?.value
);
@ -567,6 +582,7 @@ export async function GET() {
canvasEnabled: true,
agentEnabled: true,
canvasAgentModeEnabled: true,
videoCanvasSidebarEnabled: true,
agentPresetLibraryConfig: defaultAgentPresetLibraryConfig,
agentCategoryTreeConfig: normalizeAgentCategoryTreeConfig(undefined),
agentSecondaryTypeConfig: defaultAgentSecondaryTypeConfig,
@ -643,6 +659,7 @@ export async function GET() {
dulupayConfig,
realtimeCanvasServiceEnabled,
canvasAgentModeEnabled,
videoCanvasSidebarEnabled,
storageFailoverConfig,
ossImageMigrationConfig,
});
@ -689,6 +706,7 @@ const updateSchema = z.object({
canvasEnabled: z.boolean().optional(),
agentEnabled: z.boolean().optional(),
canvasAgentModeEnabled: z.boolean().optional(),
videoCanvasSidebarEnabled: z.boolean().optional(),
agentPresetLibraryConfig: z
.object({
sections: z
@ -1086,6 +1104,7 @@ export async function PUT(request: NextRequest) {
storageFailoverConfig,
ossImageMigrationConfig,
canvasAgentModeEnabled,
videoCanvasSidebarEnabled,
homeAnimationConfig,
...siteSettingsPayload
} = data;
@ -1304,6 +1323,26 @@ export async function PUT(request: NextRequest) {
});
}
if (videoCanvasSidebarEnabled !== undefined) {
const normalized = normalizeVideoCanvasSidebarEnabled(videoCanvasSidebarEnabled);
await db
.insert(systemSettings)
.values({
key: VIDEO_CANVAS_SIDEBAR_ENABLED_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentPresetLibraryConfig !== undefined) {
const normalized = normalizeAgentPresetLibraryConfig(agentPresetLibraryConfig);
await db
@ -1800,6 +1839,10 @@ export async function PUT(request: NextRequest) {
canvasAgentModeEnabled !== undefined
? normalizeCanvasAgentModeEnabled(canvasAgentModeEnabled)
: normalizeCanvasAgentModeEnabled(undefined),
videoCanvasSidebarEnabled:
videoCanvasSidebarEnabled !== undefined
? normalizeVideoCanvasSidebarEnabled(videoCanvasSidebarEnabled)
: normalizeVideoCanvasSidebarEnabled(undefined),
});
} else {
// 创建新设置
@ -2004,6 +2047,26 @@ export async function PUT(request: NextRequest) {
});
}
if (videoCanvasSidebarEnabled !== undefined) {
const normalized = normalizeVideoCanvasSidebarEnabled(videoCanvasSidebarEnabled);
await db
.insert(systemSettings)
.values({
key: VIDEO_CANVAS_SIDEBAR_ENABLED_KEY,
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
})
.onConflictDoUpdate({
target: systemSettings.key,
set: {
value: normalized,
updatedAt: new Date(),
updatedBy: session.user.id,
},
});
}
if (agentPresetLibraryConfig !== undefined) {
const normalized = normalizeAgentPresetLibraryConfig(agentPresetLibraryConfig);
await db
@ -2432,6 +2495,10 @@ export async function PUT(request: NextRequest) {
canvasAgentModeEnabled !== undefined
? normalizeCanvasAgentModeEnabled(canvasAgentModeEnabled)
: normalizeCanvasAgentModeEnabled(undefined),
videoCanvasSidebarEnabled:
videoCanvasSidebarEnabled !== undefined
? normalizeVideoCanvasSidebarEnabled(videoCanvasSidebarEnabled)
: normalizeVideoCanvasSidebarEnabled(undefined),
});
}
} catch (error) {

View File

@ -1225,6 +1225,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
siteLogoDark?: string | null;
agentEnabled?: boolean;
canvasAgentModeEnabled?: boolean;
videoCanvasSidebarEnabled?: boolean;
realtimeCanvasEnabled?: boolean;
realtimeCanvasServiceEnabled?: boolean;
agentWorkflowShowcaseConfig?: AgentWorkflowShowcaseConfig;
@ -1267,6 +1268,8 @@ export default function CanvasEditorPage({ params }: PageProps) {
const isAgentWorkspaceEnabled = siteSettingsData?.agentEnabled !== false;
const isCanvasAgentModeEnabled =
siteSettingsData?.canvasAgentModeEnabled !== false;
const isVideoModuleSidebarEnabled =
siteSettingsData?.videoCanvasSidebarEnabled !== false;
const isAgentMode = isAgentWorkspaceEnabled && requestedAgentMode;
const hasLoadedCurrentAgentProject =
!requestedAgentMode ||
@ -1401,7 +1404,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
selectedWorkflowQuickConnectAnchor && selectedVideoWorkflowNode
? selectedVideoWorkflowNode
: null;
const videoModuleSidebarWidth = isVideoMode
const videoModuleSidebarWidth = isVideoMode && isVideoModuleSidebarEnabled
? isVideoModuleSidebarCollapsed
? 58
: 236
@ -8289,7 +8292,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
</DropdownMenu>
) : null}
{isVideoMode ? (
{isVideoMode && isVideoModuleSidebarEnabled ? (
<div
className="pointer-events-auto absolute top-16 left-4 z-20"
style={{ width: `${videoModuleSidebarWidth}px` }}