.
This commit is contained in:
+31
-111
@@ -1,40 +1,34 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::rdf::ontology::{IndexEntry, LabeledIri, Ontology};
|
||||
use crate::navigator::Navigator;
|
||||
use crate::rdf::curie::CurieHelper;
|
||||
use crate::rdf::ontology::{LabeledIri, Ontology};
|
||||
use crate::rdf::term_helper::{TermHelper, TermHelperMut};
|
||||
use gl_search::{Schema, SearchDocument, SearchIndex, doc, Value};
|
||||
use crate::rdf::vocab::rda;
|
||||
use crate::widget::iri_input::iri_input;
|
||||
use crate::widget::navigation_area::navigation_area;
|
||||
use gl_search::language;
|
||||
use gl_search::{IndexWriter, Schema, SearchDocument, SearchIndex, Value};
|
||||
use http::StatusCode;
|
||||
use iced::alignment::Horizontal;
|
||||
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::window::Settings;
|
||||
use iced::{Background, Color, Element, Length, Subscription, Task, color, window};
|
||||
use iced::widget::text::Wrapping;
|
||||
use iced::{Background, Color, Element, Length, Subscription, Task, color, keyboard, window};
|
||||
use ldp::middleware::BasicAuthMiddleware;
|
||||
use ldp::model::{KeyedDataset, QuadKey};
|
||||
use ldp::reqwest::{Client, Url};
|
||||
use ldp::reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
||||
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, NamedOrBlankNode, Quad, Term};
|
||||
use tracing::{debug_span, error, field, trace};
|
||||
use crate::navigator::Navigator;
|
||||
use crate::rdf::curie::CurieHelper;
|
||||
use crate::rdf::language;
|
||||
use crate::rdf::vocab::rda;
|
||||
use crate::widget::iri_input::iri_input;
|
||||
use crate::widget::navigation_area::navigation_area;
|
||||
use tracing::{debug_span, error, trace};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum Message {
|
||||
None,
|
||||
RebuildIndex,
|
||||
Traverse,
|
||||
AddRdfSource(RdfSource<Dataset>),
|
||||
ConcludeTraversal,
|
||||
IndexQueryResults(HashMap<NamedNode, IndexEntry>),
|
||||
WindowClosed(window::Id),
|
||||
URLInputChanged(String),
|
||||
URLInputSubmitted,
|
||||
@@ -71,6 +65,7 @@ pub(crate) enum Message {
|
||||
NavigateForward,
|
||||
ResetState,
|
||||
SetReadOnly(bool),
|
||||
Event(Event),
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
@@ -181,90 +176,6 @@ impl Publisher {
|
||||
trace!(?message);
|
||||
|
||||
match message {
|
||||
Message::RebuildIndex => {
|
||||
let mut writer = self.index.writer().expect("Unable to obtain index writer");
|
||||
let clear_index_task = Task::perform(tokio::task::spawn_blocking(move || {
|
||||
let _span = debug_span!("Clear Index").entered();
|
||||
writer.delete_all_documents().expect("Unable to clear index");
|
||||
writer.commit().expect("Unable to commit index operation");
|
||||
}), |_| Message::None);
|
||||
|
||||
let index_future = self.ontology
|
||||
.query_for_indexable_triples(&*language::ENGLISH_OR_UNTAGGED, None);
|
||||
let index_task = Task::perform(index_future, |task_result| {
|
||||
match task_result {
|
||||
Ok(results) => Message::IndexQueryResults(results),
|
||||
Err(err) => Message::ShowError(err.to_string()),
|
||||
}
|
||||
});
|
||||
|
||||
task = clear_index_task.chain(Task::batch([
|
||||
index_task,
|
||||
Task::done(Message::Traverse),
|
||||
]));
|
||||
}
|
||||
Message::Traverse => {
|
||||
let client = self.http_client.clone();
|
||||
let root = Url::parse(&self.url_input).expect("Invalid URL");
|
||||
let stream = Traverse::new(client, root, None);
|
||||
|
||||
task = Task::run(stream, |result| match result {
|
||||
Ok(rdf_source) => Message::AddRdfSource(rdf_source),
|
||||
Err(err) => Message::ShowError(format!("Unable to fetch RDF Source: {err}")),
|
||||
}).chain(Task::done(Message::ConcludeTraversal));
|
||||
|
||||
self.traversal = Some(self.ontology.to_dataset());
|
||||
}
|
||||
Message::AddRdfSource(rdf_source) => {
|
||||
if let Some(traversal) = &mut self.traversal {
|
||||
traversal.extend(rdf_source.dataset());
|
||||
}
|
||||
}
|
||||
Message::ConcludeTraversal => {
|
||||
if let Some(traversal) = self.traversal.take() {
|
||||
let index_task = self.ontology
|
||||
.query_for_indexable_triples(&*language::ENGLISH_OR_UNTAGGED, Some(traversal));
|
||||
task = Task::perform(index_task, |task_result| {
|
||||
match task_result {
|
||||
Ok(results) => Message::IndexQueryResults(results),
|
||||
Err(err) => Message::ShowError(err.to_string()),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Message::IndexQueryResults(results) => {
|
||||
let mut writer = self.index.writer().expect("Unable to obtain index writer");
|
||||
let curie_helper = self.curie_helper.clone();
|
||||
task = Task::perform(tokio::task::spawn_blocking(move || {
|
||||
let span = debug_span!("Index Query Results", documents = field::Empty).entered();
|
||||
let mut counter = 0usize;
|
||||
for (individual, entry) in results {
|
||||
let mut document = doc!(
|
||||
Schema::type_field() => entry.category_id,
|
||||
Schema::iri_field() => individual.as_str(),
|
||||
);
|
||||
|
||||
if let Some(curie) = curie_helper.abbreviate(None, individual.as_str()) {
|
||||
document.add_text(Schema::curie_field(), curie);
|
||||
}
|
||||
|
||||
for (key, value) in entry.fields {
|
||||
document.add_text(Schema::field(&key, language::ENGLISH_PRIMARY), value.as_str());
|
||||
}
|
||||
writer.add_document(document).expect("Failed to add document to search index");
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
span.record("documents", counter);
|
||||
writer.commit()
|
||||
}), |result| {
|
||||
if let Err(err) = result {
|
||||
Message::ShowError(err.to_string())
|
||||
} else {
|
||||
Message::None
|
||||
}
|
||||
});
|
||||
}
|
||||
Message::WindowClosed(id) => {
|
||||
if self.window_id == id {
|
||||
task = iced::exit();
|
||||
@@ -355,9 +266,8 @@ impl Publisher {
|
||||
.map(|datatype| self.curie_helper.abbreviate(None, datatype.as_str())
|
||||
.unwrap_or(datatype.as_str().to_string()));
|
||||
|
||||
let datatype_state = combo_box::State::with_selection(
|
||||
let datatype_state = combo_box::State::new(
|
||||
self.abbreviated_datatypes.clone(),
|
||||
datatype.as_ref(),
|
||||
);
|
||||
let state = RowState {
|
||||
read_only,
|
||||
@@ -425,7 +335,7 @@ impl Publisher {
|
||||
|
||||
let query = new_query.clone();
|
||||
search_state.query = new_query;
|
||||
let results = self.index.query(category_id, query.as_str(), Schema::all_fields(), 10)
|
||||
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));
|
||||
};
|
||||
@@ -616,6 +526,17 @@ impl Publisher {
|
||||
Message::SetReadOnly(value) => {
|
||||
self.show_read_only = value;
|
||||
}
|
||||
Message::Event(Event::KeyPressed {
|
||||
key: keyboard::Key::Named(key::Named::Tab),
|
||||
modifiers,
|
||||
..
|
||||
}) => {
|
||||
if modifiers.shift() {
|
||||
task = operation::focus_previous();
|
||||
} else {
|
||||
task = operation::focus_next();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
task
|
||||
@@ -628,6 +549,7 @@ impl Publisher {
|
||||
pub(crate) fn subscription(&self) -> Subscription<Message> {
|
||||
Subscription::batch([
|
||||
window::close_events().map(Message::WindowClosed),
|
||||
keyboard::listen().map(Message::Event),
|
||||
])
|
||||
}
|
||||
|
||||
@@ -697,7 +619,7 @@ impl Publisher {
|
||||
// If the datatype is something, then it's not a named node, and we should use a plain
|
||||
// text_input as opposed to an iri_input.
|
||||
let object_input: Element<Message> = if term.datatype().is_some() {
|
||||
let base = text_input("Object", value.as_str());
|
||||
let base = text_input("Object", value.clone());
|
||||
if self.ontology.is_read_only(triple.as_ref()) {
|
||||
base.into()
|
||||
} else {
|
||||
@@ -734,9 +656,10 @@ impl Publisher {
|
||||
}).into()
|
||||
};
|
||||
|
||||
let language = term.language().unwrap_or("en").to_owned();
|
||||
let language_input = match term.datatype() {
|
||||
Some(rdf::LANG_STRING) | Some(rdf::DIR_LANG_STRING) => Some(container(
|
||||
text_input("Language", term.language().unwrap_or("en")).on_input(move |input| {
|
||||
text_input("Language", language).on_input(move |input| {
|
||||
let value = if input.is_empty() { None } else { Some(input) };
|
||||
Message::LanguageUpdated(key, value)
|
||||
}),
|
||||
@@ -848,7 +771,7 @@ impl Publisher {
|
||||
.and_then(|value| value.as_str())
|
||||
.unwrap_or_default();
|
||||
|
||||
let value = document.get_first(Schema::field(&field_name, 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();
|
||||
|
||||
@@ -877,8 +800,6 @@ impl Publisher {
|
||||
|
||||
let add_row_button = button("Add row").on_press(Message::AddRow(None));
|
||||
|
||||
let reindex_ontology_button = button("Rebuild index").on_press(Message::RebuildIndex);
|
||||
|
||||
let address_input = iri_input(&self.curie_helper, "URL", None, &self.url_input)
|
||||
.on_input(Message::URLInputChanged)
|
||||
.on_submit(Message::URLInputSubmitted)
|
||||
@@ -920,7 +841,6 @@ impl Publisher {
|
||||
|
||||
let content = navigation_area(column![
|
||||
row![
|
||||
reindex_ontology_button,
|
||||
add_row_button,
|
||||
back_button,
|
||||
forward_button,
|
||||
|
||||
Reference in New Issue
Block a user