summaryrefslogtreecommitdiff
path: root/src/hydrilla/proxy
diff options
context:
space:
mode:
authorWojtek Kosior <koszko@koszko.org>2022-09-29 12:52:54 +0200
committerWojtek Kosior <koszko@koszko.org>2022-10-04 21:45:11 +0200
commit48f80ae480e2fc0eabbdb5041e841b80c0f788f4 (patch)
treecda20c09831038d4b0c3ae78679b43dc127950be /src/hydrilla/proxy
parentb0fcc865599cfdc87e2ca8a637df8f5b336bb459 (diff)
downloadhaketilo-hydrilla-48f80ae480e2fc0eabbdb5041e841b80c0f788f4.tar.gz
haketilo-hydrilla-48f80ae480e2fc0eabbdb5041e841b80c0f788f4.zip
[proxy] display some more details in mapping/resource version view in the web UI
Diffstat (limited to 'src/hydrilla/proxy')
-rw-r--r--src/hydrilla/proxy/policies/payload_resource.py2
-rw-r--r--src/hydrilla/proxy/state.py58
-rw-r--r--src/hydrilla/proxy/state_impl/items.py209
-rw-r--r--src/hydrilla/proxy/state_impl/payloads.py2
-rw-r--r--src/hydrilla/proxy/web_ui/items.py129
-rw-r--r--src/hydrilla/proxy/web_ui/templates/include/item_list_style.css.jinja18
-rw-r--r--src/hydrilla/proxy/web_ui/templates/items/item_view.html.jinja6
-rw-r--r--src/hydrilla/proxy/web_ui/templates/items/item_viewversion.html.jinja108
-rw-r--r--src/hydrilla/proxy/web_ui/templates/items/libraries.html.jinja4
-rw-r--r--src/hydrilla/proxy/web_ui/templates/items/library_viewversion.html.jinja32
-rw-r--r--src/hydrilla/proxy/web_ui/templates/items/package_viewversion.html.jinja54
-rw-r--r--src/hydrilla/proxy/web_ui/templates/items/packages.html.jinja4
-rw-r--r--src/hydrilla/proxy/web_ui/templates/repos/index.html.jinja2
-rw-r--r--src/hydrilla/proxy/web_ui/templates/rules/index.html.jinja2
14 files changed, 589 insertions, 41 deletions
diff --git a/src/hydrilla/proxy/policies/payload_resource.py b/src/hydrilla/proxy/policies/payload_resource.py
index 3872037..30b28f2 100644
--- a/src/hydrilla/proxy/policies/payload_resource.py
+++ b/src/hydrilla/proxy/policies/payload_resource.py
@@ -91,7 +91,7 @@ class PayloadResourcePolicy(PayloadAwarePolicy):
return http_messages.ProducedResponse(
200,
- ((b'Content-Type', file_data.type.encode()),),
+ ((b'Content-Type', file_data.mime_type.encode()),),
file_data.contents
)
diff --git a/src/hydrilla/proxy/state.py b/src/hydrilla/proxy/state.py
index 559a546..4142f7f 100644
--- a/src/hydrilla/proxy/state.py
+++ b/src/hydrilla/proxy/state.py
@@ -259,6 +259,13 @@ class RepoIterationRef(Ref):
@dc.dataclass(frozen=True)
+class FileData:
+ mime_type: str
+ name: str
+ contents: bytes
+
+
+@dc.dataclass(frozen=True)
class MappingDisplayInfo(item_infos.CorrespondsToMappingDCMixin):
ref: 'MappingRef'
identifier: str
@@ -300,6 +307,10 @@ class MappingStore(Store[MappingRef]):
def get_display_infos(self) -> t.Sequence[MappingDisplayInfo]:
...
+ @abstractmethod
+ def get_by_identifier(self, identifier: str) -> MappingRef:
+ ...
+
@dc.dataclass(frozen=True, unsafe_hash=True) # type: ignore[misc]
class MappingVersionRef(Ref, item_infos.CorrespondsToMappingDCMixin):
@abstractmethod
@@ -323,6 +334,23 @@ class MappingVersionRef(Ref, item_infos.CorrespondsToMappingDCMixin):
...
@abstractmethod
+ def get_license_file(self, name: str) -> FileData:
+ ...
+
+ @abstractmethod
+ def get_upstream_license_file_url(self, name: str) -> str:
+ ...
+
+ @abstractmethod
+ def get_required_mapping(self, identifier: str) -> 'MappingVersionRef':
+ ...
+
+ @abstractmethod
+ def get_payload_resource(self, pattern: str, identifier: str) \
+ -> 'ResourceVersionRef':
+ ...
+
+ @abstractmethod
def get_item_display_info(self) -> RichMappingDisplayInfo:
...
@@ -359,6 +387,10 @@ class ResourceStore(Store[ResourceRef]):
def get_display_infos(self) -> t.Sequence[ResourceDisplayInfo]:
...
+ @abstractmethod
+ def get_by_identifier(self, identifier: str) -> ResourceRef:
+ ...
+
@dc.dataclass(frozen=True, unsafe_hash=True) # type: ignore[misc]
class ResourceVersionRef(Ref, item_infos.CorrespondsToResourceDCMixin):
@@ -371,6 +403,26 @@ class ResourceVersionRef(Ref, item_infos.CorrespondsToResourceDCMixin):
...
@abstractmethod
+ def get_license_file(self, name: str) -> FileData:
+ ...
+
+ @abstractmethod
+ def get_resource_file(self, name: str) -> FileData:
+ ...
+
+ @abstractmethod
+ def get_upstream_license_file_url(self, name: str) -> str:
+ ...
+
+ @abstractmethod
+ def get_upstream_resource_file_url(self, name: str) -> str:
+ ...
+
+ @abstractmethod
+ def get_dependency(self, identifier: str) -> ResourceVersionRef:
+ ...
+
+ @abstractmethod
def get_item_display_info(self) -> RichResourceDisplayInfo:
...
@@ -409,12 +461,6 @@ class PayloadDisplayInfo:
pattern: str
has_problems: bool
-@dc.dataclass(frozen=True)
-class FileData:
- type: str
- name: str
- contents: bytes
-
@dc.dataclass(frozen=True, unsafe_hash=True) # type: ignore[misc]
class PayloadRef(Ref):
"""...."""
diff --git a/src/hydrilla/proxy/state_impl/items.py b/src/hydrilla/proxy/state_impl/items.py
index d312db9..010b8ca 100644
--- a/src/hydrilla/proxy/state_impl/items.py
+++ b/src/hydrilla/proxy/state_impl/items.py
@@ -39,12 +39,30 @@ import typing as t
import dataclasses as dc
from contextlib import contextmanager
+from urllib.parse import urljoin
from ... import item_infos
from .. import state as st
from . import base
+def _get_item_id(cursor: sqlite3.Cursor, item_type: str, identifier: str) \
+ -> str:
+ cursor.execute(
+ 'SELECT item_id FROM items WHERE identifier = ? AND type = ?;',
+ (identifier, item_type)
+ )
+
+ rows = cursor.fetchall()
+
+ if rows == []:
+ raise st.MissingItemError()
+
+ (item_id,), = rows
+
+ return str(item_id)
+
+
def _get_parent_item_id(cursor: sqlite3.Cursor, version_id: str) -> str:
cursor.execute(
'''
@@ -66,6 +84,7 @@ def _get_parent_item_id(cursor: sqlite3.Cursor, version_id: str) -> str:
return str(item_id)
+
def _set_installed_status(cursor: sqlite3.Cursor, id: str, new_status: str) \
-> None:
cursor.execute(
@@ -138,6 +157,71 @@ def _uninstall_version(ref: VersionRefVar) -> t.Optional[VersionRefVar]:
return ref if version_still_present else None
+def _get_file(ref: VersionRefVar, name: str, file_type: str = 'L') \
+ -> st.FileData:
+ with ref.state.cursor() as cursor:
+ cursor.execute(
+ '''
+ SELECT
+ f.data, fu.mime_type
+ FROM
+ item_versions AS iv
+ JOIN items AS i USING (item_id)
+ JOIN file_uses AS fu USING (item_version_id)
+ JOIN files AS f USING (file_id)
+ WHERE
+ (iv.item_version_id = ? AND iv.installed = 'I') AND
+ i.type = ? AND
+ (fu.name = ? AND fu.type = ?) AND
+ f.data IS NOT NULL;
+ ''',
+ (ref.id, ref.type.value[0].upper(), name, file_type)
+ )
+
+ rows = cursor.fetchall()
+
+ if rows == []:
+ raise st.MissingItemError()
+
+ (data, mime_type), = rows
+
+ return st.FileData(mime_type, name, data)
+
+
+def _get_upstream_file_url(
+ ref: VersionRefVar,
+ name: str,
+ file_type: str = 'L'
+) -> str:
+ with ref.state.cursor() as cursor:
+ cursor.execute(
+ '''
+ SELECT
+ f.sha256, r.url
+ FROM
+ item_versions AS iv
+ JOIN repo_iterations AS ri USING(repo_iteration_id)
+ JOIN repos AS r USING(repo_id)
+ JOIN file_uses AS fu USING(item_version_id)
+ JOIN files AS f USING(file_id)
+ WHERE
+ iv.item_version_id = ? AND
+ (fu.name = ? AND fu.type = ?) AND
+ r.url IS NOT NULL;
+ ''',
+ (ref.id, name, file_type)
+ )
+
+ rows = cursor.fetchall()
+
+ if rows == []:
+ raise st.MissingItemError()
+
+ (sha256, repo_url), = rows
+
+ return urljoin(repo_url, f'file/sha256/{sha256}')
+
+
@dc.dataclass(frozen=True, unsafe_hash=True)
class ConcreteMappingRef(st.MappingRef):
state: base.HaketiloStateWithFields = dc.field(hash=False, compare=False)
@@ -405,6 +489,12 @@ class ConcreteMappingStore(st.MappingStore):
return sorted(result, key=(lambda di: di.identifier))
+ def get_by_identifier(self, identifier: str) -> st.MappingRef:
+ with self.state.cursor() as cursor:
+ item_id = _get_item_id(cursor, 'M', identifier)
+
+ return ConcreteMappingRef(item_id, self.state)
+
@dc.dataclass(frozen=True, unsafe_hash=True)
class ConcreteMappingVersionRef(st.MappingVersionRef):
@@ -472,6 +562,76 @@ class ConcreteMappingVersionRef(st.MappingVersionRef):
mapping_ref.update_status(enabled, frozen, id_to_pass)
+ def get_license_file(self, name: str) -> st.FileData:
+ return _get_file(self, name, 'L')
+
+ def get_upstream_license_file_url(self, name: str) -> str:
+ return _get_upstream_file_url(self, name, 'L')
+
+ def get_required_mapping(self, identifier: str) \
+ -> 'ConcreteMappingVersionRef':
+ with self.state.cursor() as cursor:
+ cursor.execute(
+ '''
+ SELECT
+ iv2.item_version_id
+ FROM
+ item_versions AS iv1
+ JOIN resolved_required_mappings AS rrm
+ ON iv1.item_version_id =
+ rrm.requiring_mapping_id
+ JOIN item_versions AS iv2
+ ON rrm.required_mapping_id =
+ iv2.item_version_id
+ JOIN items AS i
+ ON iv2.item_id = i.item_id
+ WHERE
+ iv1.item_version_id = ? AND
+ i.identifier = ?;
+ ''',
+ (self.id, identifier)
+ )
+
+ rows = cursor.fetchall()
+
+ if rows == []:
+ raise st.MissingItemError()
+
+ (required_id,), = rows
+
+ return ConcreteMappingVersionRef(str(required_id), self.state)
+
+ def get_payload_resource(self, pattern: str, identifier: str) \
+ -> 'ConcreteResourceVersionRef':
+ with self.state.cursor() as cursor:
+ cursor.execute(
+ '''
+ SELECT
+ iv.item_version_id
+ FROM
+ payloads AS p
+ JOIN resolved_depended_resources AS rdd
+ USING(payload_id)
+ JOIN item_versions AS iv
+ ON rdd.resource_item_id = iv.item_version_id
+ JOIN items AS i
+ USING (item_id)
+ WHERE
+ (p.mapping_item_id = ? AND p.pattern = ?) AND
+ i.identifier = ?;
+ ''',
+ (self.id, pattern, identifier)
+ )
+
+ rows = cursor.fetchall()
+
+ if rows == []:
+ raise st.MissingItemError()
+
+ (resource_ver_id,), = rows
+
+ return ConcreteResourceVersionRef(str(resource_ver_id), self.state)
+
def get_item_display_info(self) -> st.RichMappingDisplayInfo:
with self._mapping_ref() as mapping_ref:
return mapping_ref.get_display_info()
@@ -578,6 +738,12 @@ class ConcreteResourceStore(st.ResourceStore):
return sorted(result, key=(lambda di: di.identifier))
+ def get_by_identifier(self, identifier: str) -> st.ResourceRef:
+ with self.state.cursor() as cursor:
+ item_id = _get_item_id(cursor, 'R', identifier)
+
+ return ConcreteResourceRef(item_id, self.state)
+
@dc.dataclass(frozen=True, unsafe_hash=True)
class ConcreteResourceVersionRef(st.ResourceVersionRef):
@@ -589,6 +755,49 @@ class ConcreteResourceVersionRef(st.ResourceVersionRef):
def uninstall(self) -> t.Optional['ConcreteResourceVersionRef']:
return _uninstall_version(self)
+ def get_license_file(self, name: str) -> st.FileData:
+ return _get_file(self, name, 'L')
+
+ def get_resource_file(self, name: str) -> st.FileData:
+ return _get_file(self, name, 'W')
+
+ def get_upstream_license_file_url(self, name: str) -> str:
+ return _get_upstream_file_url(self, name, 'L')
+
+ def get_upstream_resource_file_url(self, name: str) -> str:
+ return _get_upstream_file_url(self, name, 'W')
+
+ def get_dependency(self, identifier: str) -> st.ResourceVersionRef:
+ with self.state.cursor() as cursor:
+ cursor.execute(
+ '''
+ SELECT
+ iv.item_version_id
+ FROM
+ resolved_depended_resources AS rdd1
+ JOIN payloads AS p
+ ON rdd1.payload_id = p.payload_id
+ JOIN resolved_depended_resources AS rdd2
+ ON p.payload_id = rdd2.payload_id
+ JOIN item_versions AS iv
+ ON rdd2.resource_item_id = iv.item_version_id
+ JOIN items AS i
+ USING (item_id)
+ WHERE
+ rdd1.resource_item_id = ? AND i.identifier = ?;
+ ''',
+ (self.id, identifier)
+ )
+
+ rows = cursor.fetchall()
+
+ if rows == []:
+ raise st.MissingItemError()
+
+ (dep_id,), = rows
+
+ return ConcreteResourceVersionRef(str(dep_id), self.state)
+
def get_item_display_info(self) -> st.RichResourceDisplayInfo:
with self.state.cursor() as cursor:
resource_id = _get_parent_item_id(cursor, self.id)
diff --git a/src/hydrilla/proxy/state_impl/payloads.py b/src/hydrilla/proxy/state_impl/payloads.py
index 74b8121..ebc7152 100644
--- a/src/hydrilla/proxy/state_impl/payloads.py
+++ b/src/hydrilla/proxy/state_impl/payloads.py
@@ -264,7 +264,7 @@ class ConcretePayloadRef(st.PayloadRef):
(data, mime_type), = result
- return st.FileData(type=mime_type, name=file_name, contents=data)
+ return st.FileData(mime_type=mime_type, name=file_name, contents=data)
@dc.dataclass(frozen=True)
diff --git a/src/hydrilla/proxy/web_ui/items.py b/src/hydrilla/proxy/web_ui/items.py
index f34b89b..467be2f 100644
--- a/src/hydrilla/proxy/web_ui/items.py
+++ b/src/hydrilla/proxy/web_ui/items.py
@@ -34,6 +34,8 @@ from __future__ import annotations
import typing as t
+from urllib.parse import unquote
+
import flask
import werkzeug
@@ -231,3 +233,130 @@ def alter_library_version(item_version_id: str) -> werkzeug.Response:
@bp.route('/packages/viewversion/<string:item_version_id>', methods=['POST'])
def alter_package_version(item_version_id: str) -> werkzeug.Response:
return alter_item_version(item_version_id, item_infos.ItemType.MAPPING)
+
+def show_file(
+ item_version_id: str,
+ item_type: item_infos.ItemType,
+ file_type: str,
+ name: str,
+) -> werkzeug.Response:
+ if file_type not in ('license', 'web_resource'):
+ flask.abort(404)
+
+ try:
+ store = item_version_store(_app.get_haketilo_state(), item_type)
+ item_version_ref = store.get(item_version_id)
+
+ try:
+ if file_type == 'license':
+ file_data = item_version_ref.get_license_file(name)
+ else:
+ assert isinstance(item_version_ref, st.ResourceVersionRef)
+ file_data = item_version_ref.get_resource_file(name)
+
+ return werkzeug.Response(
+ file_data.contents,
+ mimetype = file_data.mime_type
+ )
+ except st.MissingItemError:
+ if file_type == 'license':
+ url = item_version_ref.get_upstream_license_file_url(name)
+ else:
+ assert isinstance(item_version_ref, st.ResourceVersionRef)
+ url = item_version_ref.get_upstream_resource_file_url(name)
+
+ return flask.redirect(url)
+
+ except st.MissingItemError:
+ flask.abort(404)
+
+@bp.route('/packages/viewversion/<string:item_version_id>/<string:file_type>/<path:name>')
+def show_mapping_file(item_version_id: str, file_type: str, name: str) \
+ -> werkzeug.Response:
+ item_type = item_infos.ItemType.MAPPING
+ return show_file(item_version_id, item_type, file_type, name)
+
+@bp.route('/libraries/viewversion/<string:item_version_id>/<string:file_type>/<path:name>')
+def show_resource_file(item_version_id: str, file_type: str, name: str) \
+ -> werkzeug.Response:
+ item_type = item_infos.ItemType.RESOURCE
+ return show_file(item_version_id, item_type, file_type, name)
+
+@bp.route('/libraries/viewdep/<string:item_version_id>/<string:dep_identifier>')
+def show_library_dep(item_version_id: str, dep_identifier: str) \
+ -> werkzeug.Response:
+ state = _app.get_haketilo_state()
+
+ try:
+ store = state.resource_version_store()
+ dep_id = store.get(item_version_id).get_dependency(dep_identifier).id
+ url = flask.url_for('.show_library_version', item_version_id=dep_id)
+ except st.MissingItemError:
+ try:
+ versionless_store = state.resource_store()
+ item_ref = versionless_store.get_by_identifier(dep_identifier)
+ url = flask.url_for('.show_library', item_id=item_ref.id)
+ except st.MissingItemError:
+ flask.abort(404)
+
+ return flask.redirect(url)
+
+@bp.route('/<string:item_type>/viewrequired/<string:item_version_id>/<string:required_identifier>')
+def show_required_mapping(
+ item_type: str,
+ item_version_id: str,
+ required_identifier: str
+) -> werkzeug.Response:
+ state = _app.get_haketilo_state()
+
+ if item_type not in ('package', 'library'):
+ flask.abort(404)
+
+ found = False
+
+ if item_type == 'package':
+ try:
+ ref = state.mapping_version_store().get(item_version_id)
+ mapping_ver_id = ref.get_required_mapping(required_identifier).id
+ url = flask.url_for(
+ '.show_package_version',
+ item_version_id = mapping_ver_id
+ )
+ found = True
+ except st.MissingItemError:
+ pass
+
+ if not found:
+ try:
+ versionless_store = state.mapping_store()
+ mapping_ref = versionless_store\
+ .get_by_identifier(required_identifier)
+ url = flask.url_for('.show_package', item_id=mapping_ref.id)
+ except st.MissingItemError:
+ flask.abort(404)
+
+ return flask.redirect(url)
+
+@bp.route('/package/viewpayload/<string:item_version_id>/<string:pattern>/<string:lib_identifier>')
+def show_payload(item_version_id: str, pattern: str, lib_identifier: str) \
+ -> werkzeug.Response:
+ state = _app.get_haketilo_state()
+
+ try:
+ ref = state.mapping_version_store().get(item_version_id)
+
+ try:
+ resource_ver_ref = \
+ ref.get_payload_resource(unquote(pattern), lib_identifier)
+ url = flask.url_for(
+ '.show_library_version',
+ item_version_id = resource_ver_ref.id
+ )
+ except st.MissingItemError:
+ resource_ref = \
+ state.resource_store().get_by_identifier(lib_identifier)
+ url = flask.url_for('.show_library', item_id=resource_ref.id)
+ except st.MissingItemError:
+ flask.abort(404)
+
+ return flask.redirect(url)
diff --git a/src/hydrilla/proxy/web_ui/templates/include/item_list_style.css.jinja b/src/hydrilla/proxy/web_ui/templates/include/item_list_style.css.jinja
index cbdf225..063cd01 100644
--- a/src/hydrilla/proxy/web_ui/templates/include/item_list_style.css.jinja
+++ b/src/hydrilla/proxy/web_ui/templates/include/item_list_style.css.jinja
@@ -18,36 +18,40 @@ I, Wojtek Kosior, thereby promise not to sue for violation of this
file's licenses. Although I request that you do not make use of this
code in a proprietary work, I am not going to enforce this in court.
#}
-ul#item_list {
+ul.item-list {
padding: 0;
}
-ul#item_list > li {
+ul.item-list > li {
list-style-type: none;
max-width: 100%;
white-space: nowrap;
margin: 0;
}
-ul#item_list > li > :only-child {
+ul.item-list > li > :only-child {
display: block;
padding: 5px;
overflow-x: scroll;
border-bottom: 2px solid #999;
}
-ul#item_list > li.entry-line-dashed > :only-child {
+ul.item-list > li.entry-line-dashed > :only-child {
border-bottom-style: dashed
}
-ul#item_list > li.entry-line-green > :only-child {
+ul.item-list > li.entry-line-green > :only-child {
border-color: #4caf50;
}
-ul#item_list > li.entry-line-blue > :only-child {
+ul.item-list > li.entry-line-blue > :only-child {
border-color: #504caf;
}
-ul#item_list > li.entry-line-red > :only-child {
+ul.item-list > li.entry-line-red > :only-child {
border-color: #af504c;
}
+
+ul.item-list > li.invisible-entry-line > :only-child {
+ border-color: #fff;
+}
diff --git a/src/hydrilla/proxy/web_ui/templates/items/item_view.html.jinja b/src/hydrilla/proxy/web_ui/templates/items/item_view.html.jinja
index f048f14..5f8b102 100644
--- a/src/hydrilla/proxy/web_ui/templates/items/item_view.html.jinja
+++ b/src/hydrilla/proxy/web_ui/templates/items/item_view.html.jinja
@@ -20,7 +20,7 @@ code in a proprietary work, I am not going to enforce this in court.
#}
{% extends "base.html.jinja" %}
-{% macro versioned_identifier_with_repo(info) -%}
+{% macro version_with_repo(info) -%}
{{ info.info.version_string }}
{%- if not info.is_local %}
@
@@ -56,7 +56,7 @@ code in a proprietary work, I am not going to enforce this in court.
{% endblock %}
</h4>
- <ul id="item_list">
+ <ul class="item-list">
{% for info in display_info.all_versions %}
{%
if version_display_info is not defined or
@@ -88,7 +88,7 @@ code in a proprietary work, I am not going to enforce this in court.
)
%}
<a href="{{ href }}">
- <div> {{ versioned_identifier_with_repo(info) }} </div>
+ <div> {{ version_with_repo(info) }} </div>
</a>
</li>
{% endif %}
diff --git a/src/hydrilla/proxy/web_ui/templates/items/item_viewversion.html.jinja b/src/hydrilla/proxy/web_ui/templates/items/item_viewversion.html.jinja
index c7574f1..bb32be4 100644
--- a/src/hydrilla/proxy/web_ui/templates/items/item_viewversion.html.jinja
+++ b/src/hydrilla/proxy/web_ui/templates/items/item_viewversion.html.jinja
@@ -20,6 +20,50 @@ code in a proprietary work, I am not going to enforce this in court.
#}
{% extends "items/item_view.html.jinja" %}
+{% macro item_file_list(file_specs, file_type) %}
+ <ul class="item-list has-colored-links">
+ {% for spec in file_specs %}
+ <li class="invisible-entry-line">
+ {%
+ set url = url_for(
+ '.show_{}_file'.format(version_display_info.type.value),
+ item_version_id = version_display_info.ref.id,
+ file_type = file_type,
+ name = spec.name
+ )
+ %}
+ <div>
+ <a href="{{ url }}">
+ {{ spec.name }}
+ </a>
+ </div>
+ </li>
+ {% endfor %}
+ </ul>
+{% endmacro %}
+
+{% macro item_link_list(item_specs, make_url) %}
+ <ul class="item-list has-colored-links">
+ {% for spec in item_specs %}
+ <li class="invisible-entry-line">
+ <div>
+ <a href="{{ make_url(spec) }}">
+ {{ spec.identifier }}
+ </a>
+ </div>
+ </li>
+ {% endfor %}
+ </ul>
+{% endmacro %}
+
+{% block style %}
+ {{ super() }}
+
+ .has-colored-links a {
+ color: #557b8e;
+ }
+{% endblock %}
+
{% block main_info %}
{% if file_installation_error is defined %}
{{ error_note(_('web_ui.err.file_installation_error')) }}
@@ -35,19 +79,75 @@ code in a proprietary work, I am not going to enforce this in court.
{{ super() }}
+ {{ label(_('web_ui.items.single_version.identifier_label')) }}
+
+ <p>
+ {{ version_display_info.info.identifier }}
+ </p>
+
+ <div class="horizontal-separator"></div>
+
{{ label(_('web_ui.items.single_version.version_label')) }}
<p>
- {{ versioned_identifier_with_repo(version_display_info) }}
+ {{ version_with_repo(version_display_info) }}
</p>
<div class="horizontal-separator"></div>
- {% block main_info_bulk %}
+ {% if version_display_info.info.uuid is not none %}
+ {{ label(_('web_ui.items.single_version.uuid_label')) }}
+
+ <p>
+ {{ version_display_info.info.uuid }}
+ </p>
+
+ <div class="horizontal-separator"></div>
+ {% endif %}
+
+ {% if version_display_info.info.description %}
+ {{ label(_('web_ui.items.single_version.description_label')) }}
+
<p>
- TODO: add more info...
+ {{ version_display_info.info.description }}
</p>
- {% endblock %}
+
+ <div class="horizontal-separator"></div>
+ {% endif %}
+
+ {{ label(_('web_ui.items.single_version.licenses_label')) }}
+
+ {% if version_display_info.info.source_copyright %}
+ {{ item_file_list(version_display_info.info.source_copyright, 'license') }}
+ {% else %}
+ <p>
+ {{ _('web_ui.items.single_version.no_license_files') }}
+ </p>
+ {% endif %}
+
+ <div class="horizontal-separator"></div>
+
+ {% if version_display_info.info.required_mappings %}
+ {{ label(_('web_ui.items.single_version.reqired_mappings_label')) }}
+
+ {% macro make_mapping_url(spec) -%}
+ {{
+ url_for(
+ '.show_required_mapping',
+ item_type = version_display_info.type.alt_name,
+ item_version_id = version_display_info.ref.id,
+ required_identifier = spec.identifier
+ )
+ }}
+ {%- endmacro %}
+
+ {% set required_specs = version_display_info.info.required_mappings %}
+ {{ item_link_list(required_specs, make_mapping_url) }}
+
+ <div class="horizontal-separator"></div>
+ {% endif %}
+
+ {% block main_info_rest required %}{% endblock %}
{%
if settings.advanced_user and
diff --git a/src/hydrilla/proxy/web_ui/templates/items/libraries.html.jinja b/src/hydrilla/proxy/web_ui/templates/items/libraries.html.jinja
index 2d5ec29..0a72b64 100644
--- a/src/hydrilla/proxy/web_ui/templates/items/libraries.html.jinja
+++ b/src/hydrilla/proxy/web_ui/templates/items/libraries.html.jinja
@@ -27,7 +27,7 @@ code in a proprietary work, I am not going to enforce this in court.
{% include 'include/item_list_style.css.jinja' %}
- ul#item_list > li > a {
+ ul.item-list > li > a {
display: flex !important;
flex-direction: column;
justify-content: center;
@@ -38,7 +38,7 @@ code in a proprietary work, I am not going to enforce this in court.
{% block main %}
<h3>{{ _('web_ui.libraries.heading') }}</h3>
- <ul id="item_list">
+ <ul class="item-list">
{% for info in display_infos %}
<li>
<a href="{{ url_for('.show_library', item_id=info.ref.id) }}">
diff --git a/src/hydrilla/proxy/web_ui/templates/items/library_viewversion.html.jinja b/src/hydrilla/proxy/web_ui/templates/items/library_viewversion.html.jinja
index 0454391..eb77fe6 100644
--- a/src/hydrilla/proxy/web_ui/templates/items/library_viewversion.html.jinja
+++ b/src/hydrilla/proxy/web_ui/templates/items/library_viewversion.html.jinja
@@ -54,13 +54,35 @@ code in a proprietary work, I am not going to enforce this in court.
{{ _('web_ui.items.single_version.library.version_list_heading') }}
{% endblock %}
-{% block main_info_bulk %}
- <p>
- TODO: add more info...
- </p>
+{% block main_info_rest %}
+ {{ label(_('web_ui.items.single_version.library.scripts_label')) }}
+
+ {% if version_display_info.info.scripts %}
+ {{ item_file_list(version_display_info.info.scripts, 'web_resource') }}
+ {% else %}
+ <p>
+ {{ _('web_ui.items.single_version.library.no_script_files') }}
+ </p>
+ {% endif %}
<div class="horizontal-separator"></div>
+ {% if version_display_info.info.dependencies %}
+ {{ label(_('web_ui.items.single_version.library.deps_label')) }}
+
+ {% macro make_dep_url(spec) -%}
+ {{
+ url_for(
+ '.show_library_dep',
+ item_version_id = version_display_info.ref.id,
+ dep_identifier = spec.identifier
+ )
+ }}
+ {%- endmacro %}
+
+ {{ item_link_list(version_display_info.info.dependencies, make_dep_url) }}
+ {% endif %}
+
{{ label(_('web_ui.items.single_version.library.enabled_label')) }}
<p>
@@ -78,4 +100,4 @@ code in a proprietary work, I am not going to enforce this in court.
{{ _('web_ui.items.single_version.library.item_auto_activated') }}
{% endif %}
</p>
-{% endblock %}
+{% endblock main_info_rest %}
diff --git a/src/hydrilla/proxy/web_ui/templates/items/package_viewversion.html.jinja b/src/hydrilla/proxy/web_ui/templates/items/package_viewversion.html.jinja
index 699469e..bc33c42 100644
--- a/src/hydrilla/proxy/web_ui/templates/items/package_viewversion.html.jinja
+++ b/src/hydrilla/proxy/web_ui/templates/items/package_viewversion.html.jinja
@@ -54,10 +54,50 @@ code in a proprietary work, I am not going to enforce this in court.
{{ _('web_ui.items.single_version.package.version_list_heading') }}
{% endblock %}
-{% block main_info_bulk %}
- <p>
- TODO: add more info...
- </p>
+{% block main_info_rest %}
+ {{ label(_('web_ui.items.single_version.package.payloads_label')) }}
+
+ {% if version_display_info.info.payloads|length > 0 %}
+ <ul class="item-list has-colored-links">
+ {% set by_lib = {} %}
+ {%
+ for pattern_struct, spec in version_display_info.info.payloads.items()
+ if pattern_struct.orig_url not in processed_patterns
+ %}
+ {% set pattern = pattern_struct.orig_url %}
+ {% do by_lib.setdefault(spec.identifier, []).append(pattern) %}
+ {% endfor %}
+ {% for lib_identifier, patterns in by_lib|dictsort %}
+ <li class="invisible-entry-line">
+ <div>
+ {% set encoded = patterns[0]|urlencode|replace('/', '%2F') %}
+ {%
+ set url = url_for(
+ '.show_payload',
+ item_version_id = version_display_info.ref.id,
+ pattern = encoded,
+ lib_identifier = lib_identifier
+ )
+ %}
+ <div>
+ <a href="{{ url }}">
+ {{ lib_identifier }}
+ </a>
+ </div>
+ {% for pattern in patterns|unique|sort(attribute='identifier') %}
+ <div class="small-print">
+ {{ pattern }}
+ </div>
+ {% endfor %}
+ </div>
+ </li>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p>
+ {{ _('web_ui.items.single_version.package.no_payloads') }}
+ </p>
+ {% endif %}
<div class="horizontal-separator"></div>
@@ -183,9 +223,7 @@ code in a proprietary work, I am not going to enforce this in court.
{% else %}
{{
_('web_ui.items.single_version.active_ver_is_{}')
- .format(
- versioned_identifier_with_repo(display_info.active_version)
- )
+ .format(version_with_repo(display_info.active_version))
}}
{% endif %}
</p>
@@ -198,4 +236,4 @@ code in a proprietary work, I am not going to enforce this in court.
])
}}
{% endif %}{# display_info.enabled == EnabledStatus.ENABLED #}
-{% endblock main_info_bulk %}
+{% endblock main_info_rest %}
diff --git a/src/hydrilla/proxy/web_ui/templates/items/packages.html.jinja b/src/hydrilla/proxy/web_ui/templates/items/packages.html.jinja
index 29228a2..bc6b5bb 100644
--- a/src/hydrilla/proxy/web_ui/templates/items/packages.html.jinja
+++ b/src/hydrilla/proxy/web_ui/templates/items/packages.html.jinja
@@ -27,7 +27,7 @@ code in a proprietary work, I am not going to enforce this in court.
{% include 'include/item_list_style.css.jinja' %}
- ul#item_list > li > a {
+ ul.item-list > li > a {
display: flex !important;
flex-direction: column;
justify-content: center;
@@ -38,7 +38,7 @@ code in a proprietary work, I am not going to enforce this in court.
{% block main %}
<h3>{{ _('web_ui.packages.heading') }}</h3>
- <ul id="item_list">
+ <ul class="item-list">
{% for info in display_infos %}
{% set entry_classes = [] %}
diff --git a/src/hydrilla/proxy/web_ui/templates/repos/index.html.jinja b/src/hydrilla/proxy/web_ui/templates/repos/index.html.jinja
index 15f821b..e670b59 100644
--- a/src/hydrilla/proxy/web_ui/templates/repos/index.html.jinja
+++ b/src/hydrilla/proxy/web_ui/templates/repos/index.html.jinja
@@ -40,7 +40,7 @@ code in a proprietary work, I am not going to enforce this in court.
<h4>{{ _('web_ui.repos.repo_list_heading') }}</h4>
- <ul id="item_list">
+ <ul class="item-list">
{% for info in display_infos %}
{% set entry_classes = [] %}
diff --git a/src/hydrilla/proxy/web_ui/templates/rules/index.html.jinja b/src/hydrilla/proxy/web_ui/templates/rules/index.html.jinja
index 71712fe..799eaba 100644
--- a/src/hydrilla/proxy/web_ui/templates/rules/index.html.jinja
+++ b/src/hydrilla/proxy/web_ui/templates/rules/index.html.jinja
@@ -40,7 +40,7 @@ code in a proprietary work, I am not going to enforce this in court.
<h4>{{ _('web_ui.rules.rule_list_heading') }}</h4>
- <ul id="item_list">
+ <ul class="item-list">
{% for info in display_infos %}
{% if info.allow_scripts %}