feat: add pi lab ai management integration
This commit is contained in:
@@ -261,6 +261,88 @@ pub async fn user_access_policy_entry(
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn admin_ai_entry(
|
||||
State(state): State<AppState>,
|
||||
Extension(context): Extension<RequestContext>,
|
||||
) -> Result<Response, WebError> {
|
||||
if !has_real_auth_context(&state, &context) {
|
||||
let mut response = Response::builder()
|
||||
.status(StatusCode::SEE_OTHER)
|
||||
.header(header::LOCATION, "/auth")
|
||||
.body(Body::empty())
|
||||
.map_err(|error| WebError::internal(format!("认证入口跳转响应构造失败: {error}")))?;
|
||||
stamp_gateway_headers(response.headers_mut(), false);
|
||||
return Ok(response);
|
||||
}
|
||||
if !is_local_access_policy_admin_context(&context) {
|
||||
return Err(WebError::new(
|
||||
StatusCode::FORBIDDEN,
|
||||
"ai_admin_required",
|
||||
"只有管理员可以访问 AI 管理中心",
|
||||
)
|
||||
.with_context(&context));
|
||||
}
|
||||
ai_management_response(&state, &context, true)
|
||||
}
|
||||
|
||||
pub async fn user_ai_entry(
|
||||
State(state): State<AppState>,
|
||||
Extension(context): Extension<RequestContext>,
|
||||
) -> Result<Response, WebError> {
|
||||
if !has_real_auth_context(&state, &context) {
|
||||
let mut response = Response::builder()
|
||||
.status(StatusCode::SEE_OTHER)
|
||||
.header(header::LOCATION, "/auth")
|
||||
.body(Body::empty())
|
||||
.map_err(|error| WebError::internal(format!("认证入口跳转响应构造失败: {error}")))?;
|
||||
stamp_gateway_headers(response.headers_mut(), false);
|
||||
return Ok(response);
|
||||
}
|
||||
ai_management_response(&state, &context, false)
|
||||
}
|
||||
|
||||
fn ai_management_response(
|
||||
state: &AppState,
|
||||
context: &RequestContext,
|
||||
is_admin: bool,
|
||||
) -> Result<Response, WebError> {
|
||||
let workspace_name = default_workspace_name_for_context(state, context);
|
||||
let content = crate::ssr::render_view(leptos::view! {
|
||||
<crate::ssr::pages::ai_admin::AiManagementPage
|
||||
workspace_name={workspace_name}
|
||||
is_admin={is_admin}
|
||||
/>
|
||||
});
|
||||
let title = if is_admin { "AI 管理" } else { "AI 设置" };
|
||||
let shell = if is_admin {
|
||||
"admin-ai"
|
||||
} else {
|
||||
"user-ai-admin"
|
||||
};
|
||||
let mut response = Html(format!(
|
||||
r#"<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{}</title>
|
||||
<style>{}</style>
|
||||
</head>
|
||||
<body data-mnote-web-owner="mnote-web" data-mnote-shell="{}" data-mnote-actor-id="{}">
|
||||
{}
|
||||
</body>
|
||||
</html>"#,
|
||||
title,
|
||||
crate::ssr::MNOTE_CSS,
|
||||
shell,
|
||||
escape_html(context.auth.actor_id.as_str()),
|
||||
content
|
||||
))
|
||||
.into_response();
|
||||
stamp_gateway_headers(response.headers_mut(), false);
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn root_entry(
|
||||
State(state): State<AppState>,
|
||||
Extension(context): Extension<RequestContext>,
|
||||
@@ -579,6 +661,21 @@ pub async fn root_entry(
|
||||
escape_script_json(&panes_bootstrap_json),
|
||||
render_editor_island_adapter_script(),
|
||||
);
|
||||
let body_extra = if state.config().enable_page_ai_pi_lab {
|
||||
body_extra
|
||||
+ &format!(
|
||||
r#"<script>
|
||||
(function() {{
|
||||
var s = document.createElement('script');
|
||||
s.src = '/api/mnote-browser-runtime/sidebar-page-ai-pi-lab-runtime.js';
|
||||
s.onload = function() {{ if (window.createSidebarPageAiPiLabRuntime) window.createSidebarPageAiPiLabRuntime({{}}); }};
|
||||
document.body.appendChild(s);
|
||||
}})();
|
||||
</script>"#
|
||||
)
|
||||
} else {
|
||||
body_extra
|
||||
};
|
||||
("MNOTE".to_string(), render_workspace_entry(), body_extra)
|
||||
} else {
|
||||
match build_page_aggregate_snapshot(
|
||||
@@ -639,6 +736,21 @@ pub async fn root_entry(
|
||||
render_document_title_controller_script(),
|
||||
render_editor_island_adapter_script(),
|
||||
);
|
||||
let body_extra = if state.config().enable_page_ai_pi_lab {
|
||||
body_extra
|
||||
+ &format!(
|
||||
r#"<script>
|
||||
(function() {{
|
||||
var s = document.createElement('script');
|
||||
s.src = '/api/mnote-browser-runtime/sidebar-page-ai-pi-lab-runtime.js';
|
||||
s.onload = function() {{ if (window.createSidebarPageAiPiLabRuntime) window.createSidebarPageAiPiLabRuntime({{}}); }};
|
||||
document.body.appendChild(s);
|
||||
}})();
|
||||
</script>"#
|
||||
)
|
||||
} else {
|
||||
body_extra
|
||||
};
|
||||
(title.to_string(), content, body_extra)
|
||||
}
|
||||
Err(_) => ("MNOTE".to_string(), render_workspace_entry(), String::new()),
|
||||
@@ -2554,6 +2666,7 @@ mod tests {
|
||||
enable_legacy_next_compat,
|
||||
enable_debug_shell_routes: false,
|
||||
enable_editor_actor: true,
|
||||
enable_page_ai_pi_lab: false,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url,
|
||||
@@ -3074,6 +3187,7 @@ mod tests {
|
||||
enable_legacy_next_compat: false,
|
||||
enable_debug_shell_routes: false,
|
||||
enable_editor_actor: true,
|
||||
enable_page_ai_pi_lab: false,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url: None,
|
||||
@@ -3366,6 +3480,7 @@ mod tests {
|
||||
enable_legacy_next_compat: false,
|
||||
enable_debug_shell_routes: false,
|
||||
enable_editor_actor: true,
|
||||
enable_page_ai_pi_lab: false,
|
||||
hermes_base_path: "/api/hermes".into(),
|
||||
compat_next_base_path: "/api/compat/next".into(),
|
||||
convex_url: None,
|
||||
|
||||
Reference in New Issue
Block a user