Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Changelog
2.7.0 (unreleased)
------------------

- #2963 Show analysis service keyword as code across service listings
- #2957 Harmonize form input widths via tunable CSS variables
- #2956 Restrict client discount fields to lab staff
- #2958 Add labels with colors, filtering, and bulk-manage modal for samples
Expand Down
7 changes: 6 additions & 1 deletion src/bika/lims/browser/analysisrequest/manage_analyses.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ def __init__(self, context, request):
"title": _("Service"),
"index": "sortable_title",
"sortable": False}),
("Keyword", {
"title": _("Keyword"),
"sortable": False}),
("ResultUnit", {
"title": _("Unit"),
"sortable": False}),
Expand All @@ -94,7 +97,7 @@ def __init__(self, context, request):
"title": _("Max")}),
))

columns = ["Title", "Unit", "Hidden", ]
columns = ["Title", "Keyword", "Unit", "Hidden", ]
if self.show_prices():
columns.append("Price")
if self.show_ar_specs():
Expand Down Expand Up @@ -238,6 +241,8 @@ def folderitem(self, obj, item, index):
spec = rr.get(keyword, ResultsRangeDict())

item["Title"] = obj.Title()
item["Keyword"] = keyword
item["replace"]["Keyword"] = "<code>{}</code>".format(keyword)
item["ResultUnit"] = obj.getUnit()
item["Price"] = price
item["before"]["Price"] = self.get_currency_symbol()
Expand Down
10 changes: 10 additions & 0 deletions src/bika/lims/browser/analysisrequest/templates/ar_add2.pt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@
{{title}}
</td>
</tr>
{{#if keyword}}
<tr>
<td class="service-info-key"
i18n:translate="">Keyword</td>
<td class="service-info-value">
<code>{{keyword}}</code>
</td>
</tr>
{{/if}}
{{#if unit}}
<tr>
<td class="service-info-key"
Expand Down Expand Up @@ -560,6 +569,7 @@
class python:'{} {} service'.format(category_id, poc);
poc python:poc;
data-uid python:service_uid;
data-keyword python:service_keyword;
data-category python:category_id;
fieldname python:'Analyses';">
<td class="service-header">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,9 @@ def folderitem(self, obj, item, index):
item["selected"] = False
item["Hidden"] = hidden
item["selected"] = uid in self.configuration
item["Keyword"] = obj.getKeyword()
keyword = obj.getKeyword()
item["Keyword"] = keyword
item["replace"]["Keyword"] = "<code>{}</code>".format(keyword)

# Add methods
methods = obj.getMethods()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ def folderitem(self, obj, item, index):

item["Title"] = title
item["Keyword"] = keyword
item["replace"]["Keyword"] = "<code>{}</code>".format(keyword)
item["replace"]["Title"] = get_link(url, value=title)
item["choices"]["min_operator"] = self.min_operator_choices
item["choices"]["max_operator"] = self.max_operator_choices
Expand Down
4 changes: 4 additions & 0 deletions src/bika/lims/browser/widgets/artemplateanalyseswidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ def folderitem(self, obj, item, index):
item["Hidden"] = hidden
item["selected"] = uid in self.configuration

keyword = obj.getKeyword()
item["Keyword"] = keyword
item["replace"]["Keyword"] = "<code>{}</code>".format(keyword)

# Make partition a required field
item.setdefault("required", []).append("Partition")

Expand Down
4 changes: 4 additions & 0 deletions src/bika/lims/browser/widgets/serviceswidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ def folderitem(self, obj, item, index):
item["selected"] = False
item["selected"] = uid in self.selected_services_uids

keyword = obj.getKeyword()
item["Keyword"] = keyword
item["replace"]["Keyword"] = "<code>{}</code>".format(keyword)

# Add methods
methods = obj.getMethods()
if methods:
Expand Down
5 changes: 5 additions & 0 deletions src/bika/lims/controlpanel/bika_analysisservices.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,11 @@ def folderitem(self, obj, item, index):
item["Department"] = title
item["replace"]["Department"] = get_link(url, title)

# Keyword
keyword = obj.getKeyword()
if keyword:
item["replace"]["Keyword"] = "<code>{}</code>".format(keyword)

# Unit
unit = obj.getUnit()
item["Unit"] = unit and format_supsub(unit) or ""
Expand Down
1 change: 1 addition & 0 deletions src/senaite/core/browser/samples/partition_magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ def get_analysis_data_for(self, ar):
info = self.get_base_info(an)
info.update({
"service_uid": an.getServiceUID(),
"keyword": an.getKeyword(),
})
out.append(info)
return out
Expand Down
30 changes: 20 additions & 10 deletions src/senaite/core/browser/samples/templates/partition_magic.pt
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,15 @@
checked python:service_uid in template.get('analyses', {}).get(partition, [])"/>
</td>
<td class="text-info">
<a class="overlay_panel me-1"
tal:attributes="href string:${ar/url}/analysisservice_info?service_uid=${analysis/service_uid}">
<i class="fas fa-info-circle"></i>
</a>
<span tal:content="analysis/title"/>
<span tal:condition="analysis/keyword"
tal:omit-tag="">
(<code tal:content="analysis/keyword"/>)
</span>
</td>
</tr>
</table>
Expand Down Expand Up @@ -272,16 +280,18 @@
</div>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", () => {
$(".partition-body").on("show.bs.collapse", function(event) {
let el = event.currentTarget;
let partition = el.dataset.partition;
$("#" + partition + "-toggle-icon").toggleClass("fa-caret-right fa-caret-down");
});
$(".partition-body").on("hide.bs.collapse", function(event) {
let el = event.currentTarget;
let partition = el.dataset.partition;
$("#" + partition + "-toggle-icon").toggleClass("fa-caret-down fa-caret-right");
});
// Toggle the caret icon when a partition is expanded/collapsed.
// Bind defensively (namespaced + off before on): opening a service
// info overlay re-dispatches DOMContentLoaded, which would
// otherwise stack duplicate handlers and cancel out the toggle.
$(".partition-body")
.off("show.bs.collapse.partition hide.bs.collapse.partition")
.on("show.bs.collapse.partition hide.bs.collapse.partition",
function(event) {
let partition = event.currentTarget.dataset.partition;
$("#" + partition + "-toggle-icon")
.toggleClass("fa-caret-right fa-caret-down");
});
});
</script>
</metal:core>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1343,8 +1343,11 @@ class window.AnalysisRequestAdd
name_el = $("div.service-title", $service)
name = name_el.html().toLowerCase()

# hide service if no match found and not checked for any sample
if name.indexOf(term) isnt -1
# get the service keyword
keyword = ($service.data("keyword") or "").toString().toLowerCase()

# match against the human name or the keyword
if name.indexOf(term) isnt -1 or keyword.indexOf(term) isnt -1
matches.push service_uid

return matches
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1590,16 +1590,18 @@ window.AnalysisRequestAdd = class AnalysisRequestAdd {
// iterate through all registered services to find matches
services = $(`tr.${poc}.service`);
$.each(services, function(num, service) {
var $service, category_id, name, name_el, service_uid;
var $service, category_id, keyword, name, name_el, service_uid;
// get the service basic info
$service = $(service);
category_id = $service.data("category");
service_uid = $service.data("uid");
// get the service human name
name_el = $("div.service-title", $service);
name = name_el.html().toLowerCase();
// hide service if no match found and not checked for any sample
if (name.indexOf(term) !== -1) {
// get the service keyword
keyword = ($service.data("keyword") || "").toString().toLowerCase();
// match against the human name or the keyword
if (name.indexOf(term) !== -1 || keyword.indexOf(term) !== -1) {
return matches.push(service_uid);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,17 @@ window.PartitionController = class PartitionController {

/**
* Handles click on analysis row
* If user clicks on anything other than a checkbox, the row's checkbox is toggled
* If the user clicks on an empty area of the row, the row's checkbox is
* toggled. Clicks on interactive elements (links, inputs, labels, e.g. the
* service info icon) are ignored, so they keep their own behavior.
*/
on_analysis_click(event) {
const $row = $(event.currentTarget);

if (event.target.type !== "checkbox") {
$row.find("input[type=checkbox]").trigger("click");
if ($(event.target).closest("a, input, button, select, label").length) {
return;
}

$row.find("input[type=checkbox]").trigger("click");
}
}
Loading