labfreed 1.0.0a3__tar.gz → 1.0.0a4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/PKG-INFO +1 -1
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/__init__.py +1 -1
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/labfreed_extended/app/app_infrastructure.py +1 -1
- labfreed-1.0.0a4/labfreed/labfreed_extended/app/pac_info/html_renderer/external-link.svg +7 -0
- labfreed-1.0.0a4/labfreed/labfreed_extended/app/pac_info/html_renderer/macros.jinja.html +188 -0
- labfreed-1.0.0a4/labfreed/labfreed_extended/app/pac_info/html_renderer/pac-info-style.css +176 -0
- labfreed-1.0.0a4/labfreed/labfreed_extended/app/pac_info/html_renderer/pac_info.jinja.html +46 -0
- labfreed-1.0.0a4/labfreed/labfreed_extended/app/pac_info/html_renderer/pac_info_card.jinja.html +7 -0
- {labfreed-1.0.0a3/labfreed/labfreed_extended/app → labfreed-1.0.0a4/labfreed/labfreed_extended/app/pac_info}/pac_info.py +38 -1
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/.github/workflows/pypi-publish.yml +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/.github/workflows/run-tests.yml +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/CHANGELOG.md +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/LICENSE +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/README.md +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/labfreed_extended/app/formatted_print.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/labfreed_infrastructure.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/api_data_models/request.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/api_data_models/response.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/api_data_models/server_capabilities_response.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/client/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/client/attribute_cache.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/client/client.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/pythonic/attribute_server_factory.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/pythonic/excel_attribute_data_source.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/pythonic/py_attributes.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/pythonic/py_dict_data_source.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/server/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/server/attribute_data_sources.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/server/server.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/server/translation_data_sources.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/well_knonw_attribute_keys.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_cat/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_cat/category_base.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_cat/pac_cat.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_cat/predefined_categories.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id/extension.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id/id_segment.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id/pac_id.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id/url_parser.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id/url_serializer.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id_resolver/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id_resolver/cit_common.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id_resolver/cit_v1.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id_resolver/cit_v2.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id_resolver/resolver.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_id_resolver/services.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/qr/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/qr/generate_qr.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/trex/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/trex/pythonic/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/trex/pythonic/data_table.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/trex/pythonic/pyTREX.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/trex/pythonic/quantity.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/trex/table_segment.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/trex/trex.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/trex/trex_base_models.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/trex/value_segments.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/utilities/base36.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/utilities/ensure_utc_time.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/utilities/translations.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_extensions/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_extensions/default_extension_interpreters.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_extensions/display_name_extension.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_extensions/trex_extension.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_keys/gs1/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_keys/gs1/gs1_ai_enum_sorted.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_keys/labfreed/well_known_keys.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_keys/unece/UneceUnits.json +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_keys/unece/__init__.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_keys/unece/unece_units.py +0 -0
- {labfreed-1.0.0a3 → labfreed-1.0.0a4}/pyproject.toml +0 -0
|
@@ -3,7 +3,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
|
3
3
|
|
|
4
4
|
import requests
|
|
5
5
|
|
|
6
|
-
from labfreed.labfreed_extended.app.pac_info import PacInfo
|
|
6
|
+
from labfreed.labfreed_extended.app.pac_info.pac_info import PacInfo
|
|
7
7
|
from labfreed.pac_attributes.client.attribute_cache import MemoryAttributeCache
|
|
8
8
|
from labfreed.pac_attributes.client.client import AttributeClient, http_attribute_request_default_callback_factory
|
|
9
9
|
from labfreed.pac_attributes.pythonic.py_attributes import pyAttributeGroup
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
3
|
+
<title>icons/external-link</title>
|
|
4
|
+
<g id="icons/external-link" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
5
|
+
<path d="M5.10570888,18.8942911 C4.83722343,18.6258057 4.81484965,18.204406 5.03858752,17.9104349 L5.10570888,17.8336309 L15.9992174,6.94117952 L10.8105793,6.93942074 L10.7088087,6.93257412 C10.3427331,6.8829117 10.0605793,6.5691165 10.0605793,6.18942074 C10.0605793,5.81286295 10.3380887,5.50112097 10.6997498,5.44755266 L10.8105793,5.43942074 L18.5605793,5.43942074 L18.5605793,13.1894207 L18.5537326,13.2911913 C18.5090365,13.6206593 18.2503927,13.8821507 17.9223127,13.9311544 L17.8105793,13.9394207 L17.7088087,13.9325741 C17.3793407,13.8878779 17.1178493,13.6292342 17.0688456,13.3011542 L17.0605793,13.1894207 L17.0598776,8.00183969 L6.16636906,18.8942911 C5.87347584,19.1871843 5.3986021,19.1871843 5.10570888,18.8942911 Z" id="Icons/Navigation/External-Link/Dark" fill="#1C1847" fill-rule="nonzero"></path>
|
|
6
|
+
</g>
|
|
7
|
+
</svg>
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
{# ---------- PAC-INFO MACROS ---------- #}
|
|
2
|
+
{# These macros render semantic HTML with light class hooks. #}
|
|
3
|
+
|
|
4
|
+
{%- macro info_card(pac_info) -%}
|
|
5
|
+
<section class="lf-info-card">
|
|
6
|
+
<div class="lf-info-title">{{ pac_info.display_name }}</div>
|
|
7
|
+
<div class="lf-info-grid">
|
|
8
|
+
{% if pac_info.image_url %}
|
|
9
|
+
<img src="{{ pac_info.image_url }}" class="prod_img lf-info-item" alt="">
|
|
10
|
+
{% endif %}
|
|
11
|
+
|
|
12
|
+
{% if pac_info.main_category %}
|
|
13
|
+
{% for c in pac_info.pac_id.categories %}
|
|
14
|
+
{% for k, v in c.segments_as_dict().items() %}
|
|
15
|
+
{% if k != "key" %}
|
|
16
|
+
<div class="lf-info-item">
|
|
17
|
+
{% if k %}
|
|
18
|
+
<div class="lf-info-key">{{ k }}</div>
|
|
19
|
+
{% else %}
|
|
20
|
+
<div class="lf-info-key"> <i>{{"No Key" }}</i></div>
|
|
21
|
+
{% endif %}
|
|
22
|
+
<div class="lf-info-val">{{ v }}</div>
|
|
23
|
+
</div>
|
|
24
|
+
{% endif %}
|
|
25
|
+
{% endfor %}
|
|
26
|
+
{% endfor %}
|
|
27
|
+
{% endif %}
|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
{% if pac_info.safety_pictograms %}
|
|
31
|
+
{% for p in pac_info.safety_pictograms.values() %}
|
|
32
|
+
<figure class="lf-figure lf-figure--image">
|
|
33
|
+
<img src="{{ p.value|e }}" alt="{{ p.label|e }}" class="lf-attr-image">
|
|
34
|
+
<figcaption class="lf-figure__caption sr-only">{{ p.label }}</figcaption>
|
|
35
|
+
</figure>
|
|
36
|
+
{% endfor %}
|
|
37
|
+
{% endif %}
|
|
38
|
+
|
|
39
|
+
</section>
|
|
40
|
+
{%- endmacro -%}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
{%- macro key_value_table(pairs) -%}
|
|
44
|
+
{# pairs: dict-like object #}
|
|
45
|
+
<table class="lf-table lf-table--kv">
|
|
46
|
+
<tbody>
|
|
47
|
+
{%- for k, v in pairs.items() -%}
|
|
48
|
+
{%- if k != "key" -%}
|
|
49
|
+
<tr>
|
|
50
|
+
<th class="lf-th lf-th--key">{{ k }}</th>
|
|
51
|
+
<td class="lf-td lf-td--val">{{ v }}</td>
|
|
52
|
+
</tr>
|
|
53
|
+
{%- endif -%}
|
|
54
|
+
{%- endfor -%}
|
|
55
|
+
</tbody>
|
|
56
|
+
</table>
|
|
57
|
+
{%- endmacro -%}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
{%- macro category_block(category) -%}
|
|
61
|
+
<div class="lf-section lf-section--category">
|
|
62
|
+
<h5 class="lf-section__title">{{ category.__class__.__name__ }}</h5>
|
|
63
|
+
{{ key_value_table(category.segments_as_dict()) }}
|
|
64
|
+
</div>
|
|
65
|
+
{%- endmacro -%}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
{%- macro services_table(user_handover_group) -%}
|
|
69
|
+
<div class="lf-section lf-section--services">
|
|
70
|
+
<div class="lf-origin-hint">from {{ user_handover_group.origin }}</div>
|
|
71
|
+
<div class="lf-services">
|
|
72
|
+
{%- for s in user_handover_group.services -%}
|
|
73
|
+
<a href="{{ s.url }}" target="_blank" rel="noopener" class="lf-service">
|
|
74
|
+
<span class="lf-service__icon">
|
|
75
|
+
{% include "external-link.svg" %}
|
|
76
|
+
</span>
|
|
77
|
+
<span class="lf-service__name">{{ s.service_name }}</span>
|
|
78
|
+
</a>
|
|
79
|
+
{%- endfor -%}
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
{%- endmacro -%}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
{%- macro reference_value(value) -%}
|
|
86
|
+
<span class="lf-reference">{{ value }}</span>
|
|
87
|
+
{%- endmacro -%}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
{%- macro attribute_row(a) -%}
|
|
91
|
+
<tr>
|
|
92
|
+
<th class="lf-th lf-th--key">{{ a.label }}</th>
|
|
93
|
+
<td class="lf-td lf-td--val">
|
|
94
|
+
{% set value = a.value %}
|
|
95
|
+
{%- if is_image(value) -%}
|
|
96
|
+
<figure class="lf-figure lf-figure--image">
|
|
97
|
+
<img src="{{ value|e }}" alt="{{ label|e }}" class="lf-attr-image">
|
|
98
|
+
<figcaption class="lf-figure__caption sr-only">{{ label }}</figcaption>
|
|
99
|
+
</figure>
|
|
100
|
+
{%- elif is_url(value) -%}
|
|
101
|
+
<a href="{{ value|e }}" target="_blank" rel="noopener" class="lf-link">{{ value }}</a>
|
|
102
|
+
{%- elif is_reference(value) -%}
|
|
103
|
+
{{ reference_value(value)}}
|
|
104
|
+
{%- else -%}
|
|
105
|
+
<span class="lf-text">{{ value }}</span>
|
|
106
|
+
{%- endif -%}
|
|
107
|
+
</td>
|
|
108
|
+
</tr>
|
|
109
|
+
{%- endmacro -%}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
{%- macro attribute_group_block(ag) -%}
|
|
113
|
+
<div class="lf-section lf-section--attributes">
|
|
114
|
+
<h5 class="lf-section__title">
|
|
115
|
+
{{ ag.label }} <span class="lf-origin-hint">(from {{ ag.origin }})</span>
|
|
116
|
+
</h5>
|
|
117
|
+
<table class="lf-table lf-table--kv">
|
|
118
|
+
<tbody>
|
|
119
|
+
{%- for a in ag.attributes.values() -%}
|
|
120
|
+
{{ attribute_row(a) }}
|
|
121
|
+
{%- endfor -%}
|
|
122
|
+
</tbody>
|
|
123
|
+
</table>
|
|
124
|
+
</div>
|
|
125
|
+
{%- endmacro -%}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
{%- macro data_table_inline(dt) -%}
|
|
129
|
+
{# Renders your DataTable structure; expects filters: is_data_table(dt) #}
|
|
130
|
+
{%- if dt.data | length == 1 -%}
|
|
131
|
+
<table class="lf-table lf-table--kv">
|
|
132
|
+
<tbody>
|
|
133
|
+
{%- for i in range(dt.col_names | length) -%}
|
|
134
|
+
<tr>
|
|
135
|
+
<th class="lf-th lf-th--key">{{ dt.col_names[i] }}</th>
|
|
136
|
+
<td class="lf-td lf-td--val">{{ dt.data[0][i] }}</td>
|
|
137
|
+
</tr>
|
|
138
|
+
{%- endfor -%}
|
|
139
|
+
</tbody>
|
|
140
|
+
</table>
|
|
141
|
+
{%- else -%}
|
|
142
|
+
<table class="lf-table lf-table--grid">
|
|
143
|
+
<thead>
|
|
144
|
+
<tr>
|
|
145
|
+
{%- for rn in dt.col_names -%}
|
|
146
|
+
<th class="lf-th">{{ rn }}</th>
|
|
147
|
+
{%- endfor -%}
|
|
148
|
+
</tr>
|
|
149
|
+
</thead>
|
|
150
|
+
<tbody>
|
|
151
|
+
{%- for row in dt.data -%}
|
|
152
|
+
<tr>
|
|
153
|
+
{%- for e in row -%}
|
|
154
|
+
<td class="lf-td">{{ e }}</td>
|
|
155
|
+
{%- endfor -%}
|
|
156
|
+
</tr>
|
|
157
|
+
{%- endfor -%}
|
|
158
|
+
</tbody>
|
|
159
|
+
</table>
|
|
160
|
+
{%- endif -%}
|
|
161
|
+
{%- endmacro -%}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
{%- macro attached_data_block(attached_data) -%}
|
|
165
|
+
<div class="lf-section lf-section--attached">
|
|
166
|
+
{%- for name, trex in attached_data.items() -%}
|
|
167
|
+
<div class="lf-subsection">
|
|
168
|
+
<h5 class="lf-subsection__title">{{ name }}</h5>
|
|
169
|
+
<table class="lf-table lf-table--kv">
|
|
170
|
+
<tbody>
|
|
171
|
+
{%- for k, v in trex.items() -%}
|
|
172
|
+
<tr>
|
|
173
|
+
<th class="lf-th lf-th--key">{{ k }}</th>
|
|
174
|
+
<td class="lf-td lf-td--val">
|
|
175
|
+
{%- if is_data_table(v) -%}
|
|
176
|
+
{{ data_table_inline(v) }}
|
|
177
|
+
{%- else -%}
|
|
178
|
+
{{ v }}
|
|
179
|
+
{%- endif -%}
|
|
180
|
+
</td>
|
|
181
|
+
</tr>
|
|
182
|
+
{%- endfor -%}
|
|
183
|
+
</tbody>
|
|
184
|
+
</table>
|
|
185
|
+
</div>
|
|
186
|
+
{%- endfor -%}
|
|
187
|
+
</div>
|
|
188
|
+
{%- endmacro -%}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
|
|
2
|
+
.lf-section {
|
|
3
|
+
margin-top: 0.5rem;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.lf-origin-hint {
|
|
7
|
+
font-style: italic; /* cursive */
|
|
8
|
+
font-size: 1rem; /* reset to regular text size */
|
|
9
|
+
font-weight: normal; /* not bold, even if inside a heading */
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
.lf-results {
|
|
14
|
+
display: grid;
|
|
15
|
+
gap: 1.5rem;
|
|
16
|
+
padding: 1rem; /* space around the whole grid */
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.lf-info-card {
|
|
20
|
+
width:100%;
|
|
21
|
+
border: solid 1px #ccc;
|
|
22
|
+
border-radius: 8px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.lf-info-card {
|
|
26
|
+
padding: 1rem;
|
|
27
|
+
border: 1px solid #e5e7eb;
|
|
28
|
+
border-radius: 8px;
|
|
29
|
+
background: #fff;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* title as "slightly bigger text" */
|
|
33
|
+
.lf-info-title {
|
|
34
|
+
font-size: 1.25rem; /* a bit larger than normal text */
|
|
35
|
+
font-weight: 600;
|
|
36
|
+
margin-bottom: 1rem;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* responsive grid for key/value */
|
|
40
|
+
.lf-info-grid {
|
|
41
|
+
display: grid;
|
|
42
|
+
gap: 1rem;
|
|
43
|
+
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.lf-info-item {
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
gap: 0.25rem;
|
|
50
|
+
padding: 0.5rem;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.lf-info-key {
|
|
54
|
+
font-size: 0.875rem;
|
|
55
|
+
font-weight: 600;
|
|
56
|
+
color: #374151; /* slate-700 */
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.lf-info-val {
|
|
60
|
+
font-size: 1rem;
|
|
61
|
+
color: #111827; /* slate-900 */
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
.prod_img {
|
|
67
|
+
height: 10vw;
|
|
68
|
+
width: auto;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
/* Apply to all PAC macro tables */
|
|
73
|
+
.lf-table {
|
|
74
|
+
width: 100%;
|
|
75
|
+
border-collapse: collapse;
|
|
76
|
+
table-layout: fixed; /* ensures consistent column widths */
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.lf-table th,
|
|
80
|
+
.lf-table td {
|
|
81
|
+
border: 1px solid #ccc;
|
|
82
|
+
padding: 0.4rem 0.6rem;
|
|
83
|
+
vertical-align: top;
|
|
84
|
+
text-align: left;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Key/value style: 1/3 vs 2/3 columns */
|
|
88
|
+
.lf-table--kv th.lf-th--key {
|
|
89
|
+
width: 33%;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
}
|
|
92
|
+
.lf-table--kv td.lf-td--val {
|
|
93
|
+
width: 67%;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.lf-attr-image {
|
|
97
|
+
width: 30px;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* Services laid out as equal-width grid columns */
|
|
101
|
+
.lf-services {
|
|
102
|
+
display: grid;
|
|
103
|
+
gap: 0.75rem;
|
|
104
|
+
|
|
105
|
+
/* 2 columns on small, 3 on md, 4 on lg — tweak as you like */
|
|
106
|
+
grid-template-columns: repeat(2, 1fr);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@media (min-width: 640px) {
|
|
110
|
+
.lf-services { grid-template-columns: repeat(3, 1fr); }
|
|
111
|
+
}
|
|
112
|
+
@media (min-width: 1024px) {
|
|
113
|
+
.lf-services { grid-template-columns: repeat(4, 1fr); }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Each service card fills its grid cell */
|
|
117
|
+
.lf-service {
|
|
118
|
+
display: flex; /* still use flex inside for icon + text */
|
|
119
|
+
align-items: center;
|
|
120
|
+
gap: 0.4rem;
|
|
121
|
+
padding: 0.4rem 0.6rem;
|
|
122
|
+
height: 100%; /* same height across a row (since your content height is uniform) */
|
|
123
|
+
width: 100%; /* ensure full cell width */
|
|
124
|
+
text-decoration: none;
|
|
125
|
+
color: var(--lf-link, #2563eb);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.lf-service:hover {
|
|
129
|
+
font-size: 1.05em; /* ~5% larger */
|
|
130
|
+
text-decoration: none;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.lf-service__icon { width: 1rem; height: 1rem; flex-shrink: 0; }
|
|
134
|
+
.lf-service__name {
|
|
135
|
+
flex: 1;
|
|
136
|
+
overflow: hidden;
|
|
137
|
+
text-overflow: ellipsis;
|
|
138
|
+
white-space: nowrap;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
/* Position context */
|
|
144
|
+
.lf-ref-card-wrap {
|
|
145
|
+
position: relative;
|
|
146
|
+
display: inline-block;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* The floating card is hidden by default */
|
|
150
|
+
.lf-ref-card {
|
|
151
|
+
display: none;
|
|
152
|
+
position: absolute;
|
|
153
|
+
top: 100%; /* appear below the reference text */
|
|
154
|
+
left: 0;
|
|
155
|
+
z-index: 1000;
|
|
156
|
+
width: min(420px, 90vw);
|
|
157
|
+
margin-top: .5rem;
|
|
158
|
+
padding: 1rem;
|
|
159
|
+
background: #fff;
|
|
160
|
+
border: 1px solid #e5e7eb;
|
|
161
|
+
border-radius: 8px;
|
|
162
|
+
box-shadow: 0 10px 20px rgba(0,0,0,.08);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* Show on hover */
|
|
166
|
+
.lf-ref-card-wrap:hover .lf-ref-card {
|
|
167
|
+
display: block;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Style the inline reference */
|
|
171
|
+
.lf-reference {
|
|
172
|
+
color: var(--lf-link, #2563eb);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{% import "macros.jinja.html" as pac with context %}
|
|
2
|
+
|
|
3
|
+
<style>
|
|
4
|
+
{% include "pac-info-style.css" %}
|
|
5
|
+
</style>
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
{% if pac_info %}
|
|
9
|
+
<section class="lf-results">
|
|
10
|
+
{# ----- Info Card ---- #}
|
|
11
|
+
{{ pac.info_card(pac_info) }}
|
|
12
|
+
|
|
13
|
+
{# ---- Services ---- #}
|
|
14
|
+
{% if pac_info.user_handovers %}
|
|
15
|
+
<section>
|
|
16
|
+
<!--<h4>Services</h4>-->
|
|
17
|
+
{% for sg in pac_info.user_handovers %}
|
|
18
|
+
{{ pac.services_table(sg) }}
|
|
19
|
+
{% endfor %}
|
|
20
|
+
</section>
|
|
21
|
+
{% endif %}
|
|
22
|
+
|
|
23
|
+
{# ---- Attributes ---- #}
|
|
24
|
+
{% if pac_info.attributes %}
|
|
25
|
+
<section>
|
|
26
|
+
<!--<h4>Attributes</h4>-->
|
|
27
|
+
{% for ag in pac_info.attributes.values() %}
|
|
28
|
+
{% if ag.key not in hide_attribute_groups %}
|
|
29
|
+
{{ pac.attribute_group_block(ag) }}
|
|
30
|
+
{% endif %}
|
|
31
|
+
{% endfor %}
|
|
32
|
+
</section>
|
|
33
|
+
|
|
34
|
+
{% endif %}
|
|
35
|
+
|
|
36
|
+
{# ---- Attached Data ---- #}
|
|
37
|
+
{% if pac_info.attached_data %}
|
|
38
|
+
<section>
|
|
39
|
+
<!--<h4 class="lf-section__title">Attached Data</h4>-->
|
|
40
|
+
{{ pac.attached_data_block(pac_info.attached_data) }}
|
|
41
|
+
</section>
|
|
42
|
+
{% endif %}
|
|
43
|
+
|
|
44
|
+
</section>
|
|
45
|
+
|
|
46
|
+
{% endif %}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
from functools import cached_property
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from urllib.parse import urlparse
|
|
6
|
+
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
4
7
|
from pydantic import BaseModel, Field
|
|
5
|
-
from labfreed.pac_attributes.pythonic.py_attributes import pyAttribute, pyAttributeGroup, pyAttributes
|
|
8
|
+
from labfreed.pac_attributes.pythonic.py_attributes import pyAttribute, pyAttributeGroup, pyAttributes, pyReference
|
|
6
9
|
from labfreed.pac_attributes.well_knonw_attribute_keys import MetaAttributeKeys
|
|
7
10
|
from labfreed.pac_cat.pac_cat import PAC_CAT
|
|
8
11
|
from labfreed.pac_id.pac_id import PAC_ID
|
|
9
12
|
from labfreed.pac_id_resolver.services import ServiceGroup
|
|
10
13
|
from labfreed.labfreed_extended.app.formatted_print import StringIOLineBreak
|
|
14
|
+
from labfreed.trex.pythonic.data_table import DataTable
|
|
11
15
|
from labfreed.trex.pythonic.pyTREX import pyTREX
|
|
12
16
|
from labfreed.well_known_extensions.display_name_extension import DisplayNameExtension
|
|
13
17
|
|
|
@@ -112,6 +116,39 @@ class PacInfo(BaseModel):
|
|
|
112
116
|
|
|
113
117
|
return out
|
|
114
118
|
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def render_html(self, hide_attribute_groups:list[str]=[]) -> str:
|
|
122
|
+
return PACInfo_HTMLRenderer.render_template('pac_info_main.jinja.html',
|
|
123
|
+
pac_info = self,
|
|
124
|
+
hide_attribute_groups=hide_attribute_groups
|
|
125
|
+
)
|
|
115
126
|
|
|
127
|
+
def render_html_card(self) -> str:
|
|
128
|
+
return PACInfo_HTMLRenderer.render_template('pac_info_card.jinja.html',
|
|
129
|
+
pac_info = self
|
|
130
|
+
)
|
|
131
|
+
|
|
116
132
|
|
|
133
|
+
class PACInfo_HTMLRenderer():
|
|
134
|
+
TEMPLATES_DIR = Path(__file__).parent / "html_renderer"
|
|
135
|
+
jinja_env = Environment(
|
|
136
|
+
loader=FileSystemLoader(str(TEMPLATES_DIR), encoding="utf-8"),
|
|
137
|
+
autoescape=select_autoescape(enabled_extensions=("html", "jinja", "jinja2", "jinja.html")),
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
@classmethod
|
|
141
|
+
def render_template(cls, template_name:str, pac_info:PacInfo, hide_attribute_groups):
|
|
142
|
+
# --- Jinja env pointing at /html_renderer ---
|
|
143
|
+
template = cls.jinja_env.get_template("pac_info.jinja.html")
|
|
144
|
+
html = template.render(
|
|
145
|
+
pac=pac_info.pac_id,
|
|
146
|
+
pac_info=pac_info, # your object
|
|
147
|
+
hide_attribute_groups=hide_attribute_groups,
|
|
148
|
+
is_data_table = lambda value: isinstance(value, DataTable),
|
|
149
|
+
is_url = lambda s: isinstance(s, str) and urlparse(s).scheme in ('http', 'https') and bool(urlparse(s).netloc),
|
|
150
|
+
is_image = lambda s: isinstance(s, str) and s.lower().startswith('http') and s.lower().endswith(('.jpg','.jpeg','.png','.gif','.bmp','.webp','.svg','.tif','.tiff')),
|
|
151
|
+
is_reference = lambda s: isinstance(s, pyReference) ,
|
|
152
|
+
)
|
|
153
|
+
return html
|
|
117
154
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/pythonic/attribute_server_factory.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/pythonic/py_dict_data_source.py
RENAMED
|
File without changes
|
|
File without changes
|
{labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/server/attribute_data_sources.py
RENAMED
|
File without changes
|
|
File without changes
|
{labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/pac_attributes/server/translation_data_sources.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{labfreed-1.0.0a3 → labfreed-1.0.0a4}/labfreed/well_known_extensions/display_name_extension.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|