Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse stored config details to script-based visualizations #18651

Merged
merged 14 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
# -*- coding: utf-8 -*-
<%inherit file="visualization_base.mako"/>

## No stylesheets
<%def name="stylesheets()"></%def>
## No javascript libraries
<%def name="late_javascripts()">
<% tag_attrs = ' '.join([ '{0}="{1}"'.format( key, attr ) for key, attr in script_attributes.items() ]) %>
<script type="text/javascript" ${tag_attrs}></script>
## Add stylesheet
<%def name="stylesheets()">
<% script_css = script_attributes.get("css") %>
%if script_css is not None:
<% script_css = script_css if h.is_url(script_css) else f"{static_url}{script_css}" %>
<link rel="stylesheet" href="${script_css}">
%endif
</%def>

## Create a container, attach data and import script file
<%def name="get_body()">
## Collect incoming data
<%
from markupsafe import escape
data_incoming = {
"root": h.url_for("/"),
"visualization_id": visualization_id,
"visualization_name": visualization_name,
"visualization_plugin": visualization_plugin,
"visualization_title": escape(title),
"visualization_config": config }
%>
## Create a container with default identifier `app`
<% container = script_attributes.get("container") or "app" %>
<div id="${container}" data-incoming='${h.dumps(data_incoming)}'></div>
## Add script tag
<% script_src = script_attributes.get("src") %>
<% script_src = script_src if h.is_url(script_src) else f"{static_url}{script_src}" %>
<% script_type = script_attributes.get("type") or "module" %>
<script type="${script_type}" src="${script_src}"></script>
</%def>
38 changes: 13 additions & 25 deletions config/plugins/visualizations/example/config/example.xml
Original file line number Diff line number Diff line change
@@ -1,45 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE visualization SYSTEM "../../visualization.dtd">
<visualization name="Example" embeddable="false">
<description>This is a developer example which demonstrates how to implement and configure a basic d3-based plugin for charts.</description>
<visualization name="Minimal Example" embeddable="false">
<description>Welcome to the Minimal JS-Based Example Plugin.</description>
<data_sources>
<data_source>
<model_class>HistoryDatasetAssociation</model_class>
<test type="isinstance" test_attr="datatype" result_type="datatype">tabular.Tabular</test>
<test type="isinstance" test_attr="datatype" result_type="datatype">tabular.CSV</test>
<to_param param_attr="id">dataset_id</to_param>
</data_source>
</data_sources>
<params>
<param type="dataset" var_name_in_template="hda" required="true">dataset_id</param>
</params>
<entry_point entry_point_type="chart" src="script.js"/>
<entry_point entry_point_type="script" src="script.js" />
<settings>
<input>
<name>data_dialog</name>
<label>Some data selector</label>
<type>data_dialog</type>
<multiple>false</multiple>
<name>setting_input</name>
<help>setting help</help>
<type>setting_type</type>
</input>
</settings>
<groups>
<input>
<name>x</name>
<label>Bubble x-position</label>
<type>data_column</type>
<is_numeric>true</is_numeric>
</input>
<input>
<name>y</name>
<label>Bubbles y-position</label>
<type>data_column</type>
<is_numeric>true</is_numeric>
</input>
<input>
<name>z</name>
<label>Bubble size</label>
<type>data_column</type>
<is_numeric>true</is_numeric>
<name>group_input</name>
<help>group help</help>
<type>group_type</type>
</input>
</groups>
</visualization>
<specs>
<spec_name>spec_value</spec_name>
</specs>
</visualization>
24 changes: 0 additions & 24 deletions config/plugins/visualizations/example/package.json

This file was deleted.

54 changes: 0 additions & 54 deletions config/plugins/visualizations/example/src/script.js

This file was deleted.

33 changes: 33 additions & 0 deletions config/plugins/visualizations/example/static/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const { visualization_config, visualization_plugin, root } = JSON.parse(document.getElementById("app").dataset.incoming);

const div = Object.assign(document.createElement("div"), {
style: "border: 2px solid #25537b; border-radius: 1rem; padding: 1rem"
});

const img = Object.assign(document.createElement("img"), {
src: root + visualization_plugin.logo,
style: "height: 3rem"
});
div.appendChild(img);

Object.entries(visualization_plugin).forEach(([key, value]) => {
const row = document.createElement("div");
const spanKey = Object.assign(document.createElement("span"), {
innerText: `${key}: `,
style: "font-weight: bold"
});
const spanValue = Object.assign(document.createElement("span"), {
innerText: JSON.stringify(value)
});
row.appendChild(spanKey);
row.appendChild(spanValue);
div.appendChild(row);
});

