tickets (Ticket management in Noi)

The lino_noi.lib.tickets plugin extends lino_xl.lib.tickets to make it collaborate with lino_noi.lib.working.

In Lino Noi the site of a ticket also indicates "who is going to pay" for our work. Lino Noi uses this information when generating a service report.

This is a tested document. The following instructions are used for initialization:

>>> from lino import startup
>>> startup('lino_book.projects.noi1e.settings.demo')
>>> from lino.api.doctest import *

Tickets

Here is a textual description of the fields and their layout used in the detail window of a ticket.

>>> from lino.utils.diag import py2rst
>>> print(py2rst(tickets.AllTickets.detail_layout, True))
... 
(main) [visible for all]:
- **General** (general_tab_1):
  - **None** (overview)
  - (general2):
    - (general2_1): **Site** (site), **End user** (end_user), **Ticket type** (ticket_type)
    - (general2_2): **Assign to** (quick_assign_to), **Private** (private)
    - (general2_3): **Priority** (priority), **Planned time** (planned_time), **Deadline** (deadline)
    - (general2_4): **Regular** (regular_hours), **Extra** (extra_hours), **Free** (free_hours)
    - **Sessions** (working_SessionsByTicket) [visible for contributor developer admin]
  - (general3): **Workflow** (workflow_buttons), **Comments** (comments_CommentsByRFC)
- **More** (more_tab_1):
  - (more1): **State** (state), **Assigned to** (assigned_to), **Duplicate of** (duplicate_of), **Upload files** (uploads_UploadsByController) [visible for customer contributor developer admin]
  - (more2):
    - **Description** (description)
    - **Resolution** (upgrade_notes)
    - **Checks** (tickets.CheckListItemsByTicket) [visible for customer contributor developer admin]
  - (more3):
    - (more3_1): **ID** (id), **Reference** (ref)
    - **Summary** (summary)
    - (more3_3): **Author** (user), **Created** (created)
    - (more3_4): **Modified** (modified), **Fixed since** (fixed_since)
    - **Duplicates** (DuplicatesByTicket)
- **Links** (links_1): **Mentioned in** (comments_CommentsByMentioned), **Dependencies** (tickets_LinksByTicket) [visible for developer admin]
class lino_noi.lib.tickets.Ticket

The Django model used to represent a ticket in Noi. Adds some fields and methods.

assigned_to

The user who is working on this ticket.

site

The site this ticket belongs to. You can select only sites you are subscribed to.

The life cycle of a ticket

In Lino Noi we use the default tickets workflow defined in lino_xl.lib.tickets.TicketStates.

Sites

The list of the sites in our demo database depends on who is looking at it. Anonymous users can see only public sites:

>>> rt.show(tickets.Sites)
=========== ============= ======== ================ ======== ============== ====
 Reference   Designation   Client   Contact person   Remark   Workflow       ID
----------- ------------- -------- ---------------- -------- -------------- ----
 aab         aab                                              **⚒ Active**   6
 bcc         bcc                                              **⚒ Active**   7
 bugs        bugs                                             **⚒ Active**   5
 dde         dde                                              **⚒ Active**   8
 docs        docs                                             **⚒ Active**   4
 pypi        pypi                                             **⚒ Active**   3
=========== ============= ======== ================ ======== ============== ====
>>> rt.login("marc").show(tickets.Sites)
=========== ===================== ===================== ================ ======== ================================ ====
 Reference   Designation           Client                Contact person   Remark   Workflow                         ID
----------- --------------------- --------------------- ---------------- -------- -------------------------------- ----
 aab         aab                                                                   **⚒ Active**                     6
 bcc         bcc                                                                   **⚒ Active**                     7
 bugs        bugs                                                                  **⚒ Active** → [⚹] [☉] [☾] [☑]   5
 dde         dde                                                                   **⚒ Active** → [⚹] [☉] [☾] [☑]   8
 docs        docs                                                                  **⚒ Active**                     4
 pypi        pypi                                                                  **⚒ Active**                     3
 welsch      Bäckerei Ausdemwald   Bäckerei Ausdemwald   Annette Arens             **⚒ Active** → [⚹] [☉] [☾] [☑]   2
