This commit is contained in:
2026-08-07 19:28:08 -04:00
parent 36a105edfc
commit 64a2c87346
4 changed files with 112 additions and 48 deletions
+100 -28
View File
@@ -3,7 +3,6 @@ use crate::rdf::ontology::{LabeledIri, Ontology};
use crate::rdf::term_helper::{TermHelper, TermHelperMut};
use crate::widget::iri_input::iri_input;
use crate::widget::navigation_area::navigation_area;
use gl_graph::vocab::rdac;
use gl_search::language;
use gl_search::{Schema, SearchDocument, SearchIndex, Value};
use http::StatusCode;
@@ -22,9 +21,11 @@ use ldp::reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
use ldp::{RdfSource, RdfSourceUpdateResponse, ResourceRequestBuilder, SerializationOptions};
use oxigraph::io::RdfFormat;
use oxigraph::model::vocab::{rdf, rdfs};
use oxigraph::model::{BaseDirection, Dataset, NamedNode, NamedOrBlankNode, Quad, Term};
use oxigraph::model::{BaseDirection, Dataset, Graph, NamedNode, NamedOrBlankNode, NamedOrBlankNodeRef, Quad, Term, TripleRef};
use oxigraph::store::Store;
use tracing::{debug_span, error, trace};
use gl_graph::{vocab, CurieHelper};
use gl_graph::CurieHelper;
use gl_graph::inference::InferenceEngine;
#[derive(Clone, Debug)]
pub(crate) enum Message {
@@ -38,7 +39,7 @@ pub(crate) enum Message {
ShowNewDocumentButtons,
HideNewDocumentButtons,
ShowError(String),
AddRow(Option<QuadKey>),
AddRow(Option<(QuadKey, RowState)>),
DeleteRow(QuadKey),
DeleteAllRows,
OpenQueryWindow(SearchResultClickAction),
@@ -65,6 +66,10 @@ pub(crate) enum Message {
NavigateForward,
ResetState,
SetReadOnly(bool),
SetInferredTypes(bool),
SetInferredProperties(bool),
RunInference,
SetInferredTriples(Dataset),
Event(Event),
}
@@ -93,13 +98,17 @@ pub(crate) struct Publisher {
http_client: ClientWithMiddleware,
curie_helper: CurieHelper,
ontology: Ontology,
inference_engine: InferenceEngine,
abbreviated_datatypes: Vec<String>,
window_id: window::Id,
url_input: String,
url_input_valid: bool,
navigator: Navigator<Url>,
document: RdfSource<KeyedDataset<RowState>>,
inferred_triples: Graph,
show_read_only: bool,
show_inferred_types: bool,
show_inferred_properties: bool,
hovered_row: Option<QuadKey>,
search_state: Option<SearchState>,
index: SearchIndex,
@@ -120,6 +129,8 @@ impl Publisher {
.expect("Failed to build ontology")
});
let inference_engine = InferenceEngine::new(ontology.store().clone());
let index = SearchIndex::builder()
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/index")
.build()
@@ -152,13 +163,17 @@ impl Publisher {
http_client,
curie_helper,
ontology,
inference_engine,
abbreviated_datatypes,
window_id: id,
url_input: starting_url.to_string(),
url_input_valid: true,
navigator,
document,
inferred_triples: Graph::new(),
show_read_only: false,
show_inferred_types: false,
show_inferred_properties: false,
hovered_row: None,
search_state: None,
index,
@@ -234,9 +249,21 @@ impl Publisher {
let messages = document
.dataset()
.quads
.keys()
.map(|key| Message::AddRow(Some(key)));
task = Task::batch(messages.map(Task::done)).chain(Task::done(Message::ResetState));
.iter()
.map(|(key, quad)| {
let datatype_state = combo_box::State::new(
self.abbreviated_datatypes.clone(),
);
let state = RowState {
read_only: self.ontology.is_read_only(quad.as_ref()),
datatype_state,
};
Message::AddRow(Some((key, state)))
});
task = Task::batch(messages.map(Task::done))
.chain(Task::done(Message::RunInference))
.chain(Task::done(Message::ResetState));
self.document = document;
}
@@ -250,33 +277,21 @@ impl Publisher {
quad.object = Term::NamedNode(empty_node);
let key = self.document.dataset_mut().quads.insert(quad);
task = Task::done(Message::AddRow(Some(key)));
}
Message::AddRow(Some(key)) => {
let quad = self
.document
.dataset()
.quads
.get(key)
.expect("Failed to get quad from document");
let read_only = self.ontology.is_read_only(quad.as_ref());
let term = TermHelper::new(&quad.object);
let datatype = term
.datatype()
.map(|datatype| self.curie_helper.abbreviate(None, datatype.as_str())
.unwrap_or(datatype.as_str().to_string()));
let datatype_state = combo_box::State::new(
self.abbreviated_datatypes.clone(),
);
let state = RowState {
read_only,
read_only: false,
datatype_state,
};
task = Task::done(Message::AddRow(Some((key, state))));
}
Message::AddRow(Some((key, state))) => {
self.document
.dataset_mut()
.associated_data
.insert(key, state);
self.modified = true;
}
Message::DeleteRow(key) => {
@@ -472,7 +487,7 @@ impl Publisher {
let subject = NamedNode::new_unchecked(url.as_str());
self.document = RdfSource::new(url);
let template_quads = self
/*let template_quads = self
.ontology
.template_triples(class.as_ref(), subject.as_ref())
.map(|triples| {
@@ -490,7 +505,7 @@ impl Publisher {
let new_keys = self.document.dataset_mut().extend(template_quads.into_iter());
let messages = new_keys.map(|triple| Message::AddRow(Some(triple)));
task = task.chain(Task::batch(messages.map(Task::done)));
task = task.chain(Task::batch(messages.map(Task::done)));*/
}
Message::ResetState => {
self.modified = false;
@@ -526,6 +541,28 @@ impl Publisher {
Message::SetReadOnly(value) => {
self.show_read_only = value;
}
Message::SetInferredTypes(value) => {
self.show_inferred_types = value;
}
Message::SetInferredProperties(value) => {
self.show_inferred_properties = value;
}
Message::RunInference => {
let dataset = self.document
.dataset()
.quads
.iter()
.map(|(_, quad)| quad)
.collect();
let engine = self.inference_engine.clone();
task = Task::perform(tokio::task::spawn_blocking(move || {
engine.run(&dataset).unwrap()
}), |dataset| Message::SetInferredTriples(dataset.unwrap()));
}
Message::SetInferredTriples(dataset) => {
self.inferred_triples = Graph::from_iter(&dataset);
}
Message::Event(Event::KeyPressed {
key: keyboard::Key::Named(key::Named::Tab),
modifiers,
@@ -823,6 +860,29 @@ impl Publisher {
column(rows).into()
};
let inference_table = if self.show_inferred_properties {
let subject_column = table::column("Subject", |triple: TripleRef| {
let curie = if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject {
self.curie_helper.abbreviate(None, subject.as_str())
} else { None };
curie.map(text)
});
let predicate_column = table::column("Predicate", |triple: TripleRef| {
let predicate_info = self.ontology.info(&triple.predicate.into_owned(), &*language::ENGLISH_OR_UNTAGGED);
let label = if predicate_info.label.is_empty() {
self.curie_helper
.abbreviate(None, triple.predicate.as_str())
.unwrap_or(triple.predicate.as_str().to_string())
} else { predicate_info.label };
text(label)
});
let object_column = table::column("Object", |triple: TripleRef| text(triple.object.to_string()));
Some(table([subject_column, predicate_column, object_column], self.inferred_triples.iter()))
} else { None };
let save_button_base = button(text("\u{1f4be}"));
let save_button = if self.modified {
save_button_base.on_press(Message::SaveGraph(false))
@@ -830,10 +890,22 @@ impl Publisher {
save_button_base
};
let inferred_type_toggle = toggler(self.show_inferred_types)
.on_toggle(Message::SetInferredTypes);
let inferred_property_toggle = toggler(self.show_inferred_properties)
.on_toggle(Message::SetInferredProperties);
let read_only_toggle = toggler(self.show_read_only)
.on_toggle(Message::SetReadOnly);
let footer = row![
space::horizontal(),
text("Show Inferred Types"),
inferred_type_toggle,
space::horizontal(),
text("Show Inferred Properties"),
inferred_property_toggle,
space::horizontal(),
text("Show Read Only Triples"),
read_only_toggle
@@ -847,9 +919,9 @@ impl Publisher {
address_input,
save_button,
],
scrollable(body),
space::vertical(),
footer,
scrollable(body),
scrollable(inference_table),
])
.on_back_click(Message::NavigateBack)
.on_forward_click(Message::NavigateForward);