changeset 7971:fe0348bbe45b

issue2551353 - Add roundup-classhelper for 2.4.0 release Changes to the classic template are not done yet. Still testing. This commit has document updates and changes to rest.py. rest.py: add /rest/data/user/role endpoint to core so the user doesn't have to add the /rest/roles endpoint via interfaces.py. It will only send roles for a user with Admin role and there is no way to override this currently. acknowledgements.txt: Added members of team3 to other contributors. Specified for all other contributes what they worked on. upgrading.txt: added classhelper section and basic template change directions. Linked to admin_guide for full directions. admin_guide.txt: documented install, translation, troubleshooting, config etc. user_guide.txt: added section on using the classhelper. Added reference to section earlier in the doc. Added image for section.
author John Rouillard <rouilj@ieee.org>
date Tue, 21 May 2024 01:17:28 -0400
parents b63fcfc2c984
children 425dd9854e34
files doc/acknowledgements.txt doc/admin_guide.txt doc/images/classhelper-issue-all.png doc/upgrading.txt doc/user_guide.txt roundup/rest.py
diffstat 6 files changed, 465 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/doc/acknowledgements.txt	Sat May 18 21:28:05 2024 -0400
+++ b/doc/acknowledgements.txt	Tue May 21 01:17:28 2024 -0400
@@ -32,7 +32,10 @@
 
 Other contributers
 
-Norbert Schlemmer
+Norbert Schlemmer - docker support
+
+Bharath Kanama, Nikunj Thakkar, Patel Malav - classhelper web
+component development.
 
 2.3
 ---
--- a/doc/admin_guide.txt	Sat May 18 21:28:05 2024 -0400
+++ b/doc/admin_guide.txt	Tue May 21 01:17:28 2024 -0400
@@ -514,6 +514,323 @@
 
 .. _CSP: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
 
