forked from senaite/senaite.impress
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Convert impress header table to senaite.app.listing (senaite#134)
* Moved static folder -> browser/static * Moved resources viewlet class to viewlets package * Refactored publish view to viewlets * Webpack config * Removed senaite.app.listing * Changelog updated * Added needed JS libraries for listing * Registered viewlet for senaite.app.listing resources * Added methods to retrieve listing view * Added listing view for impress contents * WIP for content listing * Removed package include * Changelog updated * Changed layer interface * Removed i18n attributes * Converted content table to senaite.app.listing * Updated view class * Changelog updated
- Loading branch information
Showing
9 changed files
with
279 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<configure | ||
xmlns="http://namespaces.zope.org/zope" | ||
xmlns:browser="http://namespaces.zope.org/browser"> | ||
|
||
<!-- Listing view for publish contents --> | ||
<browser:page | ||
for="*" | ||
name="publish_content_listing" | ||
class=".content.ContentListingView" | ||
permission="zope2.View" | ||
layer="senaite.impress.interfaces.ILayer" | ||
/> | ||
|
||
</configure> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
from collections import OrderedDict | ||
|
||
from six.moves import urllib | ||
|
||
from bika.lims import api | ||
from bika.lims import senaiteMessageFactory as _ | ||
from bika.lims.interfaces import IAnalysisRequest | ||
from bika.lims.utils import get_link | ||
from bika.lims.utils import get_link_for | ||
from bika.lims.utils import t | ||
from senaite.app.listing import ListingView | ||
from senaite.core.api import dtime | ||
|
||
|
||
class ContentListingView(ListingView): | ||
"""Listing table of selected UIDs | ||
""" | ||
def __init__(self, context, request): | ||
super(ContentListingView, self).__init__(context, request) | ||
|
||
self.pagesize = 9999 | ||
self.context_actions = {} | ||
self.show_search = False | ||
self.show_select_column = False | ||
self.show_workflow_action_buttons = False | ||
self.show_table_footer = False | ||
self.omit_form = True | ||
|
||
# Show categories | ||
self.categories = [] | ||
self.show_categories = True | ||
self.expand_all_categories = False | ||
|
||
self.columns = OrderedDict(( | ||
# Although 'created' column is not displayed in the list (see | ||
# review_states to check the columns that will be rendered), this | ||
# column is needed to sort the list by create date | ||
("id", { | ||
"title": _("ID"), | ||
"sortable": False, | ||
"toggle": True}), | ||
("title", { | ||
"title": _("Title"), | ||
"sortable": False, | ||
"toggle": True}), | ||
("SampleType", { | ||
"title": _("Sample Type"), | ||
"sortable": False, | ||
"toggle": True}), | ||
("created", { | ||
"title": _("Registered"), | ||
"sortable": False, | ||
"toggle": False}), | ||
("DateSampled", { | ||
"title": _("Date Sampled"), | ||
"sortable": False, | ||
"toggle": True}), | ||
("Client", { | ||
"title": _("Client"), | ||
"sortable": False, | ||
"toggle": True}), | ||
("ClientID", { | ||
"title": _("Client ID"), | ||
"sortable": False, | ||
"toggle": True}), | ||
("Contact", { | ||
"title": _("Contact"), | ||
"sortable": False, | ||
"toggle": True}), | ||
("BatchID", { | ||
"title": _("Batch ID"), | ||
"sortable": False, | ||
"toggle": True}), | ||
("review_state", { | ||
"title": _("Workflow State ID"), | ||
"sortable": False, | ||
"toggle": False}), | ||
("state", { | ||
"title": _("Workflow State"), | ||
"sortable": False, | ||
"toggle": True}), | ||
)) | ||
|
||
self.review_states = [ | ||
{ | ||
"id": "default", | ||
"title": _("All"), | ||
"contentFilter": {}, | ||
"transitions": [], | ||
"custom_transitions": [], | ||
"columns": self.columns.keys() | ||
} | ||
] | ||
|
||
def get_uids(self): | ||
"""Parse the UIDs from the query string | ||
NOTE: | ||
This listing view is called asynchronously with a new HTTP POST request | ||
from senaite.app.listing (see JS: api.get_json) | ||
Therefore, the original `?items` request parameter is contained only in | ||
the request QUERY_STRING, but no longer in the form data, because there | ||
we have only the payload from the POST request | ||
XXX: This might be better done in senaite.app.listing | ||
""" | ||
uids = [] | ||
qs = self.request.get_header("query_string", "") | ||
params = urllib.parse.parse_qs(qs) | ||
items = params.get("items", []) | ||
for item in items: | ||
uids.extend(filter(api.is_uid, item.split(","))) | ||
return uids | ||
|
||
def make_empty_item(self, **kw): | ||
"""Create a new empty item | ||
""" | ||
item = { | ||
"uid": None, | ||
"before": {}, | ||
"after": {}, | ||
"replace": {}, | ||
"allow_edit": [], | ||
"disabled": False, | ||
"state_class": "state-active", | ||
} | ||
item.update(**kw) | ||
return item | ||
|
||
def folderitems(self): | ||
items = [] | ||
for num, uid in enumerate(self.get_uids()): | ||
obj = api.get_object(uid) | ||
# create base folderitem | ||
item = self.make_empty_item(**{ | ||
"uid": uid, | ||
"id": api.get_id(obj), | ||
"title": api.get_title(obj), | ||
"replace": { | ||
"id": get_link_for(obj), | ||
} | ||
}) | ||
|
||
# append workflow info | ||
self._folder_item_workflow(obj, item) | ||
# append sample specific info | ||
self._folder_item_sample(obj, item) | ||
|
||
items.append(self.folderitem(obj, item, num)) | ||
|
||
return items | ||
|
||
def folderitem(self, obj, item, index): | ||
"""Render a row in the listing | ||
""" | ||
return item | ||
|
||
def _folder_item_workflow(self, obj, item): | ||
"""Add workflow information to the item | ||
""" | ||
state = "Active" | ||
review_state = "active" | ||
|
||
wf_tool = api.get_tool("portal_workflow") | ||
wfs = wf_tool.getWorkflowsFor(obj) | ||
|
||
for wf in wfs: | ||
review_state = wf.getInfoFor(obj, wf.state_var, "") | ||
sdef = wf.states.get(review_state) | ||
state = sdef.title | ||
break | ||
|
||
item["state"] = t(state) | ||
item["review_state"] = review_state | ||
item["state_class"] = "state-{}".format(review_state) | ||
|
||
def _folder_item_sample(self, obj, item): | ||
"""Add sample specific information | ||
""" | ||
if not IAnalysisRequest.providedBy(obj): | ||
return | ||
item["SampleType"] = obj.getSampleTypeTitle() | ||
|
||
client = obj.getClient() | ||
client_url = api.get_url(client) | ||
client_id = client.getClientID() | ||
client_name = client.getName() | ||
|
||
# Categorize objects by client name | ||
item["category"] = client_name | ||
if client_name not in self.categories: | ||
self.categories.append(client_name) | ||
|
||
# Client Name | ||
item["Client"] = client_name | ||
item["replace"]["Client"] = get_link( | ||
client_url, value=client_name, target="_blank") | ||
|
||
# Client ID | ||
item["ClientID"] = client.getClientID() | ||
item["replace"]["ClientID"] = get_link( | ||
client_url, value=client_id, target="_blank") | ||
|
||
# Client Contact | ||
contact = obj.getContact() | ||
if contact: | ||
contact_url = api.get_url(contact) | ||
contact_name = contact.getFullname() | ||
item["Contact"] = contact.getFullname() | ||
item["replace"]["Contact"] = get_link( | ||
contact_url, value=contact_name, target="_blank") | ||
|
||
# Date Sampled | ||
date_created = obj.created() | ||
date_sampled = obj.getDateSampled() | ||
item["created"] = dtime.to_localized_time( | ||
date_created, long_format=True, | ||
context=self.context, request=self.request) | ||
item["DateSampled"] = dtime.to_localized_time( | ||
date_sampled, long_format=True, | ||
context=self.context, request=self.request) | ||
|
||
# Batch | ||
batch = obj.getBatch() | ||
if batch: | ||
batch_id = batch.getId() | ||
batch_url = api.get_url(batch) | ||
item["BatchID"] = batch.getId() | ||
item["replace"]["BatchID"] = get_link( | ||
batch_url, value=batch_id, target="_blank") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.