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 doIn progressDoneWon't doDuplicate
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:
- Create a new custom status for the namespace with the new name
- Migrate all existing statuses over to the new custom status. This needs to happen in a background job.
- A generic way to track these migrations would be to have the
work_item_status_migrationstable
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
- Reusability of
WorkItemWidgetStatus - Do we also need a
default_duplicate_statusfor promoted/moved/duplicate actions?- And if we need that - maybe it makes sense to choose an ENUM instead of a boolean (
default_actiononwork_item_status_typeswhich is eitherOPENCLOSEorDUPLICATE)
- And if we need that - maybe it makes sense to choose an ENUM instead of a boolean (