=========== ===================== ===================== ================ ======== ================================ ====
>>> rt.login("jean").show(tickets.Sites)
=========== ===================== ===================== ================ ======== ================================ ====
 Reference   Designation           Client                Contact person   Remark   Workflow                         ID
----------- --------------------- --------------------- ---------------- -------- -------------------------------- ----
 aab         aab                                                                   **⚒ Active** → [⚹] [☉] [☾] [☑]   6
 bcc         bcc                                                                   **⚒ Active** → [⚹] [☉] [☾] [☑]   7
 bugs        bugs                                                                  **⚒ Active** → [⚹] [☉] [☾] [☑]   5
 dde         dde                                                                   **⚒ Active** → [⚹] [☉] [☾] [☑]   8
 docs        docs                                                                  **⚒ Active** → [⚹] [☉] [☾] [☑]   4
 pypi        pypi                                                                  **⚒ Active** → [⚹] [☉] [☾] [☑]   3
 welket      Rumma & Ko OÜ         Rumma & Ko OÜ         Andreas Arens             **⚒ Active** → [⚹] [☉] [☾] [☑]   1
 welsch      Bäckerei Ausdemwald   Bäckerei Ausdemwald   Annette Arens             **⚒ Active** → [⚹] [☉] [☾] [☑]   2
=========== ===================== ===================== ================ ======== ================================ ====
>>> rt.login("mathieu").show(tickets.Sites)
=========== ============= ======== ================ ======== ================================ ====
 Reference   Designation   Client   Contact person   Remark   Workflow                         ID
----------- ------------- -------- ---------------- -------- -------------------------------- ----
 aab         aab                                              **⚒ Active** → [⚹] [☉] [☾] [☑]   6
 bcc         bcc                                              **⚒ Active**                     7
 bugs        bugs                                             **⚒ Active**                     5
 dde         dde                                              **⚒ Active**                     8
 docs        docs                                             **⚒ Active**                     4
 pypi        pypi                                             **⚒ Active** → [⚹] [☉] [☾] [☑]   3
=========== ============= ======== ================ ======== ================================ ====

List of sites to which Jean is "subscribed" (i.e. that are assigned to a team where Jean is member):

>>> rt.login("jean").show(tickets.MySites)
=================== ============= ================================
 Site                Description   Workflow
------------------- ------------- --------------------------------
 `aab <Detail>`__                  **⚒ Active** → [⚹] [☉] [☾] [☑]
 `pypi <Detail>`__                 **⚒ Active** → [⚹] [☉] [☾] [☑]
=================== ============= ================================

List of tickets that have not yet been assigned to a site:

>>> pv = dict(has_site=dd.YesNo.no)
>>> rt.login("robin").show(tickets.AllTickets, param_values=pv)
... 
===== ============================================== ========== ====================================== ======
 ID    Summary                                        Priority   Workflow                               Site
