.
This commit is contained in:
+148
-97
@@ -3,6 +3,8 @@ 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::CurieHelper;
|
||||
use gl_graph::inference::InferenceEngine;
|
||||
use gl_search::language;
|
||||
use gl_search::{Schema, SearchDocument, SearchIndex, Value};
|
||||
use http::StatusCode;
|
||||
@@ -11,7 +13,10 @@ use iced::keyboard::{Event, key};
|
||||
use iced::widget::button::Style;
|
||||
use iced::widget::grid::Sizing;
|
||||
use iced::widget::text::Wrapping;
|
||||
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::{Background, Color, Element, Length, Subscription, Task, color, keyboard, window};
|
||||
use ldp::middleware::BasicAuthMiddleware;
|
||||
@@ -21,11 +26,12 @@ 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, Graph, NamedNode, NamedOrBlankNode, NamedOrBlankNodeRef, Quad, Term, TripleRef};
|
||||
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::CurieHelper;
|
||||
use gl_graph::inference::InferenceEngine;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum Message {
|
||||
@@ -139,9 +145,12 @@ impl Publisher {
|
||||
let mut abbreviated_datatypes = ontology
|
||||
.datatypes()
|
||||
.into_iter()
|
||||
.map(|node| curie_helper.abbreviate(None, node.as_str())
|
||||
.unwrap_or(node.as_str().to_string())
|
||||
).collect::<Vec<_>>();
|
||||
.map(|node| {
|
||||
curie_helper
|
||||
.abbreviate(None, node.as_str())
|
||||
.unwrap_or(node.as_str().to_string())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
abbreviated_datatypes.sort();
|
||||
|
||||
let (id, task) = window::open(Settings::default());
|
||||
@@ -246,21 +255,15 @@ impl Publisher {
|
||||
});
|
||||
}
|
||||
Message::LoadDocument(document) => {
|
||||
let messages = document
|
||||
.dataset()
|
||||
.quads
|
||||
.iter()
|
||||
.map(|(key, quad)| {
|
||||
let datatype_state = combo_box::State::new(
|
||||
self.abbreviated_datatypes.clone(),
|
||||
);
|
||||
let messages = document.dataset().quads.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)))
|
||||
});
|
||||
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));
|
||||
@@ -277,9 +280,7 @@ impl Publisher {
|
||||
quad.object = Term::NamedNode(empty_node);
|
||||
|
||||
let key = self.document.dataset_mut().quads.insert(quad);
|
||||
let datatype_state = combo_box::State::new(
|
||||
self.abbreviated_datatypes.clone(),
|
||||
);
|
||||
let datatype_state = combo_box::State::new(self.abbreviated_datatypes.clone());
|
||||
let state = RowState {
|
||||
read_only: false,
|
||||
datatype_state,
|
||||
@@ -306,14 +307,14 @@ impl Publisher {
|
||||
let selected_entity_class = match action {
|
||||
SearchResultClickAction::Predicate(_) => Some(rdf::PROPERTY),
|
||||
SearchResultClickAction::Object(key) => {
|
||||
self.document
|
||||
.dataset()
|
||||
.quads
|
||||
.get(key)
|
||||
.and_then(|quad| if quad.predicate == rdf::TYPE {
|
||||
self.document.dataset().quads.get(key).and_then(|quad| {
|
||||
if quad.predicate == rdf::TYPE {
|
||||
Some(rdfs::CLASS)
|
||||
} else { None })
|
||||
},
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
SearchResultClickAction::URLInput => None,
|
||||
};
|
||||
|
||||
@@ -332,7 +333,10 @@ impl Publisher {
|
||||
}
|
||||
|
||||
if let Some(selected_entity_class) = selected_entity_class {
|
||||
let selection = self.ontology.info(&selected_entity_class.into_owned(), &*language::ENGLISH_OR_UNTAGGED);
|
||||
let selection = self.ontology.info(
|
||||
&selected_entity_class.into_owned(),
|
||||
&*language::ENGLISH_OR_UNTAGGED,
|
||||
);
|
||||
task = task.chain(Task::done(Message::QueryTypeUpdated(selection)));
|
||||
}
|
||||
}
|
||||
@@ -344,13 +348,16 @@ impl Publisher {
|
||||
}
|
||||
Message::QueryUpdated(new_query) => {
|
||||
if let Some(search_state) = &mut self.search_state {
|
||||
let category_id = search_state.entity_selection
|
||||
let category_id = search_state
|
||||
.entity_selection
|
||||
.clone()
|
||||
.and_then(|info| self.ontology.category_id(&info.iri));
|
||||
|
||||
let query = new_query.clone();
|
||||
search_state.query = new_query;
|
||||
let results = self.index.query(category_id, query.as_str(), Schema::all_fields(), 25)
|
||||
let results = self
|
||||
.index
|
||||
.query(category_id, query.as_str(), Schema::all_fields(), 25)
|
||||
.expect("Unable to complete search");
|
||||
task = Task::done(Message::SetSearchResults(results));
|
||||
};
|
||||
@@ -548,7 +555,8 @@ impl Publisher {
|
||||
self.show_inferred_properties = value;
|
||||
}
|
||||
Message::RunInference => {
|
||||
let dataset = self.document
|
||||
let dataset = self
|
||||
.document
|
||||
.dataset()
|
||||
.quads
|
||||
.iter()
|
||||
@@ -556,18 +564,19 @@ impl Publisher {
|
||||
.collect();
|
||||
|
||||
let engine = self.inference_engine.clone();
|
||||
task = Task::perform(tokio::task::spawn_blocking(move || {
|
||||
engine.run(&dataset).unwrap()
|
||||
}), |dataset| Message::SetInferredTriples(dataset.unwrap()));
|
||||
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,
|
||||
..
|
||||
}) => {
|
||||
key: keyboard::Key::Named(key::Named::Tab),
|
||||
modifiers,
|
||||
..
|
||||
}) => {
|
||||
if modifiers.shift() {
|
||||
task = operation::focus_previous();
|
||||
} else {
|
||||
@@ -621,22 +630,34 @@ impl Publisher {
|
||||
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_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()) {
|
||||
predicate_input_base
|
||||
} else {
|
||||
predicate_input_base.on_input(move |value| Message::PredicateUpdated(key, value))
|
||||
.on_control_click(Message::OpenQueryWindow(SearchResultClickAction::Predicate(key)))
|
||||
predicate_input_base
|
||||
.on_input(move |value| Message::PredicateUpdated(key, value))
|
||||
.on_control_click(Message::OpenQueryWindow(
|
||||
SearchResultClickAction::Predicate(key),
|
||||
))
|
||||
.on_shift_click(Message::NavigateToPredicate(key))
|
||||
};
|
||||
|
||||
let predicate_info = self.ontology.info(&triple.predicate, &*language::ENGLISH_OR_UNTAGGED);
|
||||
let predicate_info = self
|
||||
.ontology
|
||||
.info(&triple.predicate, &*language::ENGLISH_OR_UNTAGGED);
|
||||
let predicate_label = container(text(predicate_info.label));
|
||||
|
||||
let term = TermHelper::new(&triple.object);
|
||||
|
||||
let value_label = term.value_as_named_node().and_then(|node| {
|
||||
let info = self.ontology.info(&node.into_owned(), &*language::ENGLISH_OR_UNTAGGED);
|
||||
let info = self
|
||||
.ontology
|
||||
.info(&node.into_owned(), &*language::ENGLISH_OR_UNTAGGED);
|
||||
Some(container(text(info.label)))
|
||||
});
|
||||
|
||||
@@ -660,7 +681,8 @@ impl Publisher {
|
||||
if self.ontology.is_read_only(triple.as_ref()) {
|
||||
base.into()
|
||||
} else {
|
||||
base.on_input(move |value| Message::ObjectUpdated(key, value)).into()
|
||||
base.on_input(move |value| Message::ObjectUpdated(key, value))
|
||||
.into()
|
||||
}
|
||||
} else {
|
||||
let base = iri_input(&self.curie_helper, "Object", Some(&base), value.as_str())
|
||||
@@ -670,12 +692,15 @@ impl Publisher {
|
||||
} else {
|
||||
base.align_x(value_alignment)
|
||||
.on_input(move |value| Message::ObjectUpdated(key, value))
|
||||
.on_control_click(Message::OpenQueryWindow(SearchResultClickAction::Object(key)))
|
||||
.on_control_click(Message::OpenQueryWindow(SearchResultClickAction::Object(
|
||||
key,
|
||||
)))
|
||||
.into()
|
||||
}
|
||||
};
|
||||
|
||||
let selected_datatype = term.datatype()
|
||||
let selected_datatype = term
|
||||
.datatype()
|
||||
.and_then(|node| self.curie_helper.abbreviate(None, node.as_str()));
|
||||
|
||||
let datatype_selector: Element<Message> = if state.read_only {
|
||||
@@ -690,7 +715,8 @@ impl Publisher {
|
||||
.on_input(move |input| {
|
||||
let value = if input.is_empty() { None } else { Some(input) };
|
||||
Message::DatatypeUpdated(key, value)
|
||||
}).into()
|
||||
})
|
||||
.into()
|
||||
};
|
||||
|
||||
let language = term.language().unwrap_or("en").to_owned();
|
||||
@@ -748,7 +774,9 @@ impl Publisher {
|
||||
entities: impl IntoIterator<Item = LabeledIri>,
|
||||
) -> Element<'_, Message> {
|
||||
let buttons = entities.into_iter().map(|entity| {
|
||||
let abbreviation = self.curie_helper.abbreviate(None, entity.iri.as_str())
|
||||
let abbreviation = self
|
||||
.curie_helper
|
||||
.abbreviate(None, entity.iri.as_str())
|
||||
.unwrap_or_else(|| entity.iri.as_str().to_string());
|
||||
|
||||
let label = format!("{} ({})", entity.label, abbreviation);
|
||||
@@ -766,35 +794,41 @@ impl Publisher {
|
||||
if let Some(search_state) = &self.search_state
|
||||
&& search_state.window_id == window
|
||||
{
|
||||
let search_input =
|
||||
text_input("Query", &search_state.query).on_input(Message::QueryUpdated)
|
||||
.id("query");
|
||||
let search_input = text_input("Query", &search_state.query)
|
||||
.on_input(Message::QueryUpdated)
|
||||
.id("query");
|
||||
|
||||
let entities = Vec::new(); /*self.ontology
|
||||
.searchable_classes(&*language::ENGLISH_OR_UNTAGGED)
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();*/
|
||||
.searchable_classes(&*language::ENGLISH_OR_UNTAGGED)
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();*/
|
||||
|
||||
let type_selector = pick_list(search_state.entity_selection.as_ref(), entities, ToString::to_string)
|
||||
.on_select(|selection| Message::QueryTypeUpdated(selection));
|
||||
let type_selector = pick_list(
|
||||
search_state.entity_selection.as_ref(),
|
||||
entities,
|
||||
ToString::to_string,
|
||||
)
|
||||
.on_select(|selection| Message::QueryTypeUpdated(selection));
|
||||
|
||||
let mut columns = vec![
|
||||
table::column(text("CURIE"), |document: &SearchDocument| {
|
||||
let iri = document.get_first(Schema::iri_field())
|
||||
.and_then(|value| value.as_str())
|
||||
.unwrap_or_default();
|
||||
let mut columns = vec![table::column(text("CURIE"), |document: &SearchDocument| {
|
||||
let iri = document
|
||||
.get_first(Schema::iri_field())
|
||||
.and_then(|value| value.as_str())
|
||||
.unwrap_or_default();
|
||||
|
||||
let abbreviated_iri = self.curie_helper.abbreviate(None, iri)
|
||||
.unwrap_or_else(|| iri.to_string());
|
||||
let abbreviated_iri = self
|
||||
.curie_helper
|
||||
.abbreviate(None, iri)
|
||||
.unwrap_or_else(|| iri.to_string());
|
||||
|
||||
button(text(abbreviated_iri).wrapping(Wrapping::Word))
|
||||
.on_press(Message::SearchResultClicked(NamedNode::new_unchecked(iri)))
|
||||
.style(button::text)
|
||||
})
|
||||
];
|
||||
button(text(abbreviated_iri).wrapping(Wrapping::Word))
|
||||
.on_press(Message::SearchResultClicked(NamedNode::new_unchecked(iri)))
|
||||
.style(button::text)
|
||||
})];
|
||||
|
||||
let fields = if let Some(selection) = search_state.entity_selection.as_ref() {
|
||||
self.ontology.fields_for_class(&selection.iri, &*language::ENGLISH_OR_UNTAGGED)
|
||||
self.ontology
|
||||
.fields_for_class(&selection.iri, &*language::ENGLISH_OR_UNTAGGED)
|
||||
.expect("Unable to load fields for class")
|
||||
} else {
|
||||
vec![]
|
||||
@@ -804,18 +838,21 @@ impl Publisher {
|
||||
let field_name = field.name.clone();
|
||||
columns.push(
|
||||
table::column(text(field.label), move |document: &SearchDocument| {
|
||||
let iri = document.get_first(Schema::iri_field())
|
||||
let iri = document
|
||||
.get_first(Schema::iri_field())
|
||||
.and_then(|value| value.as_str())
|
||||
.unwrap_or_default();
|
||||
|
||||
let value = document.get_first(Schema::field(&field_name, Some(language::ENGLISH_PRIMARY)))
|
||||
let value = document
|
||||
.get_first(Schema::field(&field_name, Some(language::ENGLISH_PRIMARY)))
|
||||
.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))
|
||||
})
|
||||
.width(Length::Fixed(256.0)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -825,10 +862,7 @@ impl Publisher {
|
||||
Some(scrollable(table(columns, &search_state.results)))
|
||||
};
|
||||
|
||||
return column![
|
||||
row![search_input, type_selector],
|
||||
results_table
|
||||
].into();
|
||||
return column![row![search_input, type_selector], results_table].into();
|
||||
}
|
||||
|
||||
let back_button = button("\u{1f870}").on_press(Message::NavigateBack);
|
||||
@@ -841,7 +875,9 @@ impl Publisher {
|
||||
.on_input(Message::URLInputChanged)
|
||||
.on_submit(Message::URLInputSubmitted)
|
||||
.on_control_click(Message::OpenQueryWindow(SearchResultClickAction::URLInput))
|
||||
.style(crate::theme::styles::text_input::required(!self.url_input_valid));
|
||||
.style(crate::theme::styles::text_input::required(
|
||||
!self.url_input_valid,
|
||||
));
|
||||
|
||||
let mut rows: Vec<Element<Message>> = vec![];
|
||||
rows = self
|
||||
@@ -854,7 +890,9 @@ impl Publisher {
|
||||
|
||||
let body: Element<Message> = if self.show_new_document_buttons {
|
||||
let subclasses = Vec::new(); // TODO self.ontology.subclasses_of(vocab::rda::ENTITY.into_owned());
|
||||
let labeled_subclasses = subclasses.iter().map(|iri| self.ontology.info(iri, &*language::ENGLISH_OR_UNTAGGED));
|
||||
let labeled_subclasses = subclasses
|
||||
.iter()
|
||||
.map(|iri| self.ontology.info(iri, &*language::ENGLISH_OR_UNTAGGED));
|
||||
column![self.view_new_entity_buttons(labeled_subclasses)].into()
|
||||
} else {
|
||||
column(rows).into()
|
||||
@@ -864,24 +902,38 @@ impl Publisher {
|
||||
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 };
|
||||
} 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 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 };
|
||||
} 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 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 {
|
||||
@@ -890,14 +942,13 @@ impl Publisher {
|
||||
save_button_base
|
||||
};
|
||||
|
||||
let inferred_type_toggle = toggler(self.show_inferred_types)
|
||||
.on_toggle(Message::SetInferredTypes);
|
||||
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 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 read_only_toggle = toggler(self.show_read_only).on_toggle(Message::SetReadOnly);
|
||||
|
||||
let footer = row![
|
||||
space::horizontal(),
|
||||
@@ -923,8 +974,8 @@ impl Publisher {
|
||||
scrollable(body),
|
||||
scrollable(inference_table),
|
||||
])
|
||||
.on_back_click(Message::NavigateBack)
|
||||
.on_forward_click(Message::NavigateForward);
|
||||
.on_back_click(Message::NavigateBack)
|
||||
.on_forward_click(Message::NavigateForward);
|
||||
|
||||
if self.show_overwrite_confirmation {
|
||||
let confirmation_modal = container(column![
|
||||
@@ -973,4 +1024,4 @@ where
|
||||
)
|
||||
]
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user