chore: align sqlite control plane architecture

- replace default Convex control-plane wording with Rust SQLite control-plane across architecture, AGENTS, Reasonix, and design docs

- retire root Convex functions source and deploy script into recycle while keeping explicit cloud/compat/sync-replica boundaries

- add control-plane migration guard/docs and keep CodeGraph refreshed after the SQLite control-plane cutover
This commit is contained in:
lix-2026
2026-05-22 17:45:22 +08:00
parent 531e845600
commit 47e224d419
79 changed files with 7634 additions and 2600 deletions
+65 -22
View File
@@ -1,5 +1,6 @@
//! MNOTE 通用页面布局组件(Wolai / Notion 风格)
use crate::ssr::pages::admin::AdminAccessPolicyPanel;
use leptos::prelude::*;
const SIDEBAR_TREE_JS: &str = r##"
@@ -1227,6 +1228,12 @@ const SIDEBAR_TREE_JS: &str = r##"
if (existing && existing.parentElement) existing.parentElement.removeChild(existing);
}
function closeAdminAccessPolicyDialog() {
var existing = document.querySelector('[data-testid="mnote-admin-access-policy-modal"]');
if (existing && existing.parentElement) existing.parentElement.removeChild(existing);
document.documentElement.removeAttribute('data-mnote-admin-access-policy-modal-open');
}
function accountMenuFallbackSession() {
var body = document.body instanceof HTMLElement ? document.body : null;
var actorId = body ? String(body.getAttribute('data-mnote-actor-id') || '').trim() : '';
@@ -1263,10 +1270,6 @@ const SIDEBAR_TREE_JS: &str = r##"
return String(session && session.actorType || '').trim() === 'admin';
}
function accessPolicyHrefForSession(session) {
return sessionIsAdmin(session) ? '/admin/access-policy' : '/user/access-policy';
}
async function loadAccountInfo(menu) {
try {
var response = await fetch('/api/auth/session', {
@@ -1346,6 +1349,43 @@ const SIDEBAR_TREE_JS: &str = r##"
if (closeButton instanceof HTMLElement) closeButton.focus();
}
function openAdminAccessPolicyDialog(trigger) {
closeAdminAccessPolicyDialog();
closeAccountMenu();
if (!(trigger instanceof HTMLElement)) return;
var role = trigger.getAttribute('data-access-policy-role') === 'admin' ? 'admin' : 'user';
var template = document.querySelector('[data-testid="mnote-admin-access-policy-template-' + role + '"]');
var dialog = document.createElement('div');
dialog.className = 'mnote-admin-policy-modal';
dialog.setAttribute('data-testid', 'mnote-admin-access-policy-modal');
dialog.setAttribute('role', 'dialog');
dialog.setAttribute('aria-modal', 'true');
dialog.setAttribute('aria-labelledby', 'mnote-admin-policy-dialog-title');
dialog.innerHTML =
'<div class="mnote-admin-policy-modal__backdrop" data-admin-access-policy-close></div>' +
'<section class="mnote-admin-policy-modal__panel">' +
'<button type="button" class="mnote-admin-policy-modal__close" data-admin-access-policy-close aria-label="关闭授权管理"><span class="material-symbols-outlined" data-icon="close" aria-hidden="true"></span></button>' +
'<div class="mnote-admin-policy-modal__content" data-testid="mnote-admin-access-policy-modal-content"></div>' +
'</section>';
var content = dialog.querySelector('[data-testid="mnote-admin-access-policy-modal-content"]');
if (content) {
content.innerHTML = template ? template.innerHTML : '<div class="mnote-admin-policy-empty"></div>';
}
if (typeof window.MNOTEInitAccessPolicyPanel === 'function') {
window.MNOTEInitAccessPolicyPanel(dialog);
}
dialog.querySelectorAll('[data-admin-access-policy-close]').forEach(function(button) {
button.addEventListener('click', function(event) {
event.preventDefault();
closeAdminAccessPolicyDialog();
});
});
document.body.appendChild(dialog);
document.documentElement.setAttribute('data-mnote-admin-access-policy-modal-open', 'true');
var closeButton = dialog.querySelector('.mnote-admin-policy-modal__close');
if (closeButton instanceof HTMLElement) closeButton.focus();
}
async function signOutAccount(trigger) {
setCommandPending(trigger, true);
try {
@@ -1382,7 +1422,7 @@ const SIDEBAR_TREE_JS: &str = r##"
menu.setAttribute('role', 'menu');
menu.innerHTML =
'<button type="button" class="mnote-workspace-source-menu__item mnote-account-menu__item" data-testid="mnote-account-profile" role="menuitem"><span class="material-symbols-outlined" data-icon="account_circle" aria-hidden="true"></span><span></span></button>' +
'<a class="mnote-workspace-source-menu__item mnote-account-menu__item" data-testid="mnote-account-access-policy" role="menuitem" href="/user/access-policy"><span class="material-symbols-outlined" data-icon="admin_panel_settings" aria-hidden="true"></span><span></span></a>' +
'<button type="button" class="mnote-workspace-source-menu__item mnote-account-menu__item" data-testid="mnote-account-access-policy" role="menuitem" hidden><span class="material-symbols-outlined" data-icon="admin_panel_settings" aria-hidden="true"></span><span></span></button>' +
'<button type="button" class="mnote-workspace-source-menu__item mnote-account-menu__logout" data-testid="mnote-account-sign-out" role="menuitem">退</button>' +
'<div class="mnote-account-menu__error" data-account-error hidden></div>';
var sessionPromise = fetchAccountSession();
@@ -1395,8 +1435,16 @@ const SIDEBAR_TREE_JS: &str = r##"
}
var accessPolicyLink = menu.querySelector('[data-testid="mnote-account-access-policy"]');
sessionPromise.then(function(session) {
if (accessPolicyLink instanceof HTMLElement) accessPolicyLink.setAttribute('href', accessPolicyHrefForSession(session));
if (!(accessPolicyLink instanceof HTMLElement)) return;
accessPolicyLink.hidden = false;
accessPolicyLink.setAttribute('data-access-policy-role', sessionIsAdmin(session) ? 'admin' : 'user');
});
if (accessPolicyLink) {
accessPolicyLink.addEventListener('click', function(event) {
event.preventDefault();
openAdminAccessPolicyDialog(accessPolicyLink);
});
}
var signOutButton = menu.querySelector('[data-testid="mnote-account-sign-out"]');
if (signOutButton) {
signOutButton.addEventListener('click', function(event) {
@@ -9996,13 +10044,14 @@ pub fn PageLayout(
/// 顶栏当前页面标题(可选)
#[prop(optional)]
topbar_title: Option<String>,
/// 是否显示管理员授权入口
/// 是否显示管理员授权能力
#[prop(optional)]
show_admin_access_policy: bool,
/// 是否启用树实时流
#[prop(optional, default = true)]
enable_tree_live: bool,
) -> impl IntoView {
let _ = show_admin_access_policy;
let sidebar_tree_html = sidebar_tree_html.unwrap_or_default();
let ws_name = workspace_name
@@ -10042,6 +10091,12 @@ pub fn PageLayout(
"views": ["page-tree", "file-tree"]
})
.to_string();
let admin_access_policy_template = crate::ssr::render_view(leptos::view! {
<AdminAccessPolicyPanel workspace_name={ws_name.clone()} is_admin=true boot_script=false />
});
let user_access_policy_template = crate::ssr::render_view(leptos::view! {
<AdminAccessPolicyPanel workspace_name={ws_name.clone()} is_admin=false boot_script=false />
});
view! {
<div class="mnote-shell wolai-workspace-shell" data-mnote-web-owner="mnote-web" data-mnote-shell="workspace">
@@ -10068,21 +10123,6 @@ pub fn PageLayout(
<a href="/help" title="帮助" aria-label="帮助"><span class="material-symbols-outlined nav-icon" data-icon="help" aria-hidden="true"></span></a>
<a href="/files" title="文件" aria-label="文件"><span class="material-symbols-outlined nav-icon" data-icon="inventory_2" aria-hidden="true"></span></a>
<button type="button" title="打开本地文件夹" aria-label="打开本地文件夹" data-mnote-action="open-local-folder"><span class="material-symbols-outlined nav-icon" data-icon="folder_open" aria-hidden="true"></span></button>
{if show_admin_access_policy {
view! {
<a
href="/admin/access-policy"
class:active={current_nav == "admin"}
title="目录授权"
aria-label="目录授权"
data-testid="mnote-admin-access-policy-entry"
>
<span class="material-symbols-outlined nav-icon" data-icon="admin_panel_settings" aria-hidden="true"></span>
</a>
}.into_any()
} else {
view! {}.into_any()
}}
<button
type="button"
title="更多"
@@ -10097,6 +10137,9 @@ pub fn PageLayout(
</nav>
<div class="wolai-sidebar-body" inner_html={sidebar_sections_html}></div>
<script id="__MNOTE_TREE_LIVE_BOOTSTRAP__" type="application/json" inner_html={tree_live_bootstrap}></script>
<div hidden data-testid="mnote-admin-access-policy-template-admin" inner_html={admin_access_policy_template}></div>
<div hidden data-testid="mnote-admin-access-policy-template-user" inner_html={user_access_policy_template}></div>
<script inner_html={crate::ssr::pages::admin::ADMIN_POLICY_SCRIPT.to_string()}></script>
<script inner_html={SIDEBAR_TREE_JS.to_string()}></script>
<script id="mnote-tree-live-controller" inner_html={TREE_LIVE_CONTROLLER_JS.to_string()}></script>
</aside>