const dataset = Object.assign(document.createElement("div"), {
innerText: `You have selected dataset: ${visualization_config.dataset_id}.`,
style: "font-weight: bold; padding-top: 1rem;"
});
div.appendChild(dataset);

document.body.appendChild(div);
13 changes: 11 additions & 2 deletions lib/galaxy/app_unittest_utils/galaxy_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,8 +430,17 @@ def remove(self):


class MockTemplateHelpers:
def js(*js_files):
def css(*css_files):
pass

def css(*css_files):
def dumps(*kwargs):
return {}

def js(*js_files):
pass

def is_url(*kwargs):
return True

def url_for(*kwargs):
return "/"
2 changes: 1 addition & 1 deletion lib/galaxy/visualization/plugins/config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def parse(self, xml_tree):
# when no tests are given, default to isinstance( object, model_class )
returned["tests"] = self.parse_tests(xml_tree.findall("test"))

# to_params (optional, 0 or more) - tells the registry to set certain params based on the model_clas, tests
# to_params (optional, 0 or more) - tells the registry to set certain params based on the model_class, tests
returned["to_params"] = {}
if to_params := self.parse_to_params(xml_tree.findall("to_param")):
returned["to_params"] = to_params
Expand Down
2 changes: 1 addition & 1 deletion lib/galaxy/visualization/plugins/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def _build_render_vars(self, config: Dict[str, Any], trans=None, **kwargs) -> Di
render_vars.update(
visualization_name=self.name,
visualization_display_name=self.config["name"],
title=kwargs.get("title", None),
title=kwargs.get("title", "Unnamed Visualization"),
saved_visualization=None,
visualization_id=None,
visualization_plugin=self.to_dict(),
Expand Down
17 changes: 17 additions & 0 deletions lib/galaxy/web/framework/helpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
GalaxyWebTransaction in galaxy/webapps/base/webapp.py
"""

import re
from datetime import (
datetime,
timedelta,
Expand Down Expand Up @@ -105,6 +106,22 @@ def is_true(val):
return val is True or val in ["True", "true", "T", "t"]


def is_url(val):
"""
Regular expression to match common URL protocols
>>> assert is_url(None) == False
>>> assert is_url("is_url") == False
>>> assert is_url("http://is_url") == True
>>> assert is_url("https://is_url") == True
"""
if val is not None:
url_pattern = re.compile(r"^(https?:\/\/|ftp:\/\/)")
return bool(url_pattern.match(val))
else:
return False


def to_js_bool(val):
"""
Prints javascript boolean for passed value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def test_build_render_vars_default(self):
render_vars = plugin._build_render_vars(config)
assert render_vars["visualization_name"] == plugin.name
assert render_vars["visualization_display_name"] == plugin.config["name"]
assert render_vars["title"] is None
assert render_vars["title"] == "Unnamed Visualization"
assert render_vars["saved_visualization"] is None
assert render_vars["visualization_id"] is None
assert render_vars["query"] == {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

glx_dir = galaxy_directory()
template_cache_dir = os.path.join(glx_dir, "database", "compiled_templates")
addtional_templates_dir = os.path.join(glx_dir, "config", "plugins", "visualizations", "common", "templates")
additional_templates_dir = os.path.join(glx_dir, "config", "plugins", "visualizations", "common", "templates")
vis_reg_path = "config/plugins/visualizations"

config1 = """\
Expand Down Expand Up @@ -144,7 +144,7 @@ def test_script_entry(self):
<model_class>HistoryDatasetAssociation</model_class>
</data_source>
</data_sources>
<entry_point entry_point_type="script" data-main="one" src="bler"></entry_point>
<entry_point entry_point_type="script" container="mycontainer" src="mysrc" css="mycss"></entry_point>
</visualization>
"""
)
Expand All @@ -167,11 +167,11 @@ def test_script_entry(self):
assert script_entry.serves_templates

trans = galaxy_mock.MockTrans()
script_entry._set_up_template_plugin(mock_app_dir.root_path, [addtional_templates_dir])
response = script_entry._render({}, trans=trans, embedded=True)
assert 'src="bler"' in response
assert 'type="text/javascript"' in response
assert 'data-main="one"' in response
script_entry._set_up_template_plugin(mock_app_dir.root_path, [additional_templates_dir])
response = script_entry.render(trans=trans, embedded=True)
assert '<script type="module" src="mysrc">' in response
assert '<link rel="stylesheet" href="mycss">' in response
assert "<div id=\"mycontainer\" data-incoming='{}'></div>" in response
mock_app_dir.remove()


Expand Down
Loading