This commit is contained in:
Alex Wied
2026-07-08 21:07:52 -04:00
parent eff98162cd
commit a19a434e70
3 changed files with 51 additions and 23 deletions
+33 -17
View File
@@ -17,8 +17,8 @@ use ldp::traverse::Traverse;
use ldp::{RdfSource, RdfSourceUpdateResponse, ResourceRequestBuilder, SerializationOptions};
use oxigraph::io::RdfFormat;
use oxigraph::model::vocab::{rdf, rdfs};
use oxigraph::model::{BaseDirection, Dataset, NamedNode, NamedNodeRef, Quad, Term};
use tracing::{debug, debug_span, error, trace};
use oxigraph::model::{BaseDirection, BlankNode, Dataset, NamedNode, NamedNodeRef, NamedOrBlankNode, Quad, Term, Triple};
use tracing::{debug, debug_span, error, info, trace};
use crate::rdf::language;
use crate::rdf::vocab::rda;
use crate::widget::iri_input::iri_input;
@@ -49,7 +49,8 @@ pub(crate) enum Message {
SearchResultClicked(NamedNode),
DatatypeUpdated(QuadKey, Option<String>),
LanguageUpdated(QuadKey, Option<String>),
ValueUpdated(QuadKey, String),
PredicateUpdated(QuadKey, String),
ObjectUpdated(QuadKey, String),
DirectionToggled(QuadKey, BaseDirection),
SaveGraph(bool),
ShowOverwriteConfirmationModal,
@@ -315,7 +316,7 @@ impl Publisher {
if let Some(search_state) = &mut self.search_state {
search_state.action = action;
} else {
if let Some(entity) = self.ontology.searchable_classes(&*language::ENGLISH_OR_UNTAGGED).next() {
if let Some(entity) = self.ontology.searchable_classes(&*language::ENGLISH_OR_UNTAGGED).into_iter().next() {
let (id, window_task) = window::open(Settings::default());
self.search_state = Some(SearchState {
window_id: id,
@@ -434,7 +435,13 @@ impl Publisher {
self.modified = true;
}
}
Message::ValueUpdated(key, value) => {
Message::PredicateUpdated(key, value) => {
if let Some(quad) = self.document.dataset_mut().quads.get_mut(key) {
quad.predicate = NamedNode::new_unchecked(value);
self.modified = true;
}
}
Message::ObjectUpdated(key, value) => {
if let Some(quad) = self.document.dataset_mut().quads.get_mut(key) {
let mut term = TermHelperMut::new(&mut quad.object);
term.set_value(value);
@@ -488,21 +495,30 @@ impl Publisher {
let subject = NamedNode::new_unchecked(url.as_str());
self.document = RdfSource::new(url);
let quads = self
let template_quads = self
.ontology
.template_triples(class.as_ref(), subject.as_ref())
.map(|triples| {
triples
.map(|triple| self.document.quad_from_triple(triple))
.collect::<Vec<_>>()
});
})
.unwrap_or_else(|| {
let triple = Triple::new(
NamedOrBlankNode::BlankNode(BlankNode::default()),
rdf::TYPE,
Term::NamedNode(class)
);
vec![
self.document.quad_from_triple(triple)
]
});
if let Some(quads) = quads {
let new_keys = self.document.dataset_mut().extend(quads.into_iter());
let messages = new_keys.map(|triple| Message::AddRow(Some(triple)));
task = Task::done(Message::HideNewDocumentButtons)
.chain(Task::batch(messages.map(Task::done)));
}
task = Task::done(Message::HideNewDocumentButtons);
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)));
}
Message::ResetState => {
self.modified = false;
@@ -542,7 +558,7 @@ impl Publisher {
};
let predicate_input = iri_input(self.ontology.prefixes(), "Predicate", triple.predicate.as_str())
.on_input(move |value| Message::ValueUpdated(key, value))
.on_input(move |value| Message::PredicateUpdated(key, value))
.on_control_click(Message::OpenQueryWindow(SearchResultClickAction::Predicate(key)));
let term = TermHelper::new(&triple.object);
@@ -567,7 +583,7 @@ impl Publisher {
let object_input = iri_input(self.ontology.prefixes(), "Object", value.as_str())
.align_x(value_alignment)
.on_input(move |value| Message::ValueUpdated(key, value))
.on_input(move |value| Message::ObjectUpdated(key, value))
.on_control_click(Message::OpenQueryWindow(SearchResultClickAction::Object(key)));
let selected_datatype = term.datatype().map(|node| self.ontology.abbreviate(node));
@@ -656,10 +672,10 @@ impl Publisher {
let search_input =
text_input("Query", &search_state.query).on_input(Message::QueryUpdated);
let mut entities = self.ontology
let entities = self.ontology
.searchable_classes(&*language::ENGLISH_OR_UNTAGGED)
.into_iter()
.collect::<Vec<_>>();
entities.sort_by(|a, b| Ord::cmp(&a.label, &b.label));
let type_selector = pick_list(Some(&search_state.type_), entities, ToString::to_string)
.on_select(|selection| Message::QueryTypeUpdated(selection));
+16 -4
View File
@@ -97,7 +97,7 @@ pub struct IndexEntry {
pub fields: HashMap<String, String>,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Eq)]
pub struct LabeledIri {
pub iri: NamedNode,
pub label: String,
@@ -109,6 +109,18 @@ impl PartialEq for LabeledIri {
}
}
impl PartialOrd for LabeledIri {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.label.partial_cmp(&other.label)
}
}
impl Ord for LabeledIri {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.label.cmp(&other.label)
}
}
impl Display for LabeledIri {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.label)
@@ -255,8 +267,8 @@ WHERE {{
}
}
pub fn searchable_classes(&self, language: &LanguageCondition) -> impl Iterator<Item = LabeledIri> {
self.store.quads_for_pattern(None, Some(rdf::TYPE), Some(gl::SEARCHABLE.into()), None)
pub fn searchable_classes(&self, language: &LanguageCondition) -> BTreeSet<LabeledIri> {
self.store.quads_for_pattern(None, Some(rdf::TYPE), Some(gl::SEARCHABLE_CLASS.into()), None)
.filter_map(Result::ok)
.filter_map(|quad| {
let label = self.store.quads_for_pattern(Some(quad.subject.as_ref().into()), Some(rdfs::LABEL), None, None)
@@ -271,7 +283,7 @@ WHERE {{
label,
})
} else { None }
})
}).collect()
}
pub fn subclasses_of(&self, class: &NamedNode) -> BTreeSet<NamedNode> {
+2 -2
View File
@@ -10,8 +10,8 @@ pub mod gl {
pub const CATALOG_ID: NamedNodeRef =
NamedNodeRef::new_unchecked("https://graphofliberty.org/2026/04/ont/catalogId");
pub const SEARCHABLE: NamedNodeRef =
NamedNodeRef::new_unchecked("https://graphofliberty.org/2026/04/ont/Searchable");
pub const SEARCHABLE_CLASS: NamedNodeRef =
NamedNodeRef::new_unchecked("https://graphofliberty.org/2026/04/ont/SearchableClass");
pub const ENTITY: NamedNodeRef =
NamedNodeRef::new_unchecked("https://graphofliberty.org/2026/04/ont/Entity");