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

Allow manual reordering of report samples #135

Merged
merged 13 commits into from
Feb 14, 2023
1 change: 1 addition & 0 deletions docs/Changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
------------------

- #136 Change default browserlayer
- #135 Allow manual reordering of report samples
- #134 Convert impress header table to senaite.app.listing
- #133 Refactor publish view controls and content table to viewlets
- #132 Add custom action provider for direct PDF sharing via email
Expand Down
1 change: 1 addition & 0 deletions src/senaite/impress/ajax.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ def ajax_config(self):
"format": self.get_default_paperformat(),
"orientation": self.get_default_orientation(),
"template": self.get_default_template(),
"reload_after_reorder": self.get_reload_after_reorder(),
"allow_save": self.get_allow_publish_save(),
"allow_email": self.get_allow_publish_email(),
"custom_actions": custom_actions,
Expand Down
15 changes: 15 additions & 0 deletions src/senaite/impress/browser/publish/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def __init__(self, context, request):
self.show_workflow_action_buttons = False
self.show_table_footer = False
self.omit_form = True
self.allow_row_reorder = True

# Show categories
self.categories = []
Expand All @@ -49,6 +50,10 @@ def __init__(self, context, request):
"title": _("Sample Type"),
"sortable": False,
"toggle": True}),
("SamplePoint", {
"title": _("Sample Point"),
"sortable": False,
"toggle": True}),
("created", {
"title": _("Registered"),
"sortable": False,
Expand Down Expand Up @@ -185,6 +190,16 @@ def _folder_item_sample(self, obj, item):
return
item["SampleType"] = obj.getSampleTypeTitle()

# sample point
sp = obj.getSamplePoint()
if sp:
sp_id = api.get_id(sp)
sp_title = api.get_title(sp)
sp_url = api.get_url(sp)
item["SamplePoint"] = api.get_title(sp)
item["replace"]["SamplePoint"] = get_link(
sp_url, value=sp_title or sp_id, target="_blank")

client = obj.getClient()
client_url = api.get_url(client)
client_id = client.getClientID()
Expand Down

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/senaite/impress/browser/static/resources.pt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/jquery/jquery.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/popperjs/popper.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/bootstrap/js/bootstrap.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/react/react.production.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/react-dom/react-dom.production.min.js"></script><link href="#" rel="stylesheet" tal:attributes="href string:${view/site_url}/++plone++senaite.impress.static/modules/fontawesome-free/css/all.min.css"/><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/thirdparty/jquery-barcode-2.2.0.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/thirdparty/jquery-qrcode-0.17.0.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/thirdparty/d3.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/js/bika.lims.graphics.range.js"></script><link href="#" rel="stylesheet" tal:attributes="href string:${view/site_url}/++plone++senaite.impress.static/css/bootstrap.min.css"/><link href="#" rel="stylesheet" tal:attributes="href string:${view/site_url}/++plone++senaite.impress.static/css/bootstrap-print.css"/><link href="#" rel="stylesheet" tal:attributes="href string:${view/site_url}/++plone++senaite.impress.static/css/print.css"/><script tal:attributes="src string:${view/site_url}//++plone++senaite.impress.static/bundles/senaite.impress.js"></script><link href="#" rel="stylesheet" tal:attributes="href string:${view/site_url}//++plone++senaite.impress.static/bundles/senaite.impress.css"/>
<script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/jquery/jquery.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/popperjs/popper.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/bootstrap/js/bootstrap.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/bootstrap-confirmation2/bootstrap-confirmation.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/bootstrap-select/js/bootstrap-select.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/react/react.production.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/modules/react-dom/react-dom.production.min.js"></script><link href="#" rel="stylesheet" tal:attributes="href string:${view/site_url}/++plone++senaite.impress.static/modules/fontawesome-free/css/all.min.css"/><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/thirdparty/jquery-barcode-2.2.0.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/thirdparty/jquery-qrcode-0.17.0.min.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/thirdparty/d3.js"></script><script tal:attributes="src string:${view/site_url}/++plone++senaite.core.static/js/bika.lims.graphics.range.js"></script><link href="#" rel="stylesheet" tal:attributes="href string:${view/site_url}/++plone++senaite.impress.static/css/bootstrap.min.css"/><link href="#" rel="stylesheet" tal:attributes="href string:${view/site_url}/++plone++senaite.impress.static/css/bootstrap-print.css"/><link href="#" rel="stylesheet" tal:attributes="href string:${view/site_url}/++plone++senaite.impress.static/css/print.css"/><script tal:attributes="src string:${view/site_url}//++plone++senaite.impress.static/bundles/senaite.impress.js"></script><link href="#" rel="stylesheet" tal:attributes="href string:${view/site_url}//++plone++senaite.impress.static/bundles/senaite.impress.css"/>
8 changes: 8 additions & 0 deletions src/senaite/impress/controlpanel.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ class IImpressControlPanel(Interface):
required=False,
)

reload_after_reorder = schema.Bool(
title=_(u"Reload after reorder"),
description=_(u"Reload report automatically when items order changed"),
default=False,
required=False,
)

###
# Fieldsets
###
Expand All @@ -132,6 +139,7 @@ class IImpressControlPanel(Interface):
label=_(u"Advanced"),
# description=_(""),
fields=[
"reload_after_reorder",
"allow_pdf_download",
"allow_pdf_email_share",
"store_multireports_individually",
Expand Down
2 changes: 1 addition & 1 deletion src/senaite/impress/profiles/default/metadata.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<metadata>
<version>2403</version>
<version>2404</version>
</metadata>
11 changes: 10 additions & 1 deletion src/senaite/impress/publishview.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
from six.moves.collections_abc import Iterable

from bika.lims import api
from bika.lims.permissions import TransitionPublishResults
from plone.resource.utils import iterDirectoriesOfType
from Products.Five import BrowserView
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
Expand Down Expand Up @@ -407,6 +406,16 @@ def is_printview(self):
return True
return False

def get_reload_after_reorder(self, default=False):
"""Check if auto reloading after reordering is enabled
"""
# lookup configuration settings
reload_after_reorder = api.get_registry_record(
"senaite.impress.reload_after_reorder")
if reload_after_reorder is None:
return default
return reload_after_reorder

def get_allow_pdf_download(self, default=False):
"""Check if direct PDF download is allowed
"""
Expand Down
11 changes: 11 additions & 0 deletions src/senaite/impress/upgrades/v02_04_000.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-

from plone.browserlayer.utils import unregister_layer
from senaite.impress import logger

PROFILE_ID = "profile-senaite.impress:default"
Expand Down Expand Up @@ -32,5 +33,15 @@ def import_browserlayer(tool):
:param tool: portal_setup tool
"""
logger.info("Import SENAITE IMPRESS browser layer ...")

# ensure the old layer is removed first to make room for the new one
try:
unregister_layer("senaite.impress")
except KeyError:
# KeyError: 'No browser layer with name senaite.impress is registered
pass

# reimport browser layer to register ISenaiteImpressLayer
tool.runImportStepFromProfile(PROFILE_ID, "browserlayer")

logger.info("Import SENAITE IMPRESS browser layer [DONE]")
8 changes: 8 additions & 0 deletions src/senaite/impress/upgrades/v02_04_000.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,12 @@
handler="senaite.impress.upgrades.v02_04_000.import_browserlayer"
profile="senaite.impress:default"/>

<genericsetup:upgradeStep
title="SENAITE IMPRESS 2.4.0: Import registry"
description="Import registry profile for controlpanel settings"
source="2403"
destination="2404"
handler="senaite.impress.upgrades.v02_04_000.import_registry"
profile="senaite.impress:default"/>

</configure>
32 changes: 32 additions & 0 deletions webpack/app/senaite.impress.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class PublishController extends React.Component
@handleModalSubmit = @handleModalSubmit.bind(this)
@loadReports = @loadReports.bind(this)
@saveReports = @saveReports.bind(this)
@on_row_order_change = @on_row_order_change.bind(this)
# Rendered by the listing viewlet
@listing_el = document.getElementById("impress-contents-table")

@state =
items: @api.get_items()
Expand All @@ -59,6 +62,8 @@ class PublishController extends React.Component
allow_save: yes
allow_email: yes
custom_actions: []
reload_after_reorder: no
reload_required: no

window.impress = @

Expand All @@ -80,13 +85,18 @@ class PublishController extends React.Component

componentDidMount: ->
console.debug "PublishController::componentDidMount"
@listing_el.addEventListener("listing:row_order_change", @on_row_order_change, false);

@api.fetch_config().then (
(config) ->
@setState config, @loadReports
).bind(this)


componentWillUnmount: ->
@listing_el.removeEventListener("listing:row_order_change", @on_row_order_change, false);


getRequestOptions: ->
###
* Options to be sent to the server
Expand Down Expand Up @@ -134,6 +144,7 @@ class PublishController extends React.Component
error: ""
loading: yes
loadtext: "Loading Reports..."
reload_required: no

# fetch the rendered reports via the API asynchronously
promise = @api.render_reports @getRequestOptions()
Expand Down Expand Up @@ -438,9 +449,30 @@ class PublishController extends React.Component
return @postAction url


###
* Event handler when the object order was changed in the listing table
*
* @param {CustomEvent} event: provides the current `folderitems` of the listing
###
on_row_order_change: (event) ->
uids = event.detail.folderitems.map (item) => item.uid

if @state.reload_after_reorder
@setState items: uids, @loadReports
else
@setState items: uids, reload_required: yes


render: ->
<div className="col-sm-12">
<Modal className="modal fade" id="impress_modal" />
{@state.reload_required and
<div className="alert alert-warning">
<h4 className="alert-heading">
<span className="mr-2">Reload is required</span>
<Button name="reload" title="↺" onClick={@loadReports} className="btn btn-sm btn-outline-success" />
</h4>
</div>}
<form name="publishform" onSubmit={this.handleSubmit}>
<div className="form-group">
<div className="input-group">
Expand Down