|
@@ -1,8 +1,7 @@
|
|
|
# TODO Lot of hardcoded shizzle
|
|
|
import logging
|
|
|
-from dataclasses import dataclass, field
|
|
|
from itertools import groupby
|
|
|
-from typing import Optional, List
|
|
|
+from typing import Optional, List, Union
|
|
|
from urllib.error import URLError
|
|
|
|
|
|
import arklog
|
|
@@ -10,68 +9,12 @@ import dearpygui.dearpygui as dpg
|
|
|
import dearpygui.demo as demo
|
|
|
|
|
|
from graph_exploring_tool import query
|
|
|
+from graph_exploring_tool.query import QueryTemplate
|
|
|
|
|
|
arklog.set_config_logging()
|
|
|
|
|
|
-example_prefix = """PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
|
|
|
-PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
|
|
-PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
|
|
-PREFIX dtf: <https://ontology.rys.app/dt/function/>
|
|
|
-PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
|
|
-"""
|
|
|
-example_query = """SELECT ?outlier ?outlier_relation ?outlier_value WHERE {
|
|
|
- SERVICE <http://127.0.0.1:8000/> {
|
|
|
- SELECT ?outlier ?outlier_relation ?outlier_value WHERE {
|
|
|
- BIND(dtf:outlier("rotation.csv", "2", "<http://ua.be/drivetrain/description/artifacts/artifacts#drivetrain-sensor-data-v1>") AS ?outlier)
|
|
|
- }
|
|
|
- }
|
|
|
-}"""
|
|
|
-
|
|
|
-
|
|
|
-@dataclass(init=True, repr=True, order=False, frozen=True)
|
|
|
-class Replacement:
|
|
|
- origin: str
|
|
|
- description: str
|
|
|
-
|
|
|
-@dataclass(init=True, repr=True, order=False, frozen=True)
|
|
|
-class QueryTemplate:
|
|
|
- group: str
|
|
|
- name: str
|
|
|
- prefix: str
|
|
|
- query: str
|
|
|
- description: str
|
|
|
- visual_support: bool = False
|
|
|
- replacements: List[Replacement] = field(default_factory=list)
|
|
|
-
|
|
|
-
|
|
|
-# TODO Grab from config files?
|
|
|
-query_palette = (
|
|
|
- QueryTemplate(group="Types", name="Find Types", prefix=query.prefixes, query=query.get_types(), description="Find all the types stored in the knowledge graph.", visual_support=True),
|
|
|
- QueryTemplate(group="Service", name="Example Function", prefix=query.prefixes, query=query.get_example(), description="Example query calling the example function.", visual_support=True),
|
|
|
- QueryTemplate(group="Service", name="Outlier Function", prefix=query.prefixes, query=query.get_outlier(), description="Find an outlier in a tabular format.", visual_support=True, replacements=[
|
|
|
- Replacement(origin="http://127.0.0.1:8000/", description="Which service do you want to use?"),
|
|
|
- Replacement(origin="rotation.csv", description="In which file is the outlier located?"),
|
|
|
- Replacement(origin="2222", description="In which column?"),
|
|
|
- Replacement(origin="<http://ua.be/drivetrain/description/artifacts/artifacts#drivetrain-sensor-data-v1>", description="In which artifact?"),
|
|
|
- ]),
|
|
|
- QueryTemplate(group="Traceability", name="Find Versions", prefix=query.prefixes, query=query.get_versions(), description="Find all the older versions of an artifact.", visual_support=True, replacements=[Replacement(origin="art:drivetrain-sensor-data-v2", description="For which artifact are you looking for older versions?")]),
|
|
|
- QueryTemplate(group="Individuals", name="Find Properties", prefix=query.prefixes, query=query.get_properties(), description="Find all possible properties of an individual.", visual_support=True, replacements=[Replacement(origin="ftg:Formalism", description="What class of individual are you looking for?")]),
|
|
|
- QueryTemplate(group="Individuals", name="Find Individuals", prefix=query.prefixes, query=query.get_individuals(), description="Find all individuals.", visual_support=True, replacements=[Replacement(origin="ftg:Formalism", description="What class of individual are you looking for?"), Replacement(origin="base:hasName", description="What is the relation you are looking for?")]),
|
|
|
- QueryTemplate(group="Traceability", name="Find Class Property", prefix=query.prefixes, query=query.get_class_property(), description="Find all the properties for a class.", visual_support=True, replacements=[Replacement(origin="base:ArtifactType", description="For which class do you want to find properties?")]),
|
|
|
- QueryTemplate(group="Traceability", name="Match Artifact Formalism", prefix=query.prefixes, query=query.get_art_formalism(), description="Find the formalism corresponding to an artifact.", visual_support=True, replacements=[
|
|
|
- Replacement(origin="art:torque-profile", description="For which artifact do you want to find formalism?")
|
|
|
- ]),
|
|
|
- QueryTemplate(group="Traceability", name="Find PM Relation", prefix=query.prefixes, query=query.get_pm(), description="Find the PM.", visual_support=True, replacements=[
|
|
|
- Replacement(origin="ftg:Transformation", description="This should be a transformation?"),
|
|
|
- Replacement(origin="ftg:outputs", description="This should be a relation from the transformation?"),
|
|
|
- Replacement(origin="ftg:Formalism", description="The class of the formalism?"),
|
|
|
- Replacement(origin="base:hasName", description="Relation from formalism?"),
|
|
|
- ]),
|
|
|
-)
|
|
|
-
|
|
|
|
|
|
def _config(sender, keyword, user_data):
|
|
|
-
|
|
|
widget_type = dpg.get_item_type(sender)
|
|
|
items = user_data
|
|
|
|
|
@@ -101,7 +44,7 @@ def add_main_menu():
|
|
|
|
|
|
|
|
|
# TODO Add tab for prefixes
|
|
|
-def create_query_palette():
|
|
|
+def create_query_palette(query_palette: List[QueryTemplate]):
|
|
|
demo_layout_child = dpg.generate_uuid()
|
|
|
with dpg.child_window(tag=demo_layout_child, label="Query Palette", width=220, menubar=True):
|
|
|
with dpg.menu_bar():
|
|
@@ -136,7 +79,9 @@ def create_query_options(endpoint: str):
|
|
|
dpg.add_checkbox(label="debug", callback=_config)
|
|
|
dpg.add_checkbox(label="annotate", default_value=False, callback=_config) # TODO Actually make this annotate the result data with its type
|
|
|
|
|
|
-def create_query_editor_visual(show: bool = False):
|
|
|
+# TODO Make the elements color coded etc...
|
|
|
+# TODO Fix context menu and keyboard operations
|
|
|
+def create_query_editor_visual(example_prefix:str, example_query:str, show: bool = False):
|
|
|
with dpg.child_window(autosize_x=True, height=500, menubar=True, show=show, tag="__query_editor_visual"):
|
|
|
with dpg.menu_bar():
|
|
|
dpg.add_menu(label="Visual Query Editor", enabled=False)
|
|
@@ -146,13 +91,16 @@ def create_query_editor_visual(show: bool = False):
|
|
|
with dpg.tab(label="Prefix", tag="__prefix_tab"):
|
|
|
dpg.add_input_text(default_value=example_prefix, callback=_log, multiline=True, on_enter=True, height=300, width=-1, tag="__prefix_editor_visual_input")
|
|
|
with dpg.group(tag="__visual_editor_fields"):
|
|
|
+ # TODO Make more clear which placeholder is getting replaced (Maybe do it interactively, replace as user changes)
|
|
|
pass
|
|
|
with dpg.group(horizontal=True):
|
|
|
dpg.add_button(label="Query", callback=_perform_query)
|
|
|
dpg.add_button(label="Save", callback=_select_directory) # TODO
|
|
|
dpg.add_button(label="Load") # TODO
|
|
|
|
|
|
-def create_query_editor_textual(show: bool = False):
|
|
|
+# TODO Maybe remove/change this option, we made all the queries mostly 'visual'
|
|
|
+# It's practically a duplicate at this point
|
|
|
+def create_query_editor_textual(example_prefix:str, example_query:str, show: bool = False):
|
|
|
with dpg.child_window(autosize_x=True, height=500, menubar=True, show=show, tag="__query_editor_textual"):
|
|
|
with dpg.menu_bar():
|
|
|
dpg.add_menu(label="Textual Query Editor", enabled=False)
|
|
@@ -166,18 +114,18 @@ def create_query_editor_textual(show: bool = False):
|
|
|
dpg.add_button(label="Save", callback=_select_directory) # TODO
|
|
|
dpg.add_button(label="Load") # TODO
|
|
|
|
|
|
-# TODO Not at the bottom because fok you
|
|
|
+# TODO Not at the bottom because fok getting that layout to fit correctly
|
|
|
def create_status_console():
|
|
|
with dpg.child_window(autosize_x=True, height=35):
|
|
|
with dpg.group(horizontal=True):
|
|
|
dpg.add_text(default_value="Ready.", tag="__status_console")
|
|
|
|
|
|
-def set_copy(s, a):
|
|
|
- dpg.set_value(s, shorten(a))
|
|
|
- i = dpg.get_item_label(s)
|
|
|
- dpg.set_value(f"__copy_{i}", shorten(a))
|
|
|
- dpg.configure_item(f"__copy_drag_payload_{i}", drag_data=shorten(a))
|
|
|
- dpg.set_value(f"__copy_drag_{i}", shorten(a))
|
|
|
+def set_copy(element: Union[int, str], text_data:str):
|
|
|
+ dpg.set_value(element, shorten(text_data))
|
|
|
+ i = dpg.get_item_label(element)
|
|
|
+ dpg.set_value(f"__copy_{i}", shorten(text_data))
|
|
|
+ dpg.configure_item(f"__copy_drag_payload_{i}", drag_data=shorten(text_data))
|
|
|
+ dpg.set_value(f"__copy_drag_{i}", shorten(text_data))
|
|
|
|
|
|
def create_query_results():
|
|
|
with dpg.child_window(autosize_x=True, autosize_y=True, menubar=True, tag="__query_results_window"):
|
|
@@ -201,8 +149,6 @@ def create_query_results():
|
|
|
dpg.add_text(tag=f"__copy_{i}", default_value="Empty")
|
|
|
with dpg.drag_payload(parent=dpg.last_item(), drag_data="Empty", payload_type="string", tag=f"__copy_drag_payload_{i}"):
|
|
|
dpg.add_text(tag=f"__copy_drag_{i}", default_value="Empty")
|
|
|
-
|
|
|
- # dpg.add_text("TODO") # TODO Add ability to save some results for reuse in templates
|
|
|
with dpg.tab(label="Debug"):
|
|
|
dpg.add_text("This is the debug tab!")
|
|
|
|
|
@@ -236,11 +182,11 @@ def _query_palette_click(sender: int, mode: str, user_data: Optional[QueryTempla
|
|
|
dpg.set_value(f"__query_editor_{mode}_input", user_data.query)
|
|
|
dpg.delete_item("__visual_editor_fields", children_only=True)
|
|
|
if mode == "visual" and user_data.visual_support:
|
|
|
- # TODO set visual components
|
|
|
for replacement in user_data.replacements:
|
|
|
- dpg.add_input_text(label=f"{replacement.description}",default_value=replacement.origin, payload_type="string", width=500, parent="__visual_editor_fields", drop_callback=lambda s, a: dpg.set_value(s, shorten(a)), tag=f"__{replacement.origin}", user_data=replacement)
|
|
|
+ dpg.add_input_text(label=f"{replacement.description}",default_value=replacement.suggestion, payload_type="string", width=500, parent="__visual_editor_fields", drop_callback=lambda s, a: dpg.set_value(s, shorten(a)), tag=f"__{replacement.suggestion}", user_data=replacement)
|
|
|
|
|
|
def _perform_query(sender: int, mode: str, user_data: Optional[dict]):
|
|
|
+ # TODO Fix for new query structure
|
|
|
mode = dpg.get_value("__editor_selector").lower().strip()
|
|
|
prefix_text = dpg.get_value(f"__prefix_editor_{mode}_input")
|
|
|
query_text = dpg.get_value(f"__query_editor_{mode}_input")
|
|
@@ -249,8 +195,8 @@ def _perform_query(sender: int, mode: str, user_data: Optional[dict]):
|
|
|
if mode=="visual":
|
|
|
for replacement_field in dpg.get_item_children("__visual_editor_fields", 1):
|
|
|
value = dpg.get_value(replacement_field)
|
|
|
- origin = dpg.get_item_user_data(replacement_field).origin
|
|
|
- query_text = query_text.replace(origin, value)
|
|
|
+ placeholder = dpg.get_item_user_data(replacement_field).placeholder
|
|
|
+ query_text = query_text.replace(f"{{{{ {placeholder} }}}}", value)
|
|
|
query_result = query.perform_query(endpoint, prefix_text + "\n" + query_text)
|
|
|
except URLError as e:
|
|
|
logging.error(f"Connection to '{endpoint}' failed.")
|
|
@@ -268,7 +214,6 @@ def _perform_query(sender: int, mode: str, user_data: Optional[dict]):
|
|
|
for column in columns:
|
|
|
dpg.add_table_column(label=column, width_fixed=True, parent="__result_table")
|
|
|
# dpg.add_table_column(label="CCC", width_stretch=True, init_width_or_weight=0.0)
|
|
|
-
|
|
|
# TODO This is as brittle as my ego, needs a fix asap
|
|
|
# TODO Fix filter
|
|
|
# with dpg.filter_set(tag="__result_filter", parent="__query_result_tab"):
|
|
@@ -297,18 +242,17 @@ def _select_file(sender: int, app_data: str, user_data: Optional[dict]):
|
|
|
selected_file = cwd + "/" + selected_file
|
|
|
dpg.set_value("file_info_n", "file :" + selected_file)
|
|
|
|
|
|
-def interface(width=1200, height=900, endpoint: str = "localhost"):
|
|
|
- endpoint_middleware = "localhost:8000" # TODO Grab this from onto
|
|
|
+def interface(example_prefix: str, example_query: str, palette: List[QueryTemplate], endpoint: str, width=1200, height=900):
|
|
|
dpg.create_context()
|
|
|
dpg.create_viewport(title="Graph Exploring Tool", width=width, height=height)
|
|
|
with dpg.window(tag="primary", label="Graph Exploring Tool", menubar=True):
|
|
|
add_main_menu()
|
|
|
with dpg.group(horizontal=True, label="Main"):
|
|
|
- create_query_palette()
|
|
|
+ create_query_palette(palette)
|
|
|
with dpg.group(horizontal=False):
|
|
|
create_query_options(endpoint)
|
|
|
- create_query_editor_visual(show=True)
|
|
|
- create_query_editor_textual(show=False)
|
|
|
+ create_query_editor_visual(example_prefix, example_query, show=True)
|
|
|
+ create_query_editor_textual(example_prefix, example_query, show=False)
|
|
|
create_status_console()
|
|
|
create_query_results()
|
|
|
# demo.show_demo()
|