+Classhelper Web Component
+=========================
+
+Version 2.4.0 provides a new classhelper popup written as a
+web component. By installing 3 files and adding a stanza to
+``interfaces.py`` you can enable the new component.
+
+The `development of this component was done by team-03
+<https://github.com/UMB-CS-682-Team-03/tracker>`_ of the
+Spring 2024 CS682 graduate software engineering SDL capstone
+class at the University of Massachusetts - Boston. Their
+documentation is copied/adapted below.
+
+File Installation
+-----------------
+
+There are three files to install in your tracker. You can
+copy them from the template directory for the classic
+tracker. The location of the template file can be obtained
+by running: ``roundup-admin templates`` and looking for the
+path value of the classic template. If the path value is
+``/path/to/template``, copy::
+
+ /path/to/template/html/classhelper.js
+ /path/to/template/html/classhelper.css
+ /path/to/template/html/_generic.translation
+
+to your tracker's html directory.
+
+.. :
+    remove in 2.5 release if /data/user/roles endpoint
+    in rest.py is successful.
+
+    If you wish to search for user's by role, you have to do one more
+    step. Because roles are not an actual class (e.g. like status or
+    keyword), you have to set up a new REST endpoint for them. To do this,
+    copy::
+
+
+      from roundup.rest import Routing, RestfulInstance, _data_decorator
+
+      class RestfulInstance:
+
+	  @Routing.route("/roles", 'GET')
+	  @_data_decorator
+	  def get_roles(self, input):
+	      """Return all defined roles. The User class property
+		 roles is a string but simulate it as a MultiLink
+		 to an actual Roles class.
+	      """
+	      return 200, {"collection":
+		  [{"id": rolename,"name": rolename}
+		      for rolename in list(self.db.security.role.keys())]}
+
+    into the file ``interfaces.py`` in your tracker's home
+    directory. You can create this file if it doesn't exist.
+    See the `REST documentation <rest.html>`_ for details on
+    ``interfaces.py``.
+
+    The classic tracker does not have the ``/roles`` REST endpoint
+    configured. If you are creating a new tracker from the classic
+    template, it will show a text based search not a select/dropdown based
+    search. By modifying interfaces.py you will enable a dropdown search.
+
+Wrapping the Classic Classhelper
+--------------------------------
+
+To allow your users to select items in the web interface
+using the new classhelper, you should edit the template files
+in the ``html/`` subdirectory of your tracker. Where you see
+code like::
+
+ <th i18n:translate="">Superseder</th>
+  <td>
+    <span tal:replace="structure
+          python:context.superseder.field(showid=1,size=20)" />
+    <span tal:condition="context/is_edit_ok"
+	  tal:replace="structure
+	               python:db.issue.classhelp('id,title',
+		       property='superseder', pagesize=100)" />
+     [...]
+ </td>
+
+change it to wrap the classhelp span like this::
+
+ <th i18n:translate="">Superseder</th>
+  <td>
+    <span tal:replace="structure
+          python:context.superseder.field(showid=1,size=20)" />
+    <roundup-classhelper
+      data-popup-title="Superseder Classhelper - {itemDesignator}"
+      data-search-with="title,status,keyword[]-name">
+      <span tal:condition="context/is_edit_ok"
+	    tal:replace="structure
+                         python:db.issue.classhelp('id,title',
+                         property='superseder', pagesize=100)" />
+    </roundup-classhelper>
+     [...]
+ </td>
+
+which displays a three part classhelper.
+
+  1. the search pane includes a text search box for the `title`
+     and `status` properties and a dropdown for the keyword property,
+     sorted by name in descending order.
+  2. the selection pane will show 100 search results per page.
+     It also allows the user to move to the next or previous result
+     page.
+  3. the accumulator at the bottom shows all the selected items. It
+     also has buttons to accept the items or cancel the
+     classhelper, leaving the original page unchanged.
+
+Note that the user class is a little different because users without
+an Admin role can't search for a user by Role. So we hide the Role
+search element for non admin users. Starting with::
+
+  <th i18n:translate="">Nosy List</th>
+  <td>
+    <span tal:replace="structure context/nosy/field" />
+    <span tal:condition="context/is_edit_ok" tal:replace="structure
+	  python:db.user.classhelp('username,realname,address',
+	  property='nosy', width='600'" />
+  </td>
+
+wrap the classhelp span with ``<roundup-classhelper>`` like::
+
+  <th i18n:translate="">Nosy List</th>
+  <td>
+    <span tal:replace="structure context/nosy/field" />
+    <roundup-classhelper tal:define="search string:name,phone,roles[]"
+			 tal:attributes="data-search-with python:search
+			 if request.user.hasRole('Admin') else
+			 ','.join(search.split(',')[:-1])">
+      <span tal:condition="context/is_edit_ok" tal:replace="structure
+	    python:db.user.classhelp('username,realname,address',
+	    property='nosy', width='600'" />
+    </roundup-classhelper>
+  </td>
+
+The ``','.join(search.split(',')[:-1])`` removes the last element of
+the search string (``roles[]``) if the user does not have the Admin
+role.
+
+<roundup-classhelper> configuration
+-----------------------------------
+
+There are two attributes used to configure the classhelper.
+
+data-popup-title:
+  * this attribute is optional. A reasonable default is
+    provided if it is missing.
+  * Adding ``data-popup-title`` changes the title of the popup
+    window with the value of the attribute.
+  * ``{itemDesignator}`` can be used inside the attribute value
+    to replace it with the current classhelper usage context.
+    E.G. ``data-popup-title="Nosy List Classhelper - {itemDesignator}"``
+    will display the popup window title as ``Nosy List Classhelper - issue24``
+
+data-search-with:
+  * this attribute is optional. If it is not set, a search
+    panel is not created provided to allow the users search
+    within the class.
+  * Adding ``data-search-with`` specifies the fields that can
+    be used for searching.
+    E.G. ``data-search-with="title,status,keyword"``
+  * The search can be customized using the following syntax:
+
+    * Adding ``[]`` at then end of a field (``"status[]"``)
+      will displays a dropdown for the "status" field
+      listing all the values the user can access. E.G.::
+
+         <roundup-classhelper
+             data-search-with="title,status[],keyword[]">
+           <span tal:condition="context/is_edit_ok"
+             tal:replace="structure
+             python:db.issue.classhelp('id,title',
+             property='superseder', pagesize=100)" />
+         </roundup-classhelper>
+
+      will create a search pane with a text search for title
+      and dropdowns for status and keyword.
+
+    * Adding a sort key after the ``[]`` allows you to
+      select the order of the elements in the dropdown. For
+      example ``keyword[]+name`` sorts the keyword
+      dropdown in ascending order by name. While
+      ``keyword[]-name`` sorts the keyword dropdown in
+      descending order by name. If the sort order is not
+      specified, the default order for the class is used.
+
+.. :
+    remove in 2.5 release if /data/user/roles endpoint
+    in rest.py is successful.
+
+    * Note that the ``roles`` field for the user class is
+      special. If you have not modified ``interfaces.py``,
+      roles can not be displayed as a dropdown. It will be
+      displayed as a text search field instead.
+
+<roundup-classhelper> styling
+-----------------------------
+
+The roundup-classhelper component uses minimal styling so it
+can blend in with most trackers. If you want to change the
+styling, you can modify the classhelper.css file in the html
+directory. Even though roundup-classhelper is a web
+component, it doesn't use the shadow DOM. If you don't know
+what this means, it just means that it's easy to style.
+
+There is on trick however. Getting the web component to load
+changes to the css file is a bit tricky. Basically the
+browser caches the old file and you have to resort to tricks
+to make it get a new copy of the file.
+
+One way to do this is to open to the ``classhelper.css``
+file in your browser and force refresh it. To do this:
+
+   1. Open the home page for your Roundup issue tracker in a
+      web browser.
+
+   2. In the address bar, append ``@@file/classhelper.css``
+      to the end of your Roundup URL. For example, if your
+      Roundup URL is ``https://example.com/tracker/``, the
+      URL you should visit would be
+      ``https://example.com/tracker/@@file/classhelper.css``.
+
+   3. This will open the `classhelper.css` file in your browser.
+
+   4. Press ``Ctrl+Shift+R`` (on Windows and Linux) or
+      ``Cmd+Shift+R`` (on macOS). This triggers a hard
+      refresh of the page, which forces the browser to
+      reload the file and associated resources from the
+      server.
+
+This should resolve any issues caused by cached or outdated
+files. It is possible that you have to open devtools and set
+the disable cache option in the network panel in extreme
+cases.
+
+Also during development, you might want to `set a very low
+cache time
+<customizing.html#changing-cache-control-headers>`_ for
+classhelper.css using something like::
+
+   Client.Cache_Control['classhelper.css'] = "public, max-age=10"
+
+
+Translations
+------------
+
+To set up translations for the <roundup-classhelper>
+component, follow these steps.
+
+  1. Create a ``messages.pot`` file by running
+     ``roundup-gettext <tracker_home_directory>``. This
+     creates ``locale/messages.pot`` in your tracker's home
+     directory. It extracts all translatable strings from
+     your tracker. We will use it as a base template for the
+     new strings you want to translate.
+  2. See if you already have a ``.po`` translation file for
+     your language in the tracker's locale/ directory. If you
+     don't, copy ``messages.pot`` to a .po file for the
+     language you want to translate. For example German
+     would be at ``de.po`` English would be at ``en.po``
+     (for example if you want to change the ``apply`` button
+     to say ``Do It``.
+
+  3. Edit the new .po file. After the header, add the
+     translation entries for the <roundup-classhelper>
+     component. For example `next` and `submit` are
+     displayed in English when the rest of the interface is
+     in German. Add::
+
+        msgid "submit"
+        msgstr "gehen"
+
+        msgid "next"
+        msgstr "nächste"
+
+        msgid "name"
+        msgstr "name"
+
+     Note: the value for `msgid` is case sensitive. You can
+     see the msgid for static strings by looking for
+     ``CLASSHELPER_TRANSLATION_KEYWORDS`` in classhelper.js.
+
+  4. Save the .po file.
+
+  5. Restart your Roundup instance.
+
+This should display the missing translations, for more
+details refer to the `translation (i18n) section of the
+developers documentation
+<developers.html#extracting-translatable-messages>`_.
+
+Troubleshooting
+---------------
+
+The roundup-classhelper will fallback to using the classic
+classhelper if:
+
+  * the user doesn't have REST access
+  * the browser doesn't support web components
+
+It will display an alert modal dialog to the user before triggering
+the classic classhelper as a fallback. A detailed error will be
+printed to the browser console. The console is visible in devtools and
+can be opened by pressing the ``F12`` key.
+
+You can disable the classhelper on a per URL basis by adding
+``#classhelper-wc-toggle`` to the end of the URL. This will prevent
+the web component from starting up.
+
+Also you can set ``DISABLE_CLASSHELP = true`` at the top of
+classhelper.js to disable the classhelper without having to make any
+changes to your templates.
+
 Configuring native-fts Full Text Search
 =======================================
 
Binary file doc/images/classhelper-issue-all.png has changed
--- a/doc/upgrading.txt	Sat May 18 21:28:05 2024 -0400
+++ b/doc/upgrading.txt	Tue May 21 01:17:28 2024 -0400
@@ -250,6 +250,44 @@
 .. _issue2551282: https://issues.roundup-tracker.org/issue2551282
 .. _issue2551115: https://issues.roundup-tracker.org/issue2551115
 
+Add new classhelper to your templates (optional)
+------------------------------------------------
+
+The classic classhelper invoked by the ``(list)`` link in your
+issue.item.html template can be greatly improved by wrapping the
+links with the new web-component based ``roundup-classhelper``.
+
+The new classhelper:
+
+  * allows you to select items from multiple pages
+  * is usable with a content security policy
+  * is more easily styled
+  
+To deploy it, install the required files and wrap classhelp calls
+in the new ``<roundup-classhelper>`` component. For example,
+wrap::
+
+  <span tal:condition="context/is_edit_ok" tal:replace="structure
+     python:db.user.classhelp('username,realname,address',
+     property='nosy', width='600'" />
+
+so it looks like::
+
+    <roundup-classhelper
+      data-search-with="username,phone,roles[]">
+
+      <span tal:condition="context/is_edit_ok" tal:replace="structure
+         python:db.user.classhelp('username,realname,address',
+         property='nosy', width='600')" />
+
+    </roundup-classhelper>
+
+to allow the user to search by: username, phone number and use a
+select/dropdown to search by role. Full details about the
+attributes and installation instructions can be found in the
+`classhelper documentation`_ in the admin guide.
+
+
 Disable performance improvement for wsgi mode (optional)
 --------------------------------------------------------
 
@@ -2606,6 +2644,7 @@
 .. _PostgreSQL's full text search: https://www.postgresql.org/docs/current/textsearch.html
 .. _`administration guide notes on native-fts`: admin_guide.html#configuring-native-fts-full-text-search
 .. _Configuring Compression: admin_guide.html#configuring-compression
+.. _classhelper documentation: admin_guide.html#classhelper-web-component
 .. _Software Upgrade: admin_guide.html#software-upgrade
 .. _new search permissions for query in 1.4.17:
    upgrading-history.html#new-search-permissions-for-query-in-1-4-17
--- a/doc/user_guide.txt	Sat May 18 21:28:05 2024 -0400
+++ b/doc/user_guide.txt	Tue May 21 01:17:28 2024 -0400
@@ -155,6 +155,10 @@
 ``keyword=-1``
   match issues with no keywords set
 
+When entering the value for a constrained property you may have a
+helper (also called classhelper) available by clicking on a link
+usally displayed as ``(list)``. See the section `Using the
+Classhelper`_ for details.
 
 Date properties
 ~~~~~~~~~~~~~~~
@@ -440,6 +444,92 @@
 
 .. _`documentation for configuring the native-fts`: admin_guide.html#configuring-native-fts-full-text-search
 
+Using the Classhelper
+---------------------
+
+The classhelper makes finding the id number or name for linked items
+easier.  It is usually invoked from the parent window by clicking on
+the ``(list)`` link. There are two classhelpers: classic and
+component. This documentation discusses the newer component
+classhelper available with Roundup 2.4.0 or newer. If there is a
+problem with the component classhelper, it reports the problem and
+falls back to using the classic classhelper.
+
+The component classhelper is displayed in a popup window. You can
+interact with the original window by moving the popup out of the way
+or minimizing it. If you don't see a popup, check to see if your
+browser has disabled popup windows.
+
+The classhelper has three parts:
+
+ 1. an optional search pane
+ 2. a selection pane
+ 3. an accumulator pane
+
+.. image:: images/classhelper-issue-all.png
+   :width: 675
+   :height: 914
+   :alt: Image of the new component classhelper popup. The image shows
+         the operating system window decorations with a title of "Superseder
+	 Classhelper - issue2". Then it shows a search panel with options to
+	 enter text to search issue titles or status and a select/dropdown
+	 to search by a keyword on the issue. Below the options are search
+	 and reset buttons. Below the search panel is a selection
+	 panel that shows buttons to move to the previous or next pages and
+	 says that it is displaying items 26 to 50. This is followed by a
+	 scrollable table of issues where each row has a checkbox and the
+	 box for issue 114 is checked. At the bottom of the window is a text
+	 box that lists a number of issue numbers including 114. To the
+	 right of the text box are apply and cancel buttons.
+
+
+The search pane has text or select/dropdown fields to search for a
+matching item. The image above shows a search for issues. The Title
+and Status properties can be matched using a text input while the
+Keyword property can be selected from a dropdown. Hitting enter while
+in a text input will trigger a search and the results will be
+displayed below the search pane in the selection pane. Tabbing to the
+search button and pressing enter will also trigger a search. The reset
+button will clear the search form.
+
+Below the search pane is the select pane. It lists the number of items
+displayed (26-50) and includes two buttons to move to the previous or
+next page of search results. If there is no search pane, this will
+display a page of items from all the items in the class. Below the
+pagination component is the scrollable selection table. Each row in
+the table has a checkbox and one or more columns of data about the
+item.  Clicking on a row toggles the item's checkbox and adds or
+removes the id or name for the item in the accumulator's
+display. Arrow keys or tab/shift-tab can be used to scroll through
+each item in the selection table. The space key or enter will
+select/deselect the item. You can jump to the page controls using the
+'<' and '>' keys. Once the page control button is focused, press enter
+to trigger a page change.
+
+The bottom pane consists of a text input called the accumulator
+display. It lists all the items that have been selected. The first two
+items in this example were selected from the previous selection
+page. Next to the display are the apply and cancel buttons. You can
+jump to the apply button quickly by pressing Shift-Enter as long as
+you are not in a search input. Once the apply button is focused, press
+enter to copy the items in the display to the associated field on the
+parent window. If you activate the cancel button or close the window
+using the window decoration, the classhelper will close and not change
+the parent window.
+
+The classhelper can also be used in read-only mode. In this mode, the
+accumulator is not shown. Also the checkboxes are not displayed. To
+close the classhelper in read-only mode use the window decoration or a
+hotkey (e.g. control-w).
+
+You can have multiple classhelpers up at a time. The title on the
+window identifies the property and item the classhelper will
+modify. For example the image shows the superseder for issue2.
+
+Do not refresh the classhelper window using the ``F5`` key. This will
+erase the contents of the window and you will have to close it and
+invoke the link from the parent window again.
+
 Access Controls
 ---------------
 
--- a/roundup/rest.py	Sat May 18 21:28:05 2024 -0400
+++ b/roundup/rest.py	Tue May 21 01:17:28 2024 -0400
@@ -1029,6 +1029,21 @@
         self.client.setHeader("Allow", "OPTIONS, GET, POST")
         return 200, result
 
+    @Routing.route("/data/user/roles", 'GET')
+    @_data_decorator
+    def get_roles(self, input):
+        """Return all defined roles for users with Admin role.
+           The User class property roles is a string but simulate
+           it as a MultiLink to an actual Roles class.
+        """
+        if not self.client.db.user.has_role(self.client.db.getuid(), "Admin"):
+            raise Unauthorised(
+                'User does not have permission on "user.roles"')
+
+        return 200, {"collection":
+                     [{"id": rolename,"name": rolename}
+                      for rolename in list(self.db.security.role.keys())]}
+
     @Routing.route("/data/<:class_name>/<:item_id>", 'GET')
     @_data_decorator
     def get_element(self, class_name, item_id, input):

Roundup Issue Tracker: http://roundup-tracker.org/