This commit is contained in:
2026-08-26 19:44:18 -04:00
parent 35477a3658
commit 948b415d5a
6 changed files with 184 additions and 84 deletions
+79 -79
View File
@@ -45,12 +45,12 @@ pub(crate) enum Message {
NavigateTo(Url),
FetchDocument(Url),
LoadDocument(RdfSource<KeyedDataset<RowState>>),
ResourceNotFound,
ShowNewDocumentButtons,
HideNewDocumentButtons,
ShowError(String),
AddRow(Option<(QuadKey, RowState)>),
DeleteRow(QuadKey),
DeleteAllRows,
OpenQueryWindow(SearchResultClickAction),
HoverRow(QuadKey),
UnhoverRow(QuadKey),
@@ -68,7 +68,7 @@ pub(crate) enum Message {
ShowOverwriteConfirmationModal,
HideOverwriteConfirmationModal,
ConfirmOverwrite,
NewDocument(NamedNode),
NewDocument(Class, Option<Url>),
NavigateToPredicate(QuadKey),
NavigateToObject(QuadKey),
NavigateBack,
@@ -123,6 +123,7 @@ pub(crate) struct Publisher {
show_overwrite_confirmation: bool,
modified: bool,
show_new_document_buttons: bool,
resource_not_found: bool,
}
impl Publisher {
@@ -180,6 +181,7 @@ impl Publisher {
show_overwrite_confirmation: false,
modified: false,
show_new_document_buttons: false,
resource_not_found: false,
},
task.map(|_| Message::ConnectToOntologyService("http://[::1]:3000".to_string())),
)
@@ -259,8 +261,7 @@ impl Publisher {
}
}
Message::NavigateTo(url) => {
task = Task::done(Message::DeleteAllRows)
.chain(Task::done(Message::ResetState))
task = Task::done(Message::ResetState)
.chain(Task::done(Message::FetchDocument(url)));
}
Message::FetchDocument(url) => {
@@ -280,7 +281,7 @@ impl Publisher {
},
Err(ldp::Error::Reqwest(err)) => {
if err.status() == Some(StatusCode::NOT_FOUND) {
Message::ShowNewDocumentButtons
Message::ResourceNotFound
} else {
Message::ShowError(err.to_string())
}
@@ -289,6 +290,10 @@ impl Publisher {
}
});
}
Message::ResourceNotFound => {
self.resource_not_found = true;
task = Task::done(Message::ShowNewDocumentButtons);
}
Message::LoadDocument(document) => {
let nodes_to_look_up = document.dataset().quads.iter().map(|(_, quad)| {
let mut nodes = vec![ quad.predicate.clone() ];
@@ -342,10 +347,6 @@ impl Publisher {
self.document.dataset_mut().remove(key);
self.modified = true;
}
Message::DeleteAllRows => {
self.document.dataset_mut().clear();
self.modified = true;
}
Message::OpenQueryWindow(action) => {
let selected_entity_class = match action {
SearchResultClickAction::Predicate(_) => Some(vocab::rdf::PROPERTY),
@@ -538,21 +539,26 @@ impl Publisher {
Message::HideNewDocumentButtons => {
self.show_new_document_buttons = false;
}
Message::NewDocument(class) => {
let url = Url::parse(self.url_input.as_str()).expect("Invalid URL");
let mut document: RdfSource<KeyedDataset<RowState>> = RdfSource::new(url);
Message::NewDocument(class, None) => {
let client = self.http_client.clone();
task = tasks::navigate_to_next_url(client, class);
}
Message::NewDocument(class, Some(url)) => {
let mut document: RdfSource<KeyedDataset<RowState>> = RdfSource::new(url.clone());
let mut quad = document.new_quad();
quad.predicate = vocab::rdf::TYPE.into_owned();
quad.object = Term::NamedNode(class);
quad.object = Term::NamedNode(class.to_named_node().into_owned());
document.dataset_mut().quads.insert(quad);
task = Task::done(Message::HideNewDocumentButtons)
.chain(Task::done(Message::URLInputChanged(url.to_string())))
.chain(Task::done(Message::LoadDocument(document)));
}
Message::ResetState => {
self.modified = false;
self.show_new_document_buttons = false;
self.show_overwrite_confirmation = false;
self.resource_not_found = false;
}
Message::NavigateToPredicate(key) => {
if let Some(quad) = self.document.dataset_mut().quads.get_mut(key) {
@@ -811,72 +817,76 @@ impl Publisher {
.into()
}
pub(crate) fn view(&self, window: window::Id) -> Element<'_, Message> {
if let Some(search_state) = &self.search_state
&& search_state.window_id == window
{
let search_input = text_input("Query", &search_state.query)
.on_input(Message::QueryUpdated)
.id("query");
fn view_search_window<'a>(&'a self, search_state: &'a SearchState) -> Element<'a, Message> {
let search_input = text_input("Query", &search_state.query)
.on_input(Message::QueryUpdated)
.id("query");
let type_selector = pick_list(
search_state.entity_class_selection.as_ref(),
Class::ALL,
ToString::to_string,
).on_select(|selection| Message::UpdateQueryClass(selection));
let type_selector = pick_list(
search_state.entity_class_selection.as_ref(),
Class::ALL,
ToString::to_string,
).on_select(|selection| Message::UpdateQueryClass(selection));
let mut columns = vec![table::column(text("CURIE"), |document: &HashMap<gl_search::Field, gl_search::OwnedValue>| {
let iri = document.get(&Schema::iri_field())
.and_then(|value| value.as_str())
.unwrap_or_default();
let mut columns = vec![table::column(text("CURIE"), |document: &HashMap<gl_search::Field, gl_search::OwnedValue>| {
let iri = document.get(&Schema::iri_field())
.and_then(|value| value.as_str())
.unwrap_or_default();
let abbreviated_iri = document.get(&Schema::curie_field())
.and_then(|value| value.as_str())
.unwrap_or_default();
let abbreviated_iri = document.get(&Schema::curie_field())
.and_then(|value| value.as_str())
.unwrap_or_default();
button(text(abbreviated_iri).wrapping(Wrapping::Word))
.on_press(Message::SearchResultClicked(NamedNode::new_unchecked(iri)))
.style(button::text)
})];
button(text(abbreviated_iri).wrapping(Wrapping::Word))
.on_press(Message::SearchResultClicked(NamedNode::new_unchecked(iri)))
.style(button::text)
})];
let fields = search_state.entity_class_selection
.as_ref()
.map(|class| {
let fields = search_state.entity_class_selection
.as_ref()
.map(|class| {
class.fields(language::ENGLISH_TAG.clone())
}).unwrap_or_default();
for (field, label) in fields {
columns.push(
table::column(text(label), move |document: &HashMap<gl_search::Field, gl_search::OwnedValue>| {
let iri = document.get(&Schema::iri_field())
.and_then(|value| value.as_str())
.unwrap_or_default();
for (field, label) in fields {
columns.push(
table::column(text(label), move |document: &HashMap<gl_search::Field, gl_search::OwnedValue>| {
let iri = document.get(&Schema::iri_field())
.and_then(|value| value.as_str())
.unwrap_or_default();
let value = document
.get(&field)
.and_then(|value| value.as_str())
.unwrap_or_default();
let value = document
.get(&field)
.and_then(|value| value.as_str())
.unwrap_or_default();
button(text(value).wrapping(Wrapping::Word))
.on_press(Message::SearchResultClicked(NamedNode::new_unchecked(iri)))
.style(button::text)
})
button(text(value).wrapping(Wrapping::Word))
.on_press(Message::SearchResultClicked(NamedNode::new_unchecked(iri)))
.style(button::text)
})
.width(Length::Fixed(256.0)),
);
}
);
}
let results_table = if columns.is_empty() {
None
} else {
Some(scrollable(table(columns, &search_state.results)))
};
let results_table = if columns.is_empty() {
None
} else {
Some(scrollable(table(columns, &search_state.results)))
};
return column![row![search_input, type_selector], results_table].into();
column![row![search_input, type_selector], results_table].into()
}
pub(crate) fn view(&self, window: window::Id) -> Element<'_, Message> {
if let Some(search_state) = &self.search_state
&& search_state.window_id == window {
return self.view_search_window(search_state);
}
let back_button = button("\u{1f870}").on_press(Message::NavigateBack);
let forward_button = button("\u{1f872}").on_press(Message::NavigateForward);
let add_row_button = button("Add row").on_press(Message::AddRow(None));
let new_document_button = button("New Document").on_press(Message::ShowNewDocumentButtons);
let add_row_button = button("Add Row").on_press(Message::AddRow(None));
let address_input = iri_input(&self.curie_helper, "URL", None, &self.url_input)
.on_input(Message::URLInputChanged)
@@ -895,25 +905,14 @@ impl Publisher {
.collect();
let body: Element<Message> = if self.show_new_document_buttons {
let buttons = Class::ALL.iter()
let buttons = Class::CREATABLE.iter()
.map(|class| {
let node = class.to_named_node().into_owned();
let abbreviation = self.curie_helper
.abbreviate(None, node.as_str())
.unwrap_or(node.to_string());
let url = if self.resource_not_found {
Url::parse(&self.url_input).ok()
} else { None };
let description = self.resource_descriptions
.get(&node);
let button_text = if let Some(description) = description &&
let Some(label) = &description.label {
format!("{label} ({abbreviation})")
} else {
abbreviation
};
button(text(button_text))
.on_press(Message::NewDocument(node))
button(text(class.to_string()))
.on_press(Message::NewDocument(class.clone(), url))
.into()
});
@@ -1004,6 +1003,7 @@ impl Publisher {
let content = navigation_area(column![
row![
new_document_button,
add_row_button,
back_button,
forward_button,