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

Moved Setup View into Core #1515

Merged
merged 4 commits into from
Feb 3, 2020
Merged
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 @@ -7,6 +7,7 @@ Changelog

**Added**

- #1515 Moved Setup View into Core
- #1506 Specification non-compliant viewlet in Sample
- #1506 Sample results ranges out-of-date viewlet in Sample
- #1506 Warn icon in analyses when range is not compliant with Specification
Expand Down
86 changes: 86 additions & 0 deletions bika/lims/browser/controlpanel.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,96 @@
# Copyright 2018-2020 by it's authors.
# Some rights reserved, see README and LICENSE.

import os

from bika.lims.utils import t
from plone.app.controlpanel.overview import OverviewControlPanel
from plone.memoize.volatile import cache
from plone.memoize.volatile import store_on_context
from Products.Five.browser import BrowserView
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from bika.lims import api


def modified_cache_key(method, self, brain_or_object):
"""A cache key that returns the millis of the last modification time
"""
return api.get_modification_date(brain_or_object).millis()


class SenaiteOverviewControlPanel(OverviewControlPanel):
"""Bootstrapped version of the standard Plone Control Panel
"""
template = ViewPageTemplateFile(
"templates/plone.app.controlpanel.overview.pt")


class SetupView(BrowserView):
"""Ordered overview of all Setup Items
"""
template = ViewPageTemplateFile("templates/setupview.pt")

def __init__(self, context, request):
self.context = context
self.request = request

def __call__(self):
self.request.set("disable_border", 1)
return self.template()

@property
def portal(self):
"""Returns the Portal Object
"""
return api.get_portal()

@property
def setup(self):
"""Returns the Senaite Setup Object
"""
return api.get_setup()

@cache(modified_cache_key, store_on_context)
def get_icon_url(self, brain):
"""Returns the (big) icon URL for the given catalog brain
"""
icon_url = api.get_icon(brain, html_tag=False)
url, icon = icon_url.rsplit("/", 1)
relative_url = url.lstrip(self.portal.absolute_url())
name, ext = os.path.splitext(icon)

# big icons endwith _big
if not name.endswith("_big"):
icon = "{}_big{}".format(name, ext)

icon_big_url = "/".join([relative_url, icon])

# fall back to a default icon if the looked up icon does not exist
if self.context.restrictedTraverse(icon_big_url, None) is None:
icon_big_url = "++resource++bika.lims.images/gears.png"

return icon_big_url

def setupitems(self):
"""Lookup available setup items

:returns: catalog brains
"""
query = {
"path": {
"query": api.get_path(self.setup),
"depth": 1,
},
}
items = api.search(query, "portal_catalog")
# filter out items
items = filter(lambda item: not item.exclude_from_nav, items)

# sort by (translated) title
def cmp_by_translated_title(brain1, brain2):
title1 = t(api.get_title(brain1))
title2 = t(api.get_title(brain2))
# XXX: Python 3 compatibility
return cmp(title1, title2)

return sorted(items, cmp=cmp_by_translated_title)
8 changes: 8 additions & 0 deletions bika/lims/browser/controlpanel.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,12 @@
permission="plone.app.controlpanel.Overview"
layer="bika.lims.interfaces.IBikaLIMS"/>

<!-- SENAITE Setup View -->
<browser:page
name="lims-setup"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
class=".controlpanel.SetupView"
permission="senaite.core.permissions.ManageBika"
layer="bika.lims.interfaces.IBikaLIMS"/>

</configure>
32 changes: 32 additions & 0 deletions bika/lims/browser/css/setupview.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* CSS Styles for the SENAITE Setup View*/
.vcenter {
display: inline-block;
vertical-align: middle;
float: none;
}
.tile {
width: 100%;
height: 6em;
box-sizing: border-box;
display: inline-block;
background: #d9edf7;
padding: 2em;
margin: auto auto 1em auto;
overflow: hidden;
}
.tile .title {
text-transform: uppercase;
font-weight: bold;
text-overflow: ellipsis;
overflow: hidden;
}
.tile:hover {
background: #d9edff;
text-decoration: none;
}
.tile.setup {
background: #ddd;
}
.tile.setup:hover {
background: #aaa;
}
Binary file added bika/lims/browser/images/gears.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
85 changes: 85 additions & 0 deletions bika/lims/browser/templates/setupview.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
lang="en"
metal:use-macro="here/prefs_main_template/macros/master"
i18n:domain="senaite.core">

