Enhance documentation and admin UI: Add detailed implementation guidelines in CLAUDE.md, introduce a referrer index in README.md, and update admin UI translations for improved user experience. Update package dependencies for better functionality and performance.
This commit is contained in:
120
src/main.rs
120
src/main.rs
@@ -13,6 +13,8 @@ use tracing_subscriber::EnvFilter;
|
||||
|
||||
use rustycms::api::cache::ContentCache;
|
||||
use rustycms::api::handlers::AppState;
|
||||
use rustycms::referrers::{Referrer, ReferrerIndex};
|
||||
use rustycms::schema::validator;
|
||||
use rustycms::schema::SchemaRegistry;
|
||||
use rustycms::store::{filesystem::FileStore, sqlite::SqliteStore, ContentStore};
|
||||
|
||||
@@ -69,33 +71,26 @@ fn detect_locales(content_dir: &std::path::Path) -> Option<Vec<String>> {
|
||||
}
|
||||
|
||||
fn reload_schemas(
|
||||
types_dir: &PathBuf,
|
||||
server_url: &str,
|
||||
registry: &Arc<RwLock<SchemaRegistry>>,
|
||||
openapi_spec: &Arc<RwLock<serde_json::Value>>,
|
||||
cache: &Arc<ContentCache>,
|
||||
rt_handle: tokio::runtime::Handle,
|
||||
types_dir: PathBuf,
|
||||
server_url: String,
|
||||
registry: Arc<RwLock<SchemaRegistry>>,
|
||||
openapi_spec: Arc<RwLock<serde_json::Value>>,
|
||||
cache: Arc<ContentCache>,
|
||||
) {
|
||||
let types_dir = types_dir.clone();
|
||||
let server_url = server_url.to_string();
|
||||
let registry = Arc::clone(registry);
|
||||
let openapi_spec = Arc::clone(openapi_spec);
|
||||
let cache = Arc::clone(cache);
|
||||
std::thread::spawn(move || {
|
||||
let rt = tokio::runtime::Handle::current();
|
||||
rt.block_on(async move {
|
||||
match SchemaRegistry::load(&types_dir) {
|
||||
Ok(new_registry) => {
|
||||
let spec = rustycms::api::openapi::generate_spec(&new_registry, &server_url);
|
||||
*registry.write().await = new_registry;
|
||||
*openapi_spec.write().await = spec;
|
||||
cache.invalidate_all().await;
|
||||
tracing::info!("Hot-reload: schemas and OpenAPI spec updated, content cache cleared");
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Hot-reload failed: {}", e);
|
||||
}
|
||||
rt_handle.spawn(async move {
|
||||
match SchemaRegistry::load(&types_dir) {
|
||||
Ok(new_registry) => {
|
||||
let spec = rustycms::api::openapi::generate_spec(&new_registry, &server_url);
|
||||
*registry.write().await = new_registry;
|
||||
*openapi_spec.write().await = spec;
|
||||
cache.invalidate_all().await;
|
||||
tracing::info!("Hot-reload: schemas and OpenAPI spec updated, content cache cleared");
|
||||
}
|
||||
});
|
||||
Err(e) => {
|
||||
tracing::error!("Hot-reload failed: {}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -223,6 +218,67 @@ async fn main() -> anyhow::Result<()> {
|
||||
tracing::info!("Webhooks enabled: {} URL(s)", webhook_urls.len());
|
||||
}
|
||||
|
||||
// Reverse referrer index (file-based in content dir). Only when not using environments (single content root).
|
||||
// When the index file is missing, run a full reindex over all collections and save.
|
||||
let (referrer_index, referrer_index_path) = if environments.is_none() {
|
||||
let path = assets_dir.parent().unwrap().join("_referrers.json");
|
||||
let index = if path.exists() {
|
||||
ReferrerIndex::load(&path)
|
||||
} else {
|
||||
tracing::info!("Referrer index not found, building full index from content…");
|
||||
let mut index = ReferrerIndex::new();
|
||||
let collections_with_schema: Vec<(String, rustycms::schema::types::SchemaDefinition)> = {
|
||||
let guard = registry.read().await;
|
||||
guard
|
||||
.collection_names()
|
||||
.into_iter()
|
||||
.filter_map(|c| {
|
||||
guard.get(&c).filter(|s| !s.reusable).map(|s| (c, s.clone()))
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
for (collection, schema) in collections_with_schema {
|
||||
let locale_opts: Vec<Option<&str>> = locales
|
||||
.as_ref()
|
||||
.map(|l| l.iter().map(|s| s.as_str()).map(Some).collect())
|
||||
.unwrap_or_else(|| vec![None]);
|
||||
for locale_ref in locale_opts {
|
||||
match store.list(&collection, locale_ref).await {
|
||||
Ok(entries) => {
|
||||
for (slug, value) in entries {
|
||||
let refs = validator::extract_references(&schema, &value);
|
||||
let referrer = Referrer {
|
||||
collection: collection.clone(),
|
||||
slug: slug.clone(),
|
||||
field: String::new(),
|
||||
locale: locale_ref.map(str::to_string),
|
||||
};
|
||||
for (ref_coll, ref_slug, field) in refs {
|
||||
let mut r = referrer.clone();
|
||||
r.field = field;
|
||||
index.add_referrer(&ref_coll, &ref_slug, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => tracing::warn!("List {} (locale {:?}) failed: {}", collection, locale_ref, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Err(e) = index.save(&path) {
|
||||
tracing::warn!("Failed to save referrer index: {}", e);
|
||||
} else {
|
||||
tracing::info!("Referrer index saved to {}", path.display());
|
||||
}
|
||||
index
|
||||
};
|
||||
if path.exists() {
|
||||
tracing::info!("Referrer index loaded from {}", path.display());
|
||||
}
|
||||
(Some(Arc::new(RwLock::new(index))), Some(path))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let state = Arc::new(AppState {
|
||||
registry: Arc::clone(®istry),
|
||||
store,
|
||||
@@ -239,9 +295,12 @@ async fn main() -> anyhow::Result<()> {
|
||||
environments,
|
||||
stores: stores_map,
|
||||
assets_dirs: assets_dirs_map,
|
||||
referrer_index,
|
||||
referrer_index_path,
|
||||
});
|
||||
|
||||
// Hot-reload: watch types_dir and reload schemas on change
|
||||
// Hot-reload: watch types_dir and reload schemas on change (run reload on main Tokio runtime from watcher thread)
|
||||
let rt_handle = tokio::runtime::Handle::current();
|
||||
let types_dir_for_callback = cli.types_dir.canonicalize().unwrap_or_else(|_| cli.types_dir.clone());
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
let mut watcher = RecommendedWatcher::new(
|
||||
@@ -275,7 +334,14 @@ async fn main() -> anyhow::Result<()> {
|
||||
// Debounce: wait for editor to finish writing, drain extra events, then reload once
|
||||
std::thread::sleep(Duration::from_millis(800));
|
||||
while rx.try_recv().is_ok() {}
|
||||
reload_schemas(&types_dir_watch, &server_url_watch, ®istry, &openapi_spec, &cache);
|
||||
reload_schemas(
|
||||
rt_handle.clone(),
|
||||
types_dir_watch.clone(),
|
||||
server_url_watch.clone(),
|
||||
Arc::clone(®istry),
|
||||
Arc::clone(&openapi_spec),
|
||||
Arc::clone(&cache),
|
||||
);
|
||||
}
|
||||
});
|
||||
tracing::info!("Hot-reload: watching {}", cli.types_dir.display());
|
||||
|
||||
Reference in New Issue
Block a user