.
This commit is contained in:
+208
-65
@@ -1,4 +1,4 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
use crate::navigator::Navigator;
|
use crate::navigator::Navigator;
|
||||||
use crate::rdf::term_helper::{TermHelper, TermHelperMut};
|
use crate::rdf::term_helper::{TermHelper, TermHelperMut};
|
||||||
@@ -12,7 +12,7 @@ use iced::keyboard::{Event, key};
|
|||||||
use iced::widget::button::Style;
|
use iced::widget::button::Style;
|
||||||
use iced::widget::{button, center, column, combo_box, container, grid, mouse_area, opaque, operation, pick_list, row, scrollable, space, stack, table, text, text_input, toggler};
|
use iced::widget::{button, center, column, combo_box, container, grid, mouse_area, opaque, operation, pick_list, row, scrollable, space, stack, table, text, text_input, toggler};
|
||||||
use iced::window::Settings;
|
use iced::window::Settings;
|
||||||
use iced::{Background, Color, Element, Length, Subscription, Task, color, keyboard, window};
|
use iced::{color, keyboard, window, Background, Color, Element, Font, Length, Subscription, Task, font};
|
||||||
use iced::advanced::text::Wrapping;
|
use iced::advanced::text::Wrapping;
|
||||||
use iced::widget::grid::Sizing;
|
use iced::widget::grid::Sizing;
|
||||||
use ldp::middleware::BasicAuthMiddleware;
|
use ldp::middleware::BasicAuthMiddleware;
|
||||||
@@ -21,7 +21,7 @@ use ldp::reqwest::{Client, Url};
|
|||||||
use ldp::reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
use ldp::reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
||||||
use ldp::{RdfSource, RdfSourceUpdateResponse, ResourceRequestBuilder, SerializationOptions};
|
use ldp::{RdfSource, RdfSourceUpdateResponse, ResourceRequestBuilder, SerializationOptions};
|
||||||
use oxigraph::io::RdfFormat;
|
use oxigraph::io::RdfFormat;
|
||||||
use oxigraph::model::{BaseDirection, Graph, NamedNode, NamedOrBlankNode, NamedOrBlankNodeRef, Quad, Term, TermRef, Triple, TripleRef};
|
use oxigraph::model::{BaseDirection, Graph, NamedNode, NamedNodeRef, NamedOrBlankNode, NamedOrBlankNodeRef, Quad, Term, TermRef, Triple, TripleRef};
|
||||||
use tracing::{debug, error, trace};
|
use tracing::{debug, error, trace};
|
||||||
use gl_graph::class::Class;
|
use gl_graph::class::Class;
|
||||||
use gl_graph::ontology::{ConnectedOntology, OntologyBuilder, ReadOnlyEntity, ResourceDescription};
|
use gl_graph::ontology::{ConnectedOntology, OntologyBuilder, ReadOnlyEntity, ResourceDescription};
|
||||||
@@ -77,6 +77,7 @@ pub(crate) enum Message {
|
|||||||
RunInference,
|
RunInference,
|
||||||
SetInferredTriples(Graph),
|
SetInferredTriples(Graph),
|
||||||
ShowInferencesWindow,
|
ShowInferencesWindow,
|
||||||
|
ShowReadOnlyWindow,
|
||||||
Event(Event),
|
Event(Event),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +111,7 @@ pub(crate) struct Publisher {
|
|||||||
resource_descriptions: HashMap<NamedNode, ResourceDescription>,
|
resource_descriptions: HashMap<NamedNode, ResourceDescription>,
|
||||||
window_id: window::Id,
|
window_id: window::Id,
|
||||||
inference_window_id: Option<window::Id>,
|
inference_window_id: Option<window::Id>,
|
||||||
|
read_only_window_id: Option<window::Id>,
|
||||||
url_input: String,
|
url_input: String,
|
||||||
url_input_valid: bool,
|
url_input_valid: bool,
|
||||||
navigator: Navigator<Url>,
|
navigator: Navigator<Url>,
|
||||||
@@ -167,6 +169,7 @@ impl Publisher {
|
|||||||
resource_descriptions: HashMap::new(),
|
resource_descriptions: HashMap::new(),
|
||||||
window_id: id,
|
window_id: id,
|
||||||
inference_window_id: None,
|
inference_window_id: None,
|
||||||
|
read_only_window_id: None,
|
||||||
url_input: starting_url.to_string(),
|
url_input: starting_url.to_string(),
|
||||||
url_input_valid: true,
|
url_input_valid: true,
|
||||||
navigator,
|
navigator,
|
||||||
@@ -237,8 +240,10 @@ impl Publisher {
|
|||||||
Message::WindowClosed(id) => {
|
Message::WindowClosed(id) => {
|
||||||
if self.window_id == id {
|
if self.window_id == id {
|
||||||
task = iced::exit();
|
task = iced::exit();
|
||||||
} else {
|
} else if let Some(search_state) = &self.search_state && search_state.window_id == id {
|
||||||
self.search_state = None;
|
self.search_state = None;
|
||||||
|
} else if let Some(infrence_window_id) = self.inference_window_id && infrence_window_id == id {
|
||||||
|
self.inference_window_id = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::URLInputChanged(value) => {
|
Message::URLInputChanged(value) => {
|
||||||
@@ -633,6 +638,15 @@ impl Publisher {
|
|||||||
task = window_task.map(|_| Message::None);
|
task = window_task.map(|_| Message::None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::ShowReadOnlyWindow => {
|
||||||
|
if let Some(id) = self.read_only_window_id {
|
||||||
|
task = window::gain_focus(id);
|
||||||
|
} else {
|
||||||
|
let (id, window_task) = window::open(Settings::default());
|
||||||
|
self.read_only_window_id = Some(id);
|
||||||
|
task = window_task.map(|_| Message::None);
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::Event(Event::KeyPressed {
|
Message::Event(Event::KeyPressed {
|
||||||
key: keyboard::Key::Named(key::Named::Tab),
|
key: keyboard::Key::Named(key::Named::Tab),
|
||||||
modifiers,
|
modifiers,
|
||||||
@@ -654,6 +668,8 @@ impl Publisher {
|
|||||||
"Graph of Liberty Publisher - Inferences".to_string()
|
"Graph of Liberty Publisher - Inferences".to_string()
|
||||||
} else if let Some(search_state) = &self.search_state && window == search_state.window_id {
|
} else if let Some(search_state) = &self.search_state && window == search_state.window_id {
|
||||||
"Graph of Liberty Publisher - Search".to_string()
|
"Graph of Liberty Publisher - Search".to_string()
|
||||||
|
} else if let Some(read_only_window_id) = &self.read_only_window_id {
|
||||||
|
"Graph of Liberty Publisher - Read Only Triples".to_string()
|
||||||
} else {
|
} else {
|
||||||
"Graph of Liberty Publisher".to_string()
|
"Graph of Liberty Publisher".to_string()
|
||||||
}
|
}
|
||||||
@@ -666,6 +682,186 @@ impl Publisher {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn view_inferred_class_table<'a>(&'a self, triples: impl IntoIterator<Item = TripleRef<'a>>) -> Element<'a, Message> {
|
||||||
|
let bold = |t| text(t).font(Font { weight: font::Weight::Bold, ..Font::default() });
|
||||||
|
|
||||||
|
let subject_column = table::column(bold("Subject"), |(subject, _): (NamedNodeRef, _)| {
|
||||||
|
text(self.curie_helper
|
||||||
|
.abbreviate(Some(self.document.origin()), subject.as_str())
|
||||||
|
.unwrap_or_else(|| subject.as_str().to_string()))
|
||||||
|
});
|
||||||
|
|
||||||
|
let class_column = table::column(bold("Classes"), |(_, classes): (_, BTreeSet<NamedNodeRef>)| {
|
||||||
|
let textual_classes = classes.iter()
|
||||||
|
.map(|class| {
|
||||||
|
let curie = self.curie_helper
|
||||||
|
.abbreviate(Some(self.document.origin()), class.as_str())
|
||||||
|
.unwrap_or_else(|| class.as_str().to_string());
|
||||||
|
|
||||||
|
let label = self.resource_descriptions
|
||||||
|
.get(&class.into_owned())
|
||||||
|
.and_then(|description| description.label.clone());
|
||||||
|
|
||||||
|
if let Some(label) = label {
|
||||||
|
format!("{curie} ({label})")
|
||||||
|
} else {
|
||||||
|
curie
|
||||||
|
}
|
||||||
|
}).collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
text(textual_classes)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut inferred_classes: BTreeMap<NamedNodeRef, BTreeSet<NamedNodeRef>> = BTreeMap::new();
|
||||||
|
for triple in triples {
|
||||||
|
if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject &&
|
||||||
|
let TermRef::NamedNode(class) = triple.object {
|
||||||
|
inferred_classes.entry(subject)
|
||||||
|
.and_modify(|classes| { classes.insert(class); })
|
||||||
|
.or_insert(BTreeSet::from_iter([class]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table([subject_column, class_column], inferred_classes).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view_triple_table<'a>(&'a self, triples: impl IntoIterator<Item = TripleRef<'a>>) -> Element<'a, Message> {
|
||||||
|
let bold = |t| text(t).font(Font { weight: font::Weight::Bold, ..Font::default() });
|
||||||
|
|
||||||
|
let subject_column = table::column(bold("Subject"), |triple: TripleRef| {
|
||||||
|
let curie = if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject {
|
||||||
|
Some(self.curie_helper
|
||||||
|
.abbreviate(Some(self.document.origin()), subject.as_str())
|
||||||
|
.unwrap_or_else(|| subject.as_str().to_string()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
curie.map(text)
|
||||||
|
});
|
||||||
|
|
||||||
|
let predicate_column = table::column(bold("Predicate"), |triple: TripleRef| {
|
||||||
|
let curie = self.curie_helper
|
||||||
|
.abbreviate(None, triple.predicate.as_str())
|
||||||
|
.unwrap_or_else(|| triple.predicate.as_str().to_string());
|
||||||
|
|
||||||
|
let label = self.resource_descriptions
|
||||||
|
.get(&triple.predicate.into_owned())
|
||||||
|
.and_then(|description| description.label.clone());
|
||||||
|
|
||||||
|
if let Some(label) = label {
|
||||||
|
text(format!("{curie} ({label})"))
|
||||||
|
} else {
|
||||||
|
text(curie)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let object_column = table::column(bold("Object"), |triple: TripleRef| {
|
||||||
|
match triple.object {
|
||||||
|
TermRef::NamedNode(node) => {
|
||||||
|
let curie = self.curie_helper
|
||||||
|
.abbreviate(Some(self.document.origin()), node.as_str())
|
||||||
|
.unwrap_or_else(|| node.as_str().to_string());
|
||||||
|
|
||||||
|
let label = self.resource_descriptions
|
||||||
|
.get(&node.into_owned())
|
||||||
|
.and_then(|description| description.label.clone());
|
||||||
|
|
||||||
|
if let Some(label) = label {
|
||||||
|
text(format!("{curie} ({label})"))
|
||||||
|
} else {
|
||||||
|
text(curie)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => text(triple.object.to_string()),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
table([subject_column, predicate_column, object_column], triples).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
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(Message::UpdateQueryClass);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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| {
|
||||||
|
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();
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
.width(Length::Fixed(256.0)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let results_table = if columns.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(scrollable(table(columns, &search_state.results)))
|
||||||
|
};
|
||||||
|
|
||||||
|
column![row![search_input, type_selector], results_table].into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view_inference_window(&self) -> Element<'_, Message> {
|
||||||
|
let classes = self.inferred_triples.triples_for_predicate(vocab::rdf::TYPE);
|
||||||
|
|
||||||
|
column![
|
||||||
|
self.view_inferred_class_table(classes),
|
||||||
|
scrollable(self.view_triple_table(&self.inferred_triples)),
|
||||||
|
].into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view_read_only_window(&self) -> Element<'_, Message> {
|
||||||
|
let read_only_triples = self.document
|
||||||
|
.dataset()
|
||||||
|
.iter_both()
|
||||||
|
.filter_map(|(_, quad, state)| if state.read_only { Some(quad) } else { None })
|
||||||
|
.map(|quad| TripleRef::from(quad.as_ref()));
|
||||||
|
|
||||||
|
column![
|
||||||
|
scrollable(self.view_triple_table(read_only_triples)),
|
||||||
|
].into()
|
||||||
|
}
|
||||||
|
|
||||||
fn view_row<'a>(
|
fn view_row<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
key: QuadKey,
|
key: QuadKey,
|
||||||
@@ -835,66 +1031,6 @@ impl Publisher {
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
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(Message::UpdateQueryClass);
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
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| {
|
|
||||||
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();
|
|
||||||
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
.width(Length::Fixed(256.0)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let results_table = if columns.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(scrollable(table(columns, &search_state.results)))
|
|
||||||
};
|
|
||||||
|
|
||||||
column![row![search_input, type_selector], results_table].into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn view(&self, window: window::Id) -> Element<'_, Message> {
|
pub(crate) fn view(&self, window: window::Id) -> Element<'_, Message> {
|
||||||
if let Some(search_state) = &self.search_state &&
|
if let Some(search_state) = &self.search_state &&
|
||||||
search_state.window_id == window {
|
search_state.window_id == window {
|
||||||
@@ -902,10 +1038,15 @@ impl Publisher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(inference_window_id) = self.inference_window_id && window == inference_window_id {
|
if let Some(inference_window_id) = self.inference_window_id && window == inference_window_id {
|
||||||
return crate::window::inferences::view_inference_window(&self.resource_descriptions, self.document.origin(), &self.curie_helper, &self.inferred_triples);
|
return self.view_inference_window();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(read_only_window_id) = self.read_only_window_id && window == read_only_window_id {
|
||||||
|
return self.view_read_only_window();
|
||||||
}
|
}
|
||||||
|
|
||||||
let show_inferences_button = button("\u{1f9e0}").on_press(Message::ShowInferencesWindow);
|
let show_inferences_button = button("\u{1f9e0}").on_press(Message::ShowInferencesWindow);
|
||||||
|
let show_read_only_button = button("\u{1f6ab}").on_press(Message::ShowReadOnlyWindow);
|
||||||
let back_button = button("\u{1f870}").on_press(Message::NavigateBack);
|
let back_button = button("\u{1f870}").on_press(Message::NavigateBack);
|
||||||
let forward_button = button("\u{1f872}").on_press(Message::NavigateForward);
|
let forward_button = button("\u{1f872}").on_press(Message::NavigateForward);
|
||||||
let new_document_button = button("New Document").on_press(Message::ShowNewDocumentButtons);
|
let new_document_button = button("New Document").on_press(Message::ShowNewDocumentButtons);
|
||||||
@@ -923,6 +1064,7 @@ impl Publisher {
|
|||||||
rows = self.document
|
rows = self.document
|
||||||
.dataset()
|
.dataset()
|
||||||
.iter_both()
|
.iter_both()
|
||||||
|
.filter(|(_, _, state)| !state.read_only)
|
||||||
.map(|(key, quad, state)| self.view_row(key, quad, state))
|
.map(|(key, quad, state)| self.view_row(key, quad, state))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -955,6 +1097,7 @@ impl Publisher {
|
|||||||
let content = navigation_area(column![
|
let content = navigation_area(column![
|
||||||
row![
|
row![
|
||||||
show_inferences_button,
|
show_inferences_button,
|
||||||
|
show_read_only_button,
|
||||||
new_document_button,
|
new_document_button,
|
||||||
add_row_button,
|
add_row_button,
|
||||||
back_button,
|
back_button,
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ mod rdf;
|
|||||||
mod theme;
|
mod theme;
|
||||||
mod widget;
|
mod widget;
|
||||||
mod tasks;
|
mod tasks;
|
||||||
pub mod window;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::app::Publisher;
|
use crate::app::Publisher;
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
|
||||||
use iced::{font, Element, Font};
|
|
||||||
use iced::widget::{column, scrollable, span, table, text};
|
|
||||||
use oxigraph::model::{Graph, NamedNode, NamedNodeRef, NamedOrBlankNodeRef, TermRef, TripleRef};
|
|
||||||
use url::Url;
|
|
||||||
use gl_graph::{vocab, CurieHelper};
|
|
||||||
use gl_graph::ontology::ResourceDescription;
|
|
||||||
use crate::app::Message;
|
|
||||||
|
|
||||||
pub(crate) fn view_inference_window<'a>(resource_descriptions: &HashMap<NamedNode, ResourceDescription>, origin: &Url, curie_helper: &CurieHelper, inferences: &'a Graph) -> Element<'a, Message> {
|
|
||||||
let bold = |t| text(t).font(Font { weight: font::Weight::Bold, ..Font::default() });
|
|
||||||
|
|
||||||
let inferred_class_subject_column = table::column(bold("Subject"), |(subject, _): (NamedNodeRef, _)| {
|
|
||||||
text(curie_helper
|
|
||||||
.abbreviate(Some(origin), subject.as_str())
|
|
||||||
.unwrap_or_else(|| subject.as_str().to_string()))
|
|
||||||
});
|
|
||||||
|
|
||||||
let inferred_class_class_column = table::column(bold("Classes"), |(_, classes): (_, BTreeSet<NamedNodeRef>)| {
|
|
||||||
let textual_classes = classes.iter()
|
|
||||||
.map(|class| {
|
|
||||||
let curie = curie_helper
|
|
||||||
.abbreviate(Some(origin), class.as_str())
|
|
||||||
.unwrap_or_else(|| class.as_str().to_string());
|
|
||||||
|
|
||||||
let label = resource_descriptions
|
|
||||||
.get(&class.into_owned())
|
|
||||||
.and_then(|description| description.label.clone());
|
|
||||||
|
|
||||||
if let Some(label) = label {
|
|
||||||
format!("{curie} ({label})")
|
|
||||||
} else {
|
|
||||||
curie
|
|
||||||
}
|
|
||||||
}).collect::<Vec<_>>()
|
|
||||||
.join("\n");
|
|
||||||
|
|
||||||
text(textual_classes)
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut inferred_classes: BTreeMap<NamedNodeRef, BTreeSet<NamedNodeRef>> = BTreeMap::new();
|
|
||||||
for triple in inferences.triples_for_predicate(vocab::rdf::TYPE) {
|
|
||||||
if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject && let TermRef::NamedNode(class) = triple.object {
|
|
||||||
inferred_classes.entry(subject)
|
|
||||||
.and_modify(|classes| { classes.insert(class); })
|
|
||||||
.or_insert(BTreeSet::from_iter([class]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let inferred_class_table = table([inferred_class_subject_column, inferred_class_class_column], inferred_classes);
|
|
||||||
|
|
||||||
let subject_column = table::column(bold("Subject"), |triple: TripleRef| {
|
|
||||||
let curie = if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject {
|
|
||||||
Some(curie_helper
|
|
||||||
.abbreviate(Some(origin), subject.as_str())
|
|
||||||
.unwrap_or_else(|| subject.as_str().to_string()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
curie.map(text)
|
|
||||||
});
|
|
||||||
|
|
||||||
let predicate_column = table::column(bold("Predicate"), |triple: TripleRef| {
|
|
||||||
let curie = curie_helper
|
|
||||||
.abbreviate(None, triple.predicate.as_str())
|
|
||||||
.unwrap_or_else(|| triple.predicate.as_str().to_string());
|
|
||||||
|
|
||||||
let label = resource_descriptions
|
|
||||||
.get(&triple.predicate.into_owned())
|
|
||||||
.and_then(|description| description.label.clone());
|
|
||||||
|
|
||||||
if let Some(label) = label {
|
|
||||||
text(format!("{curie} ({label})"))
|
|
||||||
} else {
|
|
||||||
text(curie)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let object_column = table::column(bold("Object"), |triple: TripleRef| {
|
|
||||||
match triple.object {
|
|
||||||
TermRef::NamedNode(node) => {
|
|
||||||
let curie = curie_helper
|
|
||||||
.abbreviate(Some(origin), node.as_str())
|
|
||||||
.unwrap_or_else(|| node.as_str().to_string());
|
|
||||||
|
|
||||||
let label = resource_descriptions
|
|
||||||
.get(&node.into_owned())
|
|
||||||
.and_then(|description| description.label.clone());
|
|
||||||
|
|
||||||
if let Some(label) = label {
|
|
||||||
text(format!("{curie} ({label})"))
|
|
||||||
} else {
|
|
||||||
text(curie)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => text(triple.object.to_string()),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let all_inferences_table = table([subject_column, predicate_column, object_column], inferences);
|
|
||||||
|
|
||||||
column![
|
|
||||||
inferred_class_table,
|
|
||||||
scrollable(all_inferences_table),
|
|
||||||
].into()
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pub(crate) mod inferences;
|
|
||||||
Reference in New Issue
Block a user