<head>
<metal:block fill-slot="javascript_head_slot"
tal:define="portal context/@@plone_portal_state/portal;">
</metal:block>

<metal:block fill-slot="style_slot"
tal:define="portal context/@@plone_portal_state/portal;">
<!-- Link in the Setup CSS -->
<link href="++resource++bika.lims.css/setupview.css" rel="stylesheet">
</metal:block>

</head>
<body>

<metal:override fill-slot="top_slot"
tal:define="disable_column_one python:request.set('disable_plone.leftcolumn', 1);
disable_column_two python:request.set('disable_plone.rightcolumn', 1);"/>

<div metal:fill-slot="prefs_configlet_main" id="lims-controlpanel">

<div class="row">

<!-- The setup item -->
<tal:setup tal:define="setup python:view.setup">
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3">
<a class="tile setup text-capitalized"
tal:attributes="href setup/absolute_url">

<div class="row item">
<div class="col-xs-2 vcenter">
<img src="#"
class="icon"
tal:attributes="src python:view.get_icon_url(setup);
title setup/Title"/>
</div>
<div class="col-xs-9 vcenter">
<div class="title"
i18n:translate=""
tal:content="setup/Title">
Setup Item Title
</div>
</div>
</div>
</a>
</div>
</tal:setup>

<!-- The other setup items -->
<tal:tiles tal:repeat="brain view/setupitems">
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3">
<a class="tile text-capitalized"
tal:attributes="href brain/getURL">

<div class="row item">
<div class="col-xs-2 vcenter">
<img src="#"
class="icon"
tal:attributes="src python:view.get_icon_url(brain);
title brain/Title"/>
</div>
<div class="col-xs-9 vcenter">
<div class="title"
i18n:translate=""
tal:content="brain/Title">
Setup Item Title
</div>
</div>
</div>
</a>
</div>
</tal:tiles>
</div>

</div>

</body>
</html>
9 changes: 9 additions & 0 deletions bika/lims/browser/viewlets/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
xmlns:browser="http://namespaces.zope.org/browser"
i18n_domain="senaite.core">

<!-- Setup Button Viewlet -->
<browser:viewlet
name="senaite.setupbutton"
manager="plone.app.layout.viewlets.interfaces.IPortalHeader"
class=".setupbutton.SenaiteSetupButtonViewlet"
permission="senaite.core.permissions.ManageBika"
layer="bika.lims.interfaces.IBikaLIMS"
/>

<!-- Content Views Viewlet (Tabs) -->
<browser:viewlet
name="plone.contentviews"
Expand Down
6 changes: 4 additions & 2 deletions bika/lims/browser/viewlets/instruments.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,11 @@ def get_failed_instruments(self):
def available(self):
"""Control availability of the viewlet
"""
url = api.get_url(self.context)
context_state = api.get_view("plone_context_state")
url = context_state.current_page_url()
portal_url = api.get_url(api.get_portal())
# render on the portal root
if self.context == api.get_portal():
if url.endswith(portal_url):
return True
# render on the front-page
if url.endswith("/front-page"):
Expand Down
35 changes: 35 additions & 0 deletions bika/lims/browser/viewlets/setupbutton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
#
# This file is part of SENAITE.LIMS.
#
# SENAITE.LIMS is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright 2018-2019 by it's authors.
# Some rights reserved, see README and LICENSE.

from bika.lims import api
from plone.app.layout.viewlets.common import ViewletBase
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile


class SenaiteSetupButtonViewlet(ViewletBase):
"""Renders a Button to navigate to the Setup View
"""
index = ViewPageTemplateFile("templates/setupbutton.pt")

def update(self):
super(SenaiteSetupButtonViewlet, self).update()
self.portal = api.get_portal()
portal_url = self.portal.absolute_url()
self.setup_url = "/".join([portal_url, "@@lims-setup"])
14 changes: 14 additions & 0 deletions bika/lims/browser/viewlets/templates/setupbutton.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!-- SENAITE Setup Button Viewlet -->
<div id="senaite-setupbutton"
class=" pull-right"
style="padding-left: 1em;"
i18n:domain="senaite.core">

<a class="btn btn-default" type="button"
tal:attributes="href view/setup_url">
<span tal:omit-tag="" i18n:translate="">
<span class="glyphicon glyphicon-cog" aria-hidden="true"></span>
</span>
</a>

</div>