----- ---------------------------------------------- ---------- -------------------------------------- ------
 110   Why is foo so bar                              Normal     [✋] [▶] **☐ Ready** → [☒]
 108   No more foo when bar is gone                   Normal     [✋] [▶] **⚒ Working** → [☾] [☐] [☒]
 100   Cannot delete foo                              Normal     [✋] [▶] **⚒ Working** → [☾] [☐] [☒]
 94    How can I see where bar?                       Normal     [✋] [▶] **☐ Ready** → [☒]
 90    No more foo when bar is gone                   Normal     [✋] [▶] **☎ Talk** → [☾] [☉] [☐] [☒]
 80    Foo never bars                                 Normal     [✋] [▶] **☒ Refused**
 70    'NoneType' object has no attribute 'isocode'   Normal     [✋] [▶] **☐ Ready** → [☒]
 66    Irritating message when bar                    Normal     [✋] [▶] **☎ Talk** → [☾] [☉] [☐] [☒]
 60    Default account in invoices per partner        Normal     [✋] [▶] **⚒ Working** → [☾] [☐] [☒]
 52    'NoneType' object has no attribute 'isocode'   Normal     [✋] [▶] **⚒ Working** → [☾] [☐] [☒]
 50    Misc optimizations in Baz                      Normal     [✋] [▶] **☎ Talk** → [☾] [☉] [☐] [☒]
 40    How can I see where bar?                       Normal     [✋] [▶] **☒ Refused**
 38    Why is foo so bar                              Normal     [✋] [▶] **☐ Ready** → [☒]
 30    Irritating message when bar                    Normal     [✋] [▶] **☐ Ready** → [☒]
 24    Default account in invoices per partner        Normal     [✋] [▶] **☒ Refused**
 20    Why is foo so bar                              Normal     [✋] [▶] **⚒ Working** → [☾] [☐] [☒]
 10    Where can I find a Foo when bazing Bazes?      Normal     [✋] [▶] **☎ Talk** → [☾] [☉] [☐] [☒]
===== ============================================== ========== ====================================== ======

Ticket types

The demo fixture defines the following ticket types.

>>> rt.show(tickets.TicketTypes)
============= ================== ================== ================
 Designation   Designation (de)   Designation (fr)   Reporting type
------------- ------------------ ------------------ ----------------
 Bugfix        Bugfix             Bugfix
 Enhancement   Enhancement        Enhancement
 Upgrade       Upgrade            Upgrade
============= ================== ================== ================

Deciding what to do next

Show all active tickets reported by me.

>>> rt.login('jean').show(tickets.MyTickets)
... 
========== ==================================================================== ================= ============== ========= ======= ====== ==============================================
 Priority   Ticket                                                               Assigned to       Planned time   Regular   Extra   Free   Workflow
