This commit is contained in:
2026-07-24 19:25:07 -04:00
parent 54253a049f
commit 2618fe0d72
5 changed files with 68 additions and 26 deletions
Generated
+10 -4
View File
@@ -328,6 +328,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b25655df2c3cdd83c5e5b293b88acd880332b2ddadd7c30ac43144fdc0033da9"
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.72.1" version = "0.72.1"
@@ -1622,7 +1628,7 @@ version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
dependencies = [ dependencies = [
"base64", "base64 0.22.1",
"bytes", "bytes",
"futures-channel", "futures-channel",
"futures-util", "futures-util",
@@ -2099,7 +2105,7 @@ name = "ldp"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base64", "base64 0.23.0",
"bytes", "bytes",
"futures", "futures",
"http", "http",
@@ -3468,7 +3474,7 @@ version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
dependencies = [ dependencies = [
"base64", "base64 0.22.1",
"bytes", "bytes",
"futures-core", "futures-core",
"futures-util", "futures-util",
@@ -4104,7 +4110,7 @@ checksum = "edde6a10743fff00a4e1a8c9ef020bf5f3cbad301b7d2d39f2b07f123c4eac07"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"arc-swap", "arc-swap",
"base64", "base64 0.22.1",
"bitpacking", "bitpacking",
"bon", "bon",
"byteorder", "byteorder",
+33 -11
View File
@@ -18,7 +18,7 @@ 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, Quad, Term}; use oxigraph::model::{BaseDirection, Dataset, NamedNode, NamedOrBlankNode, Quad, Term};
use tracing::{debug_span, error, field, trace}; use tracing::{debug_span, error, field, trace};
use crate::navigator::Navigator; use crate::navigator::Navigator;
use crate::rdf::curie::CurieHelper; use crate::rdf::curie::CurieHelper;
@@ -56,6 +56,7 @@ pub(crate) enum Message {
SearchResultClicked(NamedNode), SearchResultClicked(NamedNode),
DatatypeUpdated(QuadKey, Option<String>), DatatypeUpdated(QuadKey, Option<String>),
LanguageUpdated(QuadKey, Option<String>), LanguageUpdated(QuadKey, Option<String>),
SubjectUpdated(QuadKey, String),
PredicateUpdated(QuadKey, String), PredicateUpdated(QuadKey, String),
ObjectUpdated(QuadKey, String), ObjectUpdated(QuadKey, String),
DirectionToggled(QuadKey, BaseDirection), DirectionToggled(QuadKey, BaseDirection),
@@ -129,7 +130,7 @@ impl Publisher {
let mut abbreviated_datatypes = ontology let mut abbreviated_datatypes = ontology
.datatypes() .datatypes()
.into_iter() .into_iter()
.map(|node| curie_helper.abbreviate(node.as_str()) .map(|node| curie_helper.abbreviate(None, node.as_str())
.unwrap_or(node.as_str().to_string()) .unwrap_or(node.as_str().to_string())
).collect::<Vec<_>>(); ).collect::<Vec<_>>();
abbreviated_datatypes.sort(); abbreviated_datatypes.sort();
@@ -238,7 +239,7 @@ impl Publisher {
Schema::iri_field() => individual.as_str(), Schema::iri_field() => individual.as_str(),
); );
if let Some(curie) = curie_helper.abbreviate(individual.as_str()) { if let Some(curie) = curie_helper.abbreviate(None, individual.as_str()) {
document.add_text(Schema::curie_field(), curie); document.add_text(Schema::curie_field(), curie);
} }
@@ -340,7 +341,7 @@ impl Publisher {
let term = TermHelper::new(&quad.object); let term = TermHelper::new(&quad.object);
let datatype = term let datatype = term
.datatype() .datatype()
.map(|datatype| self.curie_helper.abbreviate(datatype.as_str()) .map(|datatype| self.curie_helper.abbreviate(None, datatype.as_str())
.unwrap_or(datatype.as_str().to_string())); .unwrap_or(datatype.as_str().to_string()));
let datatype_state = combo_box::State::with_selection( let datatype_state = combo_box::State::with_selection(
@@ -454,7 +455,7 @@ impl Publisher {
Message::DatatypeUpdated(key, Some(maybe_prefixed_iri)) => { Message::DatatypeUpdated(key, Some(maybe_prefixed_iri)) => {
let node = self let node = self
.curie_helper .curie_helper
.expand(&maybe_prefixed_iri) .expand(None, &maybe_prefixed_iri)
.unwrap_or(maybe_prefixed_iri); .unwrap_or(maybe_prefixed_iri);
if let Some(quad) = self.document.dataset_mut().quads.get_mut(key) { if let Some(quad) = self.document.dataset_mut().quads.get_mut(key) {
@@ -484,6 +485,12 @@ impl Publisher {
self.modified = true; self.modified = true;
} }
} }
Message::SubjectUpdated(key, value) => {
if let Some(quad) = self.document.dataset_mut().quads.get_mut(key) {
quad.subject = NamedOrBlankNode::NamedNode(NamedNode::new_unchecked(value));
self.modified = true;
}
}
Message::PredicateUpdated(key, value) => { Message::PredicateUpdated(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) {
quad.predicate = NamedNode::new_unchecked(value); quad.predicate = NamedNode::new_unchecked(value);
@@ -627,7 +634,21 @@ impl Publisher {
container(space()).width(BUTTON_WIDTH) container(space()).width(BUTTON_WIDTH)
}; };
let predicate_input_base = iri_input(&self.curie_helper, "Predicate", triple.predicate.as_str()); let base = self.document.origin().as_str();
let subject = match &triple.subject {
NamedOrBlankNode::NamedNode(subject) => subject.as_str(),
_ => "",
};
let subject_input_base = iri_input(&self.curie_helper, "Subject", Some(&base), subject);
let subject_input = if self.ontology.is_read_only(triple.as_ref()) {
subject_input_base
} else {
subject_input_base.on_input(move |value| Message::SubjectUpdated(key, value))
};
let predicate_input_base = iri_input(&self.curie_helper, "Predicate", Some(&base), triple.predicate.as_str());
let predicate_input = if self.ontology.is_read_only(triple.as_ref()) { let predicate_input = if self.ontology.is_read_only(triple.as_ref()) {
predicate_input_base predicate_input_base
} else { } else {
@@ -659,7 +680,7 @@ impl Publisher {
}) })
.unwrap_or(Horizontal::Left); .unwrap_or(Horizontal::Left);
let object_input_base = iri_input(&self.curie_helper, "Object", value.as_str()) let object_input_base = iri_input(&self.curie_helper, "Object", Some(&base), value.as_str())
.on_shift_click(Message::NavigateToObject(key)); .on_shift_click(Message::NavigateToObject(key));
let object_input = if self.ontology.is_read_only(triple.as_ref()) { let object_input = if self.ontology.is_read_only(triple.as_ref()) {
object_input_base object_input_base
@@ -670,7 +691,7 @@ impl Publisher {
}; };
let selected_datatype = term.datatype() let selected_datatype = term.datatype()
.and_then(|node| self.curie_helper.abbreviate(node.as_str())); .and_then(|node| self.curie_helper.abbreviate(None, node.as_str()));
let datatype_selector: Element<Message> = if state.read_only { let datatype_selector: Element<Message> = if state.read_only {
selected_datatype.map(text).into() selected_datatype.map(text).into()
@@ -720,6 +741,7 @@ impl Publisher {
let row = row![ let row = row![
button_area, button_area,
subject_input,
predicate_input, predicate_input,
predicate_label, predicate_label,
object_input, object_input,
@@ -740,7 +762,7 @@ impl Publisher {
entities: impl IntoIterator<Item = LabeledIri>, entities: impl IntoIterator<Item = LabeledIri>,
) -> Element<'_, Message> { ) -> Element<'_, Message> {
let buttons = entities.into_iter().map(|entity| { let buttons = entities.into_iter().map(|entity| {
let abbreviation = self.curie_helper.abbreviate(entity.iri.as_str()) let abbreviation = self.curie_helper.abbreviate(None, entity.iri.as_str())
.unwrap_or_else(|| entity.iri.as_str().to_string()); .unwrap_or_else(|| entity.iri.as_str().to_string());
let label = format!("{} ({})", entity.label, abbreviation); let label = format!("{} ({})", entity.label, abbreviation);
@@ -775,7 +797,7 @@ impl Publisher {
.and_then(|value| value.as_str()) .and_then(|value| value.as_str())
.unwrap_or_default(); .unwrap_or_default();
let abbreviated_iri = self.curie_helper.abbreviate(iri) let abbreviated_iri = self.curie_helper.abbreviate(None, iri)
.unwrap_or_else(|| iri.to_string()); .unwrap_or_else(|| iri.to_string());
button(text(abbreviated_iri).wrapping(Wrapping::Word)) button(text(abbreviated_iri).wrapping(Wrapping::Word))
@@ -830,7 +852,7 @@ impl Publisher {
let reindex_ontology_button = button("Rebuild index").on_press(Message::RebuildIndex); let reindex_ontology_button = button("Rebuild index").on_press(Message::RebuildIndex);
let address_input = iri_input(&self.curie_helper, "URL", &self.url_input) let address_input = iri_input(&self.curie_helper, "URL", None, &self.url_input)
.on_input(Message::URLInputChanged) .on_input(Message::URLInputChanged)
.on_submit(Message::URLInputSubmitted) .on_submit(Message::URLInputSubmitted)
.on_control_click(Message::OpenQueryWindow(SearchResultClickAction::URLInput)); .on_control_click(Message::OpenQueryWindow(SearchResultClickAction::URLInput));
+11 -2
View File
@@ -12,7 +12,11 @@ impl CurieHelper {
} }
} }
pub fn abbreviate(&self, iri: &str) -> Option<String> { pub fn abbreviate(&self, base: Option<&str>, iri: &str) -> Option<String> {
if let Some(base) = base && let Some(local_name) = iri.strip_prefix(base) {
return Some(format!(":{local_name}"));
}
for (name, base) in &self.prefixes { for (name, base) in &self.prefixes {
if let Some(local_name) = iri.strip_prefix(base) { if let Some(local_name) = iri.strip_prefix(base) {
return Some(format!("{name}:{local_name}")); return Some(format!("{name}:{local_name}"));
@@ -21,10 +25,15 @@ impl CurieHelper {
None None
} }
pub fn expand(&self, abbreviated_iri: &str) -> Option<String> { pub fn expand(&self, base: Option<&str>, abbreviated_iri: &str) -> Option<String> {
let (prefix, name) = abbreviated_iri.split_once(':')?; let (prefix, name) = abbreviated_iri.split_once(':')?;
if prefix == "" && let Some(base) = base {
Some(format!("{base}{name}"))
} else {
self.prefixes self.prefixes
.get(prefix) .get(prefix)
.map(|base| format!("{base}{name}")) .map(|base| format!("{base}{name}"))
} }
}
} }
+2
View File
@@ -29,6 +29,8 @@ static PREFIXES: LazyLock<BTreeMap<String, String>> = LazyLock::new(|| {
"ebucore", "ebucore",
"http://www.ebu.ch/metadata/ontologies/ebucore/ebucore#", "http://www.ebu.ch/metadata/ontologies/ebucore/ebucore#",
), ),
("prov", "http://www.w3.org/ns/prov#"),
("locid", "http://id.loc.gov/vocabulary/identifiers/"),
("premis", "http://www.loc.gov/premis/rdf/v1#"), ("premis", "http://www.loc.gov/premis/rdf/v1#"),
("premis3", "http://www.loc.gov/premis/rdf/v3/"), ("premis3", "http://www.loc.gov/premis/rdf/v3/"),
("dcterms", "http://purl.org/dc/terms/"), ("dcterms", "http://purl.org/dc/terms/"),
+9 -6
View File
@@ -20,6 +20,7 @@ where
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
curie_helper: &'a CurieHelper, curie_helper: &'a CurieHelper,
base: Option<String>,
on_control_click: Option<Message>, on_control_click: Option<Message>,
on_shift_click: Option<Message>, on_shift_click: Option<Message>,
text_input: widget::TextInput<'a, Message, Theme, Renderer>, text_input: widget::TextInput<'a, Message, Theme, Renderer>,
@@ -31,11 +32,12 @@ where
Theme: Catalog, Theme: Catalog,
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
pub fn new(curie_helper: &'a CurieHelper, placeholder: &str, iri: &str) -> Self { pub fn new(curie_helper: &'a CurieHelper, placeholder: &str, base: Option<&str>, iri: &str) -> Self {
let display_value = curie_helper.abbreviate(iri).unwrap_or_else(|| iri.to_string()); let display_value = curie_helper.abbreviate(base, iri).unwrap_or_else(|| iri.to_string());
let text_input = widget::TextInput::new(placeholder, &display_value); let text_input = widget::TextInput::new(placeholder, &display_value);
Self { Self {
curie_helper, curie_helper,
base: base.map(String::from),
on_control_click: None, on_control_click: None,
on_shift_click: None, on_shift_click: None,
text_input, text_input,
@@ -62,8 +64,9 @@ where
#[must_use] #[must_use]
pub fn on_input(mut self, on_input: impl Fn(String) -> Message + 'a) -> Self { pub fn on_input(mut self, on_input: impl Fn(String) -> Message + 'a) -> Self {
let base_clone = self.base.clone();
let wrapped = move |value: String| { let wrapped = move |value: String| {
let expanded_value = self.curie_helper.expand(&value); let expanded_value = self.curie_helper.expand(base_clone.as_deref(), &value);
on_input(expanded_value.unwrap_or_else(|| value)) on_input(expanded_value.unwrap_or_else(|| value))
}; };
@@ -90,13 +93,13 @@ where
} }
} }
pub fn iri_input<'a, Message, Theme, Renderer>(curie_helper: &'a CurieHelper, placeholder: &str, iri: &str) -> IriInput<'a, Message, Theme, Renderer> pub fn iri_input<'a, Message, Theme, Renderer>(curie_helper: &'a CurieHelper, placeholder: &str, base: Option<&str>, iri: &str) -> IriInput<'a, Message, Theme, Renderer>
where where
Message: Clone, Message: Clone,
Theme: Catalog, Theme: Catalog,
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
IriInput::new(curie_helper, placeholder, iri) IriInput::new(curie_helper, placeholder, base, iri)
} }
impl <Message, Theme, Renderer> Widget<Message, Theme, Renderer> for IriInput<'_, Message, Theme, Renderer> impl <Message, Theme, Renderer> Widget<Message, Theme, Renderer> for IriInput<'_, Message, Theme, Renderer>
@@ -160,7 +163,7 @@ where
let clipboard = shell.clipboard_mut(); let clipboard = shell.clipboard_mut();
if let Some(Content::Text(content)) = &clipboard.write { if let Some(Content::Text(content)) = &clipboard.write {
if let Some(expanded) = self.curie_helper.expand(&content) { if let Some(expanded) = self.curie_helper.expand(self.base.as_deref(), &content) {
clipboard.write = Some(Content::Text(expanded)); clipboard.write = Some(Content::Text(expanded));
} }
} }