feat: more closing of M4
This commit is contained in:
@@ -30,6 +30,7 @@ use crate::views::{
|
||||
modal, workspace,
|
||||
post_editor::{LinkedMediaItem, PostEditorMsg, PostEditorState, ResolvedPostLink},
|
||||
media_editor::{LinkedPostItem, MediaEditorState, MediaEditorMsg},
|
||||
site_validation::SiteValidationState,
|
||||
template_editor::{TemplateEditorState, TemplateEditorMsg},
|
||||
script_editor::{ScriptEditorState, ScriptEditorMsg},
|
||||
tags_view::{self, TagsMsg, TagsSection, TagsViewState},
|
||||
@@ -135,7 +136,9 @@ pub enum Message {
|
||||
ValidateMedia,
|
||||
GenerateSite,
|
||||
RunMetadataDiff,
|
||||
RunSiteValidation,
|
||||
EngineTaskDone { task_id: TaskId, label: String, result: Result<String, String> },
|
||||
SiteValidationLoaded(Result<engine::validate_site::SiteValidationReport, String>),
|
||||
|
||||
// Editor views
|
||||
PostEditor(PostEditorMsg),
|
||||
@@ -555,8 +558,11 @@ mod tests {
|
||||
use bds_core::db::fts::ensure_fts_tables;
|
||||
use bds_core::db::queries::project::insert_project;
|
||||
use bds_core::db::Database;
|
||||
use bds_core::engine::{media, post, script, template};
|
||||
use bds_core::engine::{ai, media, post, script, template};
|
||||
use bds_core::model::{Project, ScriptKind, TemplateKind};
|
||||
use std::io::{Read, Write};
|
||||
use std::net::TcpListener;
|
||||
use std::thread;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn make_project() -> Project {
|
||||
@@ -609,6 +615,28 @@ mod tests {
|
||||
(db, project, tempdir)
|
||||
}
|
||||
|
||||
fn spawn_models_server() -> String {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let addr = listener.local_addr().unwrap();
|
||||
thread::spawn(move || {
|
||||
if let Some(stream) = listener.incoming().next() {
|
||||
let mut stream = stream.unwrap();
|
||||
let mut buffer = [0_u8; 8192];
|
||||
let size = stream.read(&mut buffer).unwrap();
|
||||
let request = String::from_utf8_lossy(&buffer[..size]).to_string();
|
||||
assert!(request.starts_with("GET /v1/models HTTP/1.1"));
|
||||
let body = r#"{"data":[{"id":"llama3.2","name":"Llama 3.2"}]}"#;
|
||||
let response = format!(
|
||||
"HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{}",
|
||||
body.len(),
|
||||
body,
|
||||
);
|
||||
stream.write_all(response.as_bytes()).unwrap();
|
||||
}
|
||||
});
|
||||
format!("http://{}", addr)
|
||||
}
|
||||
|
||||
fn make_app(db: Database, project: Project, tmp: &TempDir) -> BdsApp {
|
||||
BdsApp::new_for_tests(db, project, tmp.path().to_path_buf())
|
||||
}
|
||||
@@ -801,6 +829,24 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_ai_settings_allows_airplane_only_configuration() {
|
||||
let (db, _project, _tmp) = setup();
|
||||
let mut state = SettingsViewState::default();
|
||||
state.airplane_endpoint_url = spawn_models_server();
|
||||
state.airplane_endpoint_model = "llama3.2".to_string();
|
||||
state.system_prompt = iced::widget::text_editor::Content::with_text("Use JSON only.");
|
||||
|
||||
BdsApp::save_ai_settings_state(&db, &mut state).unwrap();
|
||||
|
||||
let settings = ai::load_ai_settings(db.conn(), false).unwrap();
|
||||
assert!(settings.online_endpoint.url.is_empty());
|
||||
assert!(settings.online_endpoint.model.is_empty());
|
||||
assert_eq!(settings.airplane_endpoint.url, state.airplane_endpoint_url);
|
||||
assert_eq!(settings.airplane_endpoint.model, "llama3.2");
|
||||
assert_eq!(settings.system_prompt.trim_end(), "Use JSON only.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn media_editor_save_flow_persists_changes() {
|
||||
let (db, project, tmp) = setup();
|
||||
@@ -1607,6 +1653,7 @@ pub struct BdsApp {
|
||||
tags_view_state: Option<TagsViewState>,
|
||||
settings_state: Option<SettingsViewState>,
|
||||
dashboard_state: Option<DashboardState>,
|
||||
site_validation_state: SiteValidationState,
|
||||
}
|
||||
|
||||
// ───────────────────────────────────────────────────────────
|
||||
@@ -1739,6 +1786,7 @@ impl BdsApp {
|
||||
tags_view_state: None,
|
||||
settings_state: None,
|
||||
dashboard_state: None,
|
||||
site_validation_state: SiteValidationState::default(),
|
||||
},
|
||||
init_task,
|
||||
)
|
||||
@@ -1796,6 +1844,7 @@ impl BdsApp {
|
||||
tags_view_state: None,
|
||||
settings_state: None,
|
||||
dashboard_state: None,
|
||||
site_validation_state: SiteValidationState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2301,6 +2350,7 @@ impl BdsApp {
|
||||
self.open_singleton_tab(TabType::MetadataDiff, "tabBar.metadataDiff");
|
||||
Task::none()
|
||||
}
|
||||
Message::RunSiteValidation => self.start_site_validation(),
|
||||
Message::EngineTaskDone { task_id, label, result } => {
|
||||
match &result {
|
||||
Ok(detail) => {
|
||||
@@ -2316,6 +2366,36 @@ impl BdsApp {
|
||||
self.refresh_task_snapshots();
|
||||
sidebar_task
|
||||
}
|
||||
Message::SiteValidationLoaded(result) => {
|
||||
self.site_validation_state.is_running = false;
|
||||
self.site_validation_state.has_run = true;
|
||||
match result {
|
||||
Ok(report) => {
|
||||
self.site_validation_state.error_message = None;
|
||||
self.site_validation_state.missing_files = report.missing_pages;
|
||||
self.site_validation_state.extra_files = report.extra_pages;
|
||||
self.site_validation_state.stale_files = report.stale_pages;
|
||||
self.notify(
|
||||
ToastLevel::Success,
|
||||
&format!(
|
||||
"{}: missing={}, extra={}, stale={}",
|
||||
t(self.ui_locale, "tabBar.siteValidation"),
|
||||
self.site_validation_state.missing_files.len(),
|
||||
self.site_validation_state.extra_files.len(),
|
||||
self.site_validation_state.stale_files.len(),
|
||||
),
|
||||
);
|
||||
}
|
||||
Err(error) => {
|
||||
self.site_validation_state.error_message = Some(error.clone());
|
||||
self.site_validation_state.missing_files.clear();
|
||||
self.site_validation_state.extra_files.clear();
|
||||
self.site_validation_state.stale_files.clear();
|
||||
self.notify(ToastLevel::Error, &error);
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
// ── Toast ──
|
||||
Message::ShowToast(level, msg) => {
|
||||
@@ -3232,6 +3312,7 @@ impl BdsApp {
|
||||
self.tags_view_state.as_ref(),
|
||||
self.settings_state.as_ref(),
|
||||
self.dashboard_state.as_ref(),
|
||||
&self.site_validation_state,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3330,20 +3411,7 @@ impl BdsApp {
|
||||
MenuAction::GenerateSitemap => Task::done(Message::GenerateSite),
|
||||
MenuAction::ValidateSite => {
|
||||
self.open_singleton_tab(TabType::SiteValidation, "tabBar.siteValidation");
|
||||
self.spawn_engine_task(
|
||||
"tabBar.siteValidation",
|
||||
|db_path, project_id, data_dir, _tm, _tid| {
|
||||
let db = Database::open(&db_path).map_err(|e| e.to_string())?;
|
||||
let report = engine::validate_site::validate_site(db.conn(), &data_dir, &project_id)
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(format!(
|
||||
"missing={}, extra={}, stale={}",
|
||||
report.missing_pages.len(),
|
||||
report.extra_pages.len(),
|
||||
report.stale_pages.len(),
|
||||
))
|
||||
},
|
||||
)
|
||||
self.start_site_validation()
|
||||
}
|
||||
MenuAction::UploadSite => {
|
||||
if self.offline_mode {
|
||||
@@ -3603,6 +3671,38 @@ impl BdsApp {
|
||||
self.add_output(text);
|
||||
}
|
||||
|
||||
fn start_site_validation(&mut self) -> Task<Message> {
|
||||
self.open_singleton_tab(TabType::SiteValidation, "tabBar.siteValidation");
|
||||
let Some(_db) = self.db.as_ref() else {
|
||||
self.site_validation_state.is_running = false;
|
||||
self.site_validation_state.error_message = Some(t(self.ui_locale, "engine.generateSiteNoProject"));
|
||||
return Task::none();
|
||||
};
|
||||
let Some(project_id) = self.active_project.as_ref().map(|project| project.id.clone()) else {
|
||||
self.site_validation_state.is_running = false;
|
||||
self.site_validation_state.error_message = Some(t(self.ui_locale, "engine.generateSiteNoProject"));
|
||||
return Task::none();
|
||||
};
|
||||
let Some(data_dir) = self.data_dir.clone() else {
|
||||
self.site_validation_state.is_running = false;
|
||||
self.site_validation_state.error_message = Some(t(self.ui_locale, "engine.previewDataDirUnavailable"));
|
||||
return Task::none();
|
||||
};
|
||||
|
||||
self.site_validation_state.is_running = true;
|
||||
self.site_validation_state.error_message = None;
|
||||
let db_path = self.db_path.clone();
|
||||
|
||||
Task::perform(
|
||||
async move {
|
||||
let db = Database::open(&db_path).map_err(|error| error.to_string())?;
|
||||
engine::validate_site::validate_site(db.conn(), &data_dir, &project_id)
|
||||
.map_err(|error| error.to_string())
|
||||
},
|
||||
Message::SiteValidationLoaded,
|
||||
)
|
||||
}
|
||||
|
||||
/// Spawn a blocking engine operation on a background thread via TaskManager.
|
||||
///
|
||||
/// Returns `Task::none()` if no active project/db/data_dir.
|
||||
@@ -6167,12 +6267,18 @@ impl BdsApp {
|
||||
db: &Database,
|
||||
state: &mut SettingsViewState,
|
||||
) -> Result<(), String> {
|
||||
let online_endpoint = Self::compose_ai_endpoint(state, AiEndpointKind::Online)?;
|
||||
let airplane_endpoint = Self::compose_ai_endpoint(state, AiEndpointKind::Airplane)?;
|
||||
ai::test_endpoint(&online_endpoint).map_err(|error| error.to_string())?;
|
||||
ai::test_endpoint(&airplane_endpoint).map_err(|error| error.to_string())?;
|
||||
ai::save_endpoint(db.conn(), &online_endpoint).map_err(|error| error.to_string())?;
|
||||
ai::save_endpoint(db.conn(), &airplane_endpoint).map_err(|error| error.to_string())?;
|
||||
if Self::endpoint_has_configuration(state, AiEndpointKind::Online) {
|
||||
let online_endpoint = Self::compose_ai_endpoint(state, AiEndpointKind::Online)?;
|
||||
ai::test_endpoint(&online_endpoint).map_err(|error| error.to_string())?;
|
||||
ai::save_endpoint(db.conn(), &online_endpoint).map_err(|error| error.to_string())?;
|
||||
state.online_api_key_input.clear();
|
||||
state.online_api_key_configured = true;
|
||||
}
|
||||
if Self::endpoint_has_configuration(state, AiEndpointKind::Airplane) {
|
||||
let airplane_endpoint = Self::compose_ai_endpoint(state, AiEndpointKind::Airplane)?;
|
||||
ai::test_endpoint(&airplane_endpoint).map_err(|error| error.to_string())?;
|
||||
ai::save_endpoint(db.conn(), &airplane_endpoint).map_err(|error| error.to_string())?;
|
||||
}
|
||||
ai::save_model_preferences(
|
||||
db.conn(),
|
||||
(!state.default_model.trim().is_empty()).then_some(state.default_model.as_str()),
|
||||
@@ -6181,11 +6287,27 @@ impl BdsApp {
|
||||
&state.system_prompt.text(),
|
||||
)
|
||||
.map_err(|error| error.to_string())?;
|
||||
state.online_api_key_input.clear();
|
||||
state.online_api_key_configured = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn endpoint_has_configuration(
|
||||
state: &SettingsViewState,
|
||||
kind: AiEndpointKind,
|
||||
) -> bool {
|
||||
match kind {
|
||||
AiEndpointKind::Online => {
|
||||
!state.online_endpoint_url.trim().is_empty()
|
||||
|| !state.online_endpoint_model.trim().is_empty()
|
||||
|| !state.online_api_key_input.trim().is_empty()
|
||||
|| state.online_api_key_configured
|
||||
}
|
||||
AiEndpointKind::Airplane => {
|
||||
!state.airplane_endpoint_url.trim().is_empty()
|
||||
|| !state.airplane_endpoint_model.trim().is_empty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compose_ai_endpoint(
|
||||
state: &SettingsViewState,
|
||||
kind: AiEndpointKind,
|
||||
|
||||
@@ -15,3 +15,4 @@ pub mod script_editor;
|
||||
pub mod tags_view;
|
||||
pub mod settings_view;
|
||||
pub mod dashboard;
|
||||
pub mod site_validation;
|
||||
|
||||
128
crates/bds-ui/src/views/site_validation.rs
Normal file
128
crates/bds-ui/src/views/site_validation.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use iced::widget::text::Shaping;
|
||||
use iced::widget::{button, column, container, row, scrollable, text};
|
||||
use iced::{Background, Color, Element, Length, Theme};
|
||||
|
||||
use bds_core::i18n::UiLocale;
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::i18n::t;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SiteValidationState {
|
||||
pub has_run: bool,
|
||||
pub is_running: bool,
|
||||
pub missing_files: Vec<String>,
|
||||
pub extra_files: Vec<String>,
|
||||
pub stale_files: Vec<String>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
pub fn view<'a>(state: &'a SiteValidationState, locale: UiLocale) -> Element<'a, Message> {
|
||||
let run_button = if state.is_running {
|
||||
button(text(t(locale, "siteValidation.running")).size(13).shaping(Shaping::Advanced))
|
||||
} else {
|
||||
button(text(t(locale, "siteValidation.run")).size(13).shaping(Shaping::Advanced))
|
||||
.on_press(Message::RunSiteValidation)
|
||||
};
|
||||
|
||||
let mut content = column![
|
||||
row![
|
||||
text(t(locale, "tabBar.siteValidation"))
|
||||
.size(24)
|
||||
.shaping(Shaping::Advanced)
|
||||
.color(Color::from_rgb(0.88, 0.88, 0.92)),
|
||||
run_button,
|
||||
]
|
||||
.spacing(16),
|
||||
]
|
||||
.spacing(16);
|
||||
|
||||
if state.is_running {
|
||||
content = content.push(help_text(t(locale, "siteValidation.running")));
|
||||
} else if let Some(error) = &state.error_message {
|
||||
content = content.push(section(
|
||||
t(locale, "siteValidation.error"),
|
||||
std::slice::from_ref(error),
|
||||
Color::from_rgb(0.75, 0.28, 0.28),
|
||||
));
|
||||
} else if !state.has_run {
|
||||
content = content.push(help_text(t(locale, "siteValidation.idle")));
|
||||
} else if state.missing_files.is_empty() && state.extra_files.is_empty() && state.stale_files.is_empty() {
|
||||
content = content.push(help_text(t(locale, "siteValidation.clean")));
|
||||
} else {
|
||||
if !state.missing_files.is_empty() {
|
||||
content = content.push(section(
|
||||
format!("{} ({})", t(locale, "siteValidation.missing"), state.missing_files.len()),
|
||||
&state.missing_files,
|
||||
Color::from_rgb(0.70, 0.25, 0.25),
|
||||
));
|
||||
}
|
||||
if !state.extra_files.is_empty() {
|
||||
content = content.push(section(
|
||||
format!("{} ({})", t(locale, "siteValidation.extra"), state.extra_files.len()),
|
||||
&state.extra_files,
|
||||
Color::from_rgb(0.68, 0.48, 0.18),
|
||||
));
|
||||
}
|
||||
if !state.stale_files.is_empty() {
|
||||
content = content.push(section(
|
||||
format!("{} ({})", t(locale, "siteValidation.stale"), state.stale_files.len()),
|
||||
&state.stale_files,
|
||||
Color::from_rgb(0.62, 0.32, 0.18),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
container(scrollable(content))
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.padding(24)
|
||||
.style(|_theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(Color::from_rgb(0.11, 0.11, 0.14))),
|
||||
..container::Style::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
fn help_text<'a>(value: String) -> Element<'a, Message> {
|
||||
container(
|
||||
text(value)
|
||||
.size(14)
|
||||
.shaping(Shaping::Advanced)
|
||||
.color(Color::from_rgb(0.66, 0.66, 0.72)),
|
||||
)
|
||||
.padding(16)
|
||||
.style(|_theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(Color::from_rgb(0.14, 0.14, 0.18))),
|
||||
..container::Style::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
fn section<'a>(title: String, entries: &'a [String], accent: Color) -> Element<'a, Message> {
|
||||
let items = entries.iter().fold(column!().spacing(6), |column, entry| {
|
||||
column.push(
|
||||
text(entry)
|
||||
.size(13)
|
||||
.shaping(Shaping::Advanced)
|
||||
.color(Color::from_rgb(0.82, 0.82, 0.88)),
|
||||
)
|
||||
});
|
||||
|
||||
container(
|
||||
column![
|
||||
text(title.to_string())
|
||||
.size(16)
|
||||
.shaping(Shaping::Advanced)
|
||||
.color(accent),
|
||||
items,
|
||||
]
|
||||
.spacing(10),
|
||||
)
|
||||
.padding(16)
|
||||
.style(|_theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(Color::from_rgb(0.14, 0.14, 0.18))),
|
||||
..container::Style::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
@@ -20,6 +20,7 @@ use crate::views::{
|
||||
modal, panel,
|
||||
post_editor::{self, PostEditorState},
|
||||
project_selector,
|
||||
site_validation::{self, SiteValidationState},
|
||||
script_editor::{self, ScriptEditorState},
|
||||
settings_view::{self, SettingsViewState},
|
||||
sidebar, status_bar, tab_bar,
|
||||
@@ -110,6 +111,7 @@ pub fn view<'a>(
|
||||
tags_view_state: Option<&'a TagsViewState>,
|
||||
settings_state: Option<&'a SettingsViewState>,
|
||||
dashboard_state: Option<&'a DashboardState>,
|
||||
site_validation_state: &'a SiteValidationState,
|
||||
) -> Element<'a, Message> {
|
||||
// Activity bar (leftmost column)
|
||||
let activity = activity_bar::view(sidebar_view, sidebar_visible, locale);
|
||||
@@ -131,6 +133,7 @@ pub fn view<'a>(
|
||||
tags_view_state,
|
||||
settings_state,
|
||||
dashboard_state,
|
||||
site_validation_state,
|
||||
);
|
||||
|
||||
// Right column: tab bar + content + panel
|
||||
@@ -353,6 +356,7 @@ fn route_content_area<'a>(
|
||||
tags_view_state: Option<&'a TagsViewState>,
|
||||
settings_state: Option<&'a SettingsViewState>,
|
||||
dashboard_state: Option<&'a DashboardState>,
|
||||
site_validation_state: &'a SiteValidationState,
|
||||
) -> Element<'a, Message> {
|
||||
match route_kind(
|
||||
tabs,
|
||||
@@ -364,6 +368,7 @@ fn route_content_area<'a>(
|
||||
tags_view_state,
|
||||
settings_state,
|
||||
dashboard_state,
|
||||
site_validation_state,
|
||||
) {
|
||||
ContentRoute::Dashboard(state) => crate::views::dashboard::view(state, locale),
|
||||
ContentRoute::Welcome => welcome::view(locale),
|
||||
@@ -411,6 +416,7 @@ fn route_content_area<'a>(
|
||||
loading_view(locale)
|
||||
}
|
||||
}
|
||||
ContentRoute::SiteValidation => site_validation::view(site_validation_state, locale),
|
||||
ContentRoute::Placeholder(title) => welcome::tab_placeholder(title, None),
|
||||
}
|
||||
}
|
||||
@@ -426,6 +432,7 @@ enum ContentRoute<'a> {
|
||||
Scripts(&'a str),
|
||||
Tags,
|
||||
Settings,
|
||||
SiteValidation,
|
||||
Placeholder(&'a str),
|
||||
}
|
||||
|
||||
@@ -439,6 +446,7 @@ fn route_kind<'a>(
|
||||
tags_view_state: Option<&'a TagsViewState>,
|
||||
settings_state: Option<&'a SettingsViewState>,
|
||||
dashboard_state: Option<&'a DashboardState>,
|
||||
_site_validation_state: &'a SiteValidationState,
|
||||
) -> ContentRoute<'a> {
|
||||
let Some(tab_id) = active_tab else {
|
||||
return dashboard_state.map(ContentRoute::Dashboard).unwrap_or(ContentRoute::Welcome);
|
||||
@@ -466,6 +474,7 @@ fn route_kind<'a>(
|
||||
TabType::Settings => {
|
||||
if settings_state.is_some() { ContentRoute::Settings } else { ContentRoute::Loading }
|
||||
}
|
||||
TabType::SiteValidation => ContentRoute::SiteValidation,
|
||||
TabType::Style
|
||||
| TabType::Chat
|
||||
| TabType::Import
|
||||
@@ -474,7 +483,6 @@ fn route_kind<'a>(
|
||||
| TabType::GitDiff
|
||||
| TabType::Documentation
|
||||
| TabType::ApiDocumentation
|
||||
| TabType::SiteValidation
|
||||
| TabType::TranslationValidation
|
||||
| TabType::FindDuplicates => ContentRoute::Placeholder(&tab.title),
|
||||
}
|
||||
@@ -501,6 +509,7 @@ mod tests {
|
||||
let empty_media = HashMap::new();
|
||||
let empty_templates = HashMap::new();
|
||||
let empty_scripts = HashMap::new();
|
||||
let site_validation_state = SiteValidationState::default();
|
||||
let unsupported = [
|
||||
TabType::Style,
|
||||
TabType::Chat,
|
||||
@@ -510,7 +519,6 @@ mod tests {
|
||||
TabType::GitDiff,
|
||||
TabType::Documentation,
|
||||
TabType::ApiDocumentation,
|
||||
TabType::SiteValidation,
|
||||
TabType::TranslationValidation,
|
||||
TabType::FindDuplicates,
|
||||
];
|
||||
@@ -527,6 +535,7 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
&site_validation_state,
|
||||
);
|
||||
match route {
|
||||
ContentRoute::Placeholder(title) => assert_eq!(title, "Tool"),
|
||||
@@ -542,6 +551,7 @@ mod tests {
|
||||
let empty_media = HashMap::new();
|
||||
let empty_templates = HashMap::new();
|
||||
let empty_scripts = HashMap::new();
|
||||
let site_validation_state = SiteValidationState::default();
|
||||
let route = route_kind(
|
||||
&[],
|
||||
None,
|
||||
@@ -552,12 +562,41 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
Some(&dashboard),
|
||||
&site_validation_state,
|
||||
);
|
||||
match route {
|
||||
ContentRoute::Dashboard(state) => assert_eq!(state.subtitle, "Test Project"),
|
||||
_ => panic!("expected dashboard route"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn site_validation_tab_routes_to_real_view() {
|
||||
let empty_posts = HashMap::new();
|
||||
let empty_media = HashMap::new();
|
||||
let empty_templates = HashMap::new();
|
||||
let empty_scripts = HashMap::new();
|
||||
let site_validation_state = SiteValidationState::default();
|
||||
let tabs = vec![tab("site_validation", TabType::SiteValidation, "Validation")];
|
||||
|
||||
let route = route_kind(
|
||||
&tabs,
|
||||
Some("site_validation"),
|
||||
&empty_posts,
|
||||
&empty_media,
|
||||
&empty_templates,
|
||||
&empty_scripts,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
&site_validation_state,
|
||||
);
|
||||
|
||||
match route {
|
||||
ContentRoute::SiteValidation => {}
|
||||
_ => panic!("expected site validation route"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn loading_view<'a>(locale: UiLocale) -> Element<'a, Message> {
|
||||
|
||||
Reference in New Issue
Block a user