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