Skip to content

Spike: Work item status widget - Iteration 1

Summary

This is the spike issue for the requirements defined in &14793 (closed).

Requirements

Statuses

Every root namespace will have pre-defined statuses, namely:

  • To do
  • In progress
  • Done
  • Won't do
  • Duplicate

Note: Before creating the migration of the pre-defined statuses, check with @nickleonard to ensure these are the ones we want.

In a next iteration, we allow configuring custom statuses per root namespace. However, the data structure from iteration 1 will already allow us to add custom statuses in the future.

Every work item has a status and when a new work item gets created, the status can be chosen (only required in a future iteration). For existing work items, we will choose the following statuses per state:

  • Closed work items: Done
  • Open work items: To do
  • Promoted, moved or duplicated work items: Duplicate

It's possible to change the status of a work item that is Duplicate to any other status. The information that a work item is duplicated, moved, or promoted is still in the system notes.

Categories

Every status will be part of a pre-defined category. There is no plan yet to customize these categories. The categories will be:

  • Triage (to be defined yet if it exists)
  • To do
  • In progress
  • Done
  • Cancelled

Initially these categories will not be visible, but will appear once we allow managing custom statuses. The category also defines the icon of the status and which state it belongs to (closed or open).

We can add the category as an ENUM and hardcode the attributes.

module WorkItems
  class Status
    enum category: {
      triage: 1,
      to_do: 2,
      in_progress: 3,
      done: 4,
      cancelled: 5
    }

    CATEGORY_METADATA = {
      triage: {
        icon: 'circle',
        state: :open,
        default_color: '#ff0000'
      },
      done: {
        icon: 'checkmark-circle',
        state: :closed,
        default_color: '#00ff00'
      }
      # ...
    }
  end
end

Statuses and related actions (state and moved/promoted/duplicated)

State and statuses interact with each other. For example:

  • When a work item gets closed, we set the status to Done
  • When a work item gets re-opened, we set the status to To do
  • When a work item gets promoted, we set the status to Duplicate
  • When a work item status gets set to Done, we close it
  • When a work item status gets set to To do, we open it
  • When a work item status gets set to In progress, we open it

The information if a status is part of the Closed or Open state is stored in the category.

However, only one status can be the "default" status per state. This is required to know which status to set when changing the state. e.g., When a work item that is In Progress gets closed, we need to know which status to set it to (in the pre-defined case: Done).

Database Schema

Note: Feel free to recommend other names.

work_item_status_types

Column Type Description
name varchar Name of the status type
color varchar Adjustable color of the status
namespace_id bigint Root namespace ID or -1 for pre-defined statuses
work_item_type_id bigint Either NULL to allow it for all types, or the specific work_item_type_id
category smallint ENUM of the category
default_closed_status boolean Indicating if it's the default closed status (only valid to be set once per namespace_id)
default_open_status boolean Indicating if it's the default open status (only valid to be set once per namespace_id)

work_item_statuses

Column Type Description
work_item_id bigint (PRIMARY) ID of the work item. Primary key of the table to ensure uniqueness
work_item_status_id bigint ID of the status.

work_item_status_migrations

Not required until we allow customization of statuses

This can be used to migrate statuses from one to another. More on that problem later.

Column Type Description
work_item_status_id bigint ID of the status
work_item_id bigint ID of the work item

Pre-Defined and Custom statuses

It would be too excessive to populate the pre-defined statuses per root namespace. However, we can't use NULL for namespace_id as we require it as part of the sharding key. This problem is the same as for work item types where we agreed on having a namespace_id = -1 for pre-defined types and reserve the first 1000 IDs for pre-defined statuses. We will do the same approach for work item statuses.

Modifying statuses

Editing a pre-defined status

When editing a pre-defined status (e.g., change the name), we need to do the following:

  1. Create a new custom status for the namespace with the new name
  2. Migrate all existing statuses over to the new custom status. This needs to happen in a background job.
  3. A generic way to track these migrations would be to have the work_item_status_migrations table

Note: To make things easier, we decided to move all pre-defined statuses to be a custom status, once a namespace decides to edit one status. This safes us from adding an additional table where we store which pre-defined statuses are disabled. We need to store though if a namespace is using pre-defined statuses or custom statuses.

Removing a status

A status is only allowed to be removed when it is no longer used in the namespace. As part of the UX, we want to enable users to define to which status a removed status would migrate to. This would be again a case for the work_item_status_migrations table.

Status Migration

We need to set a status every time a work item gets created, closed, re-opened, promoted, moved, or duplicated. We also need to perform a migration over all work items and set the initial status based on their state.

GraphQL Schema

For each work item, we can query the available work item statuses as part of the widget definitions:

query workItemType {
      id
      name
      widgetDefinitions {
        type
        ... on WorkItemWidgetDefinitionStatus {
         allowedStatuses {
            nodes {
              id
              name
              iconName
            }
          }
        }
      }
    }
query workItemStatuses {
  workItem(id: $id) {
    title
    description
    status {
      id
      name
      iconName
    }
  }
}

In addition to that, we need to add allowedStatuses on a Namespace/Project/Group query:

query GroupStatuses {
  group(fullPath: $fullPath) {
    allowedStatuses {
      nodes {
        id
        name
        iconName
      }
    }
  }
}

Open Questions

  1. Reusability of WorkItemWidgetStatus
  2. Do we also need a default_duplicate_status for promoted/moved/duplicate actions?
    1. And if we need that - maybe it makes sense to choose an ENUM instead of a boolean (default_action on work_item_status_types which is either OPEN CLOSE or DUPLICATE )
Edited by Nicolas Dular