---------- -------------------------------------------------------------------- ----------------- -------------- --------- ------- ------ ----------------------------------------------
 Normal     `#113 (⚹ Misc optimizations in Baz) <Detail>`__                      Romain Raffault                                           [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
 Normal     `#106 (☎ 'NoneType' object has no attribute 'isocode') <Detail>`__   Romain Raffault                                           [▶] **☎ Talk** → [☾] [☉] [⚒] [☐] [☑] [☒]
 Normal     `#99 (☉ No more foo when bar is gone) <Detail>`__                                                                              [✋] [▶] **☉ Open** → [☾] [☎] [⚒] [☐] [☑] [☒]
 Normal     `#92 (⚒ Why is foo so bar) <Detail>`__                               Rolf Rompen                                               [▶] **⚒ Working** → [☾] [☎] [☐] [☑] [☒]
 Normal     `#78 (☐ Default account in invoices per partner) <Detail>`__         Rolf Rompen                                               [▶] **☐ Ready** → [☎] [☑] [☒]
 Normal     `#57 (⚹ Irritating message when bar) <Detail>`__                                                                               [✋] [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
 Normal     `#50 (☎ Misc optimizations in Baz) <Detail>`__                                                                                 [✋] [▶] **☎ Talk** → [☾] [☉] [☐] [☒]
 Normal     `#43 (☉ 'NoneType' object has no attribute 'isocode') <Detail>`__                                                              [✋] [▶] **☉ Open** → [☾] [☎] [⚒] [☐] [☑] [☒]
 Normal     `#36 (⚒ No more foo when bar is gone) <Detail>`__                    Luc                                                       [▶] **⚒ Working** → [☾] [☎] [☐] [☑] [☒]
 Normal     `#22 (☐ How can I see where bar?) <Detail>`__                        Rolf Rompen                                               [▶] **☐ Ready** → [☎] [☑] [☒]
 Normal     `#1 (⚹ Föö fails to bar when baz) <Detail>`__                                                                                  [✋] [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
========== ==================================================================== ================= ============== ========= ======= ====== ==============================================

The backlog

The TicketsBySite panel shows all the tickets for a given site. It is a scrum backlog.

>>> welket = tickets.Site.objects.get(ref="welket")
>>> rt.login("robin").show(tickets.TicketsBySite, welket)
... 
===================== ==================================================================== ============== ========== ======= ====== ==============================================
 Priority              Ticket                                                               Planned time   Regular    Extra   Free   Workflow
--------------------- -------------------------------------------------------------------- -------------- ---------- ------- ------ ----------------------------------------------
 Normal                `#114 (☎ Default account in invoices per partner) <Detail>`__                                                 [✋] [▶] **☎ Talk** → [☾] [☉] [⚒] [☐] [☑] [☒]
 Normal                `#113 (⚹ Misc optimizations in Baz) <Detail>`__                                                               [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
 Normal                `#106 (☎ 'NoneType' object has no attribute 'isocode') <Detail>`__                                            [▶] **☎ Talk** → [☾] [☉] [⚒] [☐] [☑] [☒]
 Normal                `#97 (⚹ 'NoneType' object has no attribute 'isocode') <Detail>`__                                             [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
 Normal                `#84 (⚒ Irritating message when bar) <Detail>`__                                                              [▶] **⚒ Working** → [☾] [☎] [☐] [☑] [☒]
 Normal                `#82 (☎ Cannot delete foo) <Detail>`__                                                                        [▶] **☎ Talk** → [☾] [☉] [⚒] [☐] [☑] [☒]
 Normal                `#81 (⚹ No more foo when bar is gone) <Detail>`__                                                             [✋] [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
 Normal                `#74 (☎ Why is foo so bar) <Detail>`__                                                                        [▶] **☎ Talk** → [☾] [☉] [⚒] [☐] [☑] [☒]
 Normal                `#68 (⚒ Misc optimizations in Baz) <Detail>`__                                                                [▶] **⚒ Working** → [☾] [☎] [☐] [☑] [☒]
 Normal                `#65 (⚹ Why is foo so bar) <Detail>`__                                                                        [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
 Normal                `#62 (☐ Foo never bars) <Detail>`__                                                                           [✋] [▶] **☐ Ready** → [☎] [☑] [☒]
 Normal                `#58 (☎ How can I see where bar?) <Detail>`__                                                                 [▶] **☎ Talk** → [☾] [☉] [⚒] [☐] [☑] [☒]
 Normal                `#49 (⚹ How can I see where bar?) <Detail>`__                                                                 [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
 Normal                `#44 (⚒ Foo never bars) <Detail>`__                                                                           [▶] **⚒ Working** → [☾] [☎] [☐] [☑] [☒]
 Normal                `#42 (☎ Default account in invoices per partner) <Detail>`__                                                  [▶] **☎ Talk** → [☾] [☉] [⚒] [☐] [☑] [☒]
 Normal                `#36 (⚒ No more foo when bar is gone) <Detail>`__                                                             [▶] **⚒ Working** → [☾] [☎] [☐] [☑] [☒]
 Normal                `#33 (⚹ Default account in invoices per partner) <Detail>`__                                                  [✋] [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
 Normal                `#18 (☎ No more foo when bar is gone) <Detail>`__                                                             [✋] [▶] **☎ Talk** → [☾] [☉] [⚒] [☐] [☑] [☒]
 Normal                `#17 (⚹ Foo never bars) <Detail>`__                                                                           [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
 Normal                `#14 (☐ Bar cannot baz) <Detail>`__                                                 0:10                      [✋] [▶] **☐ Ready** → [☎] [☑] [☒]
 Normal                `#12 (⚒ Foo cannot bar) <Detail>`__                                                 1:30                      [▶] **⚒ Working** → [☾] [☎] [☐] [☑] [☒]
 Normal                `#4 (⚒ Foo and bar don't baz) <Detail>`__                                           2:18                      [▶] **⚒ Working** → [☾] [☎] [☐] [☑] [☒]
 Normal                `#1 (⚹ Föö fails to bar when baz) <Detail>`__                                                                 [✋] [▶] **⚹ New** → [☾] [☎] [☉] [⚒] [☐] [☑]
 **Total (23 rows)**                                                                                       **3:58**
===================== ==================================================================== ============== ========== ======= ====== ==============================================

Note that anonymous cannot see tickets of a non-public site.

>>> rt.show(tickets.TicketsBySite, welket)
... 
No data to display
>>> pypi = tickets.Site.objects.get(ref="pypi")
>>> rt.show(tickets.TicketsBySite, pypi)
... 
No data to display

Filtering tickets

Lino Noi modifies the list of the parameters you can use for filterings tickets be setting a custom params_layout.

>>> show_fields(tickets.AllTickets, all=True)
... 
+--------------------+--------------------+-----------------------------------------------------------------------+
| Internal name      | Verbose name       | Help text                                                             |
+====================+====================+=======================================================================+
| user               | Author             | The author or reporter of this ticket. The user who reported this     |
|                    |                    | ticket to the database and is responsible for managing it.            |
+--------------------+--------------------+-----------------------------------------------------------------------+
| end_user           | End user           | Only rows concerning this end user.                                   |
+--------------------+--------------------+-----------------------------------------------------------------------+
| assigned_to        | Assigned_to        | Only tickets with this user assigned.                                 |
+--------------------+--------------------+-----------------------------------------------------------------------+
| not_assigned_to    | Not assigned to    | Only that this user is not assigned to.                               |
+--------------------+--------------------+-----------------------------------------------------------------------+
| interesting_for    | Interesting for    | Only tickets interesting for this partner.                            |
+--------------------+--------------------+-----------------------------------------------------------------------+
| site               | Site               | Select a site if you want to see only tickets for this site.          |
+--------------------+--------------------+-----------------------------------------------------------------------+
| has_site           | Has site           | Show only (or hide) tickets which have a site assigned.               |
+--------------------+--------------------+-----------------------------------------------------------------------+
| state              | State              | Only rows having this state.                                          |
+--------------------+--------------------+-----------------------------------------------------------------------+
| priority           | Priority           | Only rows having this priority.                                       |
+--------------------+--------------------+-----------------------------------------------------------------------+
| show_assigned      | Assigned           | Show only (or hide) tickets that are assigned to somebody.            |
+--------------------+--------------------+-----------------------------------------------------------------------+
| show_active        | Active             | Show only (or hide) tickets which are active (i.e. state is Talk      |
|                    |                    | or ToDo).                                                             |
+--------------------+--------------------+-----------------------------------------------------------------------+
| show_todo          | To do              | Show only (or hide) tickets which are todo (i.e. state is New         |
|                    |                    | or ToDo).                                                             |
+--------------------+--------------------+-----------------------------------------------------------------------+
| show_private       | Private            | Show only (or hide) tickets that are marked private.                  |
+--------------------+--------------------+-----------------------------------------------------------------------+
| start_date         | Date from          | Start of observed date range                                          |
+--------------------+--------------------+-----------------------------------------------------------------------+
| end_date           | until              | End of observed date range                                            |
+--------------------+--------------------+-----------------------------------------------------------------------+
| observed_event     | Observed event     |                                                                       |
+--------------------+--------------------+-----------------------------------------------------------------------+
| has_ref            | Has reference      |                                                                       |
+--------------------+--------------------+-----------------------------------------------------------------------+
| last_commenter     | Commented Last     | Only tickets that have this use commenting last.                      |
+--------------------+--------------------+-----------------------------------------------------------------------+
| not_last_commenter | Not Commented Last | Only tickets where this use is not the last commenter.                |
+--------------------+--------------------+-----------------------------------------------------------------------+
| subscriber         | Site Subscriber    | Limit tickets to tickets that have a site this user is subscribed to. |
+--------------------+--------------------+-----------------------------------------------------------------------+