@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1@title Configuring Custom Fields
2@group config
3
4How to add custom fields to applications which support them.
5
6= Overview =
7
8Several Phorge applications allow the configuration of custom fields. These
9fields allow you to add more information to objects, and in some cases reorder
10or remove builtin fields.
11
12For example, you could use custom fields to add an "Estimated Hours" field to
13tasks, a "Lead" field to projects, or a "T-Shirt Size" field to users.
14
15These applications currently support custom fields:
16
17| Application | Support |
18|-------------|---------|
19| Differential | Partial Support |
20| Diffusion | Limited Support |
21| Maniphest | Full Support |
22| Owners | Full Support |
23| People | Full Support |
24| Projects | Full Support |
25
26Custom fields can appear in many interfaces and support search, editing, and
27other features.
28
29= Basic Custom Fields =
30
31To get started with custom fields, you can use configuration to select and
32reorder fields and to add new simple fields.
33
34If you don't need complicated display controls or sophisticated validation,
35these simple fields should cover most use cases. They allow you to attach
36things like strings, numbers, and dropdown menus to objects.
37
38The relevant configuration settings are:
39
40| Application | Add Fields | Select Fields |
41|-------------|------------|---------------|
42| Differential | Planned | `differential.fields` |
43| Diffusion | Planned | Planned |
44| Maniphest | `maniphest.custom-field-definitions` | `maniphest.fields` |
45| Owners | `owners.custom-field-definitions` | `owners.fields` |
46| People | `user.custom-field-definitions` | `user.fields` |
47| Projects | `projects.custom-field-definitions` | `projects.fields` |
48
49When adding fields, you'll specify a JSON blob like this (for example, as the
50value of `maniphest.custom-field-definitions`):
51
52 {
53 "mycompany:estimated-hours": {
54 "name": "Estimated Hours",
55 "type": "int",
56 "caption": "Estimated number of hours this will take.",
57 "required": true
58 },
59 "mycompany:actual-hours": {
60 "name": "Actual Hours",
61 "type": "int",
62 "caption": "Actual number of hours this took."
63 },
64 "mycompany:company-jobs": {
65 "name": "Job Role",
66 "type": "select",
67 "options": {
68 "mycompany:engineer": "Engineer",
69 "mycompany:nonengineer": "Other"
70 }
71 },
72 "mycompany:favorite-dinosaur": {
73 "name": "Favorite Dinosaur",
74 "type": "text"
75 }
76 }
77
78The fields will then appear in the other config option for the application
79(for example, in `maniphest.fields`) and you can enable, disable, or reorder
80them.
81
82For details on how to define a field, see the next section.
83
84= Custom Field Configuration =
85
86When defining custom fields using a configuration option like
87`maniphest.custom-field-definitions`, these options are available:
88
89 - **name**: Display label for the field on the edit and detail interfaces.
90 - **description**: Optional text shown when managing the field.
91 - **type**: Field type. The supported field types are:
92 - **int**: An integer, rendered as a text field.
93 - **text**: A string, rendered as a text field.
94 - **bool**: A boolean value, rendered as a checkbox.
95 - **select**: Allows the user to select from several options as defined
96 by **options**, rendered as a dropdown.
97 - **remarkup**: A text area which allows the user to enter markup.
98 - **users**: A typeahead which allows multiple users to be input.
99 - **date**: A date/time picker.
100 - **header**: Renders a visual divider which you can use to group fields.
101 - **link**: A text field which allows the user to enter a link.
102 - **edit**: Show this field on the application's edit interface (this
103 defaults to `true`).
104 - **view**: Show this field on the application's view interface (this
105 defaults to `true`). (Note: Empty fields are not shown.)
106 - **search**: Show this field on the application's search interface, allowing
107 users to filter objects by the field value.
108 - **fulltext**: Index the text in this field as part of the object's global
109 full-text index. This allows users to find the object by searching for
110 the field's contents using global search.
111 - **caption**: A caption to display underneath the field (optional).
112 - **required**: True if the user should be required to provide a value.
113 - **options**: If type is set to **select**, provide options for the dropdown
114 as a dictionary.
115 - **default**: Default field value.
116 - **strings**: Allows you to override specific strings based on the field
117 type. See below.
118 - **instructions**: Optional block of remarkup text which will appear
119 above the control when rendered on the edit view.
120 - **placeholder**: A placeholder text that appears on text boxes. Only
121 supported in text, int and remarkup fields (optional).
122 - **list**: If set to `icon`, `attribute` or `byline`, the value of the field
123 will be shown in list-view.
124 - **list.icon**: If `list` is set to `icon`, use this icon. These are the
125 same icons that can be used in the `{icon}` syntax for Remarkup.
126 - **list.label**: When rendering value in a list, use this label (instead of
127 `name`).
128 - **copy**: If true, this field's value will be copied when an object is
129 created using another object as a template.
130 - **limit**: For control types which use a tokenizer control to let the user
131 select a list of values, this limits how many values can be selected. For
132 example, a "users" field with a limit of "1" will behave like the "Owner"
133 field in Maniphest and only allow selection of a single user.
134
135The `strings` value supports different strings per control type. They are:
136
137 - **bool**
138 - **edit.checkbox** Text for the edit interface, no default.
139 - **view.yes** Text for the view interface, defaults to "Yes".
140 - **search.default** Text for the search interface, defaults to "(Any)".
141 - **search.require** Text for the search interface, defaults to "Require".
142
143Internally, Phorge implements some additional custom field types and
144options. These are not intended for general use and are subject to abrupt
145change, but are documented here for completeness:
146
147 - **Credentials**: Controls with type `credential` allow selection of a
148 Passphrase credential which provides `credential.provides`, and creation
149 of credentials of `credential.type`.
150 - **Datasource**: Controls with type `datasource` allow selection of tokens
151 from an arbitrary datasource, controlled with `datasource.class` and
152 `datasource.parameters`.
153
154= Advanced Custom Fields =
155
156If you want custom fields to have advanced behaviors (sophisticated rendering,
157advanced validation, complicated controls, interaction with other systems, etc),
158you can write a custom field as an extension and add it to Phorge.
159
160To do this, extend the appropriate `CustomField` class for the application you
161want to add a field to:
162
163| Application | Extend |
164|-------------|---------|
165| Differential | @{class:DifferentialCustomField} |
166| Diffusion | @{class:PhabricatorCommitCustomField} |
167| Maniphest | @{class:ManiphestCustomField} |
168| Owners | @{class:PhabricatorOwnersCustomField} |
169| People | @{class:PhabricatorUserCustomField} |
170| Projects | @{class:PhabricatorProjectCustomField} |
171
172The easiest way to get started is to drop your subclass into
173`phorge/src/extensions/`. If Phorge is configured in development
174mode, the class should immediately be available in the UI. If not, you can
175restart Phorge (for help, see @{article:Restarting Phorge}).
176
177For example, this is a simple template which adds a custom field to Maniphest:
178
179 name=ExampleManiphestCustomField.php
180 <?php
181
182 final class ExampleCustomField extends ManiphestCustomField {
183
184 public function getFieldKey() {
185 return 'example:test';
186 }
187
188 public function shouldAppearInPropertyView() {
189 return true;
190 }
191
192 public function renderPropertyViewLabel() {
193 return pht('Example Custom Field');
194 }
195
196 public function renderPropertyViewValue(array $handles) {
197 return phutil_tag(
198 'h1',
199 array(
200 'style' => 'color: #ff00ff',
201 ),
202 pht('It worked!'));
203 }
204
205 }
206
207Broadly, you can then add features by overriding more methods and implementing
208them. Many of the native fields are implemented on the custom field
209architecture, and it may be useful to look at them. For details on available
210integrations, see the base class for your application and
211@{class:PhabricatorCustomField}.
212
213= Next Steps =
214
215Continue by:
216
217 - learning more about extending Phorge with custom code in
218 @{article@contrib:Adding New Classes};
219 - or returning to the @{article: Configuration Guide}.