Add table(s) for mapping widgets to work_items
Add table(s) necessary for storing information about what widgets are available for each work item type.
Proposal (based on discussion in #374092 (comment 1134564199))
Table schema should be aligned with future customization of work item types (#335110), this also means that we should avoid changing work_item_type_id when user customizes/changes work item type (otherwise we would have to update work_item_type_id for all existing work_items for this type).
erDiagram
work_item_types {
int id
string name
int namespace_id
boolean disabled
}
work_item_types ||--|o work_item_type_overrides : ""
work_item_type_overrides {
int id
string name
int namespace_id
boolean disabled
}
work_item_types ||--|{ widget_definitions : ""
widget_definitions {
int id
int namespace_id
int work_item_type_id
int widget_definition_enum
int position
string name
boolean disabled
}
Then content of table would look like this:
Widget mapping to a class
Model enum definition of mapping widget ids to classes (this is not dynamic, needs to be updated only with rare situation of adding new widget):
widget_definition_enum = {
hierarchy: 0,
weight: 1,
start_due_date: 2,
text_field: 3,
integer_field: 4
}
work_item_types
- pre-filled with default types (types with namespace_id=null)
- users can add custom work item types (these will have namespace_id set)
| id | name | namespace_id | disabled |
|---|---|---|---|
| 0 | issue | ||
| 1 | task | ||
| 2 | requirement | ||
| 3 | custom type 1 | 1 | |
| 4 | custom type 2 | 1 | |
| 5 | alternative issue | true | |
| 6 | alternative epic | true |
work_item_type_overrides table
- used for user's customization of default work item types (changing its name, or disabling them)
| namespace_id | work_item_type_id | name | disabled |
|---|---|---|---|
| 1 | 0 | ticket | false |
| 1 | 1 | task | true |
widget_definitions
-
widget_definitionsis pre-filled with widget definitions for default types (ids 0-2:issuehas two widgets - hierarchy, weight,taskhas one widget - Weight)
| id | namespace_id | work_item_type_id | widget_definition_enum | position | name | disabled |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | Hierarchy | false | |
| 1 | 0 | 1 | 1 | Weight | false | |
| 2 | 1 | 0 | 0 | Hierarchy | false | |
| 3 | 1 | 1 | 0 | 0 | Hierarchy | true |
| 4 | 1 | 1 | 1 | 0 | MyWeight | false |
| 5 | 1 | 3 | 1 | 0 | Weight | false |
| 6 | 1 | 3 | 3 | 0 | MyTextField1 | false |
| 7 | 1 | 3 | 4 | 0 | MyNumField 1 | false |
Getting all work item types for a namespace:
select * from work_item_types where namespace_id is null or namespace_id=1
Getting all widgets for a work item type:
select * from widget_definitions where work_item_type_id=1 and (namespace_id is null or namespace_id=1) where disabled=false
Important Note: here we would have to prioritize namespaced record over default record when loading them (IOW this would load records 2,3,4, but we would discard 2 in favor of 3 as id=3 is namespace-specific)
Scenarios:
- user creates new namespace and works with pre-defined work item types: no new records are added
- user wants to use default issue type but change some of its widgets: for task he wants to disable hierarchy and rename weight widget to "MyWeight"): adds rows with ids 3 and 4
- user wants to add his own work item type (custom type 1) with its own set of widgets (Weight, MyTextField1 and MyNumField 1): adds rows with ids 5,6,7 to widget_definitions
- user wants to rename default type
IssuetoTicket: first row inwork_item_overrides - user wants to disable default type
Task: second row inwork_item_overrides - we want to provide multiple predefined work item type sets - e.g. Issue and Epic types used by default. But user can enable usage of
Alternative issueandAlternative epic: alternative types are disabled by default, user can enable them inwork_item_overridesand disable Issue/Epic there
- the schema may contain some attributes which we don't use (yet?) - e.g. row_order or disabled - these might be added later when needed.
- work_item_type has many widgets - we may need an association table for this (or alternatively store list of widget references into an array field but this may be less flexible)
So maybe for now models might look like this (for current needs while extensible in future)?
class WorkItems::Type # already existing model
has_many :type_widgets
has_many :widgets, through: :type_widgets
end
class WorkItems::TypeWidgets # TODO - better name?
belongs_to :work_item_type
belongs_to :widget_definition
end
class WorkItems::WidgetDefinition
has_many :type_widgets
has_many :work_item_types, through: :type_widgets
# attributes: id, name, widget_class
# widget_class - defines widget's "class" we we know to which widget class (https://gitlab.com/gitlab-org/gitlab/-/tree/master/app/models/work_items/widgets) - doesn't have to be class name, can be also just enum (and mapping to classes can be statically defined)
end
Related to #370599