| 1 | |
| 2 | = Project classifiers (aka labels) = #Introduction |
| 3 | |
| 4 | Consider merging this page with |
| 5 | [wiki:TracDev/Proposals/MultipleProject Multi-Project Support for Trac] |
| 6 | |
| 7 | In order to provide an structured solution so as not to limit the possible ways of |
| 8 | grouping projects it is convenient to introduce the concept of |
| 9 | '''project labels'''. Main goals are the following : |
| 10 | |
| 11 | - Offer a structured mechanism to identify a group of projects no matter |
| 12 | what hierarchy is involved . |
| 13 | - Encapsulate these details at the API level while |
| 14 | determining (multi)project context. |
| 15 | |
| 16 | Considering the [wiki:TracDev/Proposals/MultipleProject#ProjectTree reference example], |
| 17 | in spite of searching for tickets |
| 18 | in `Family A` and `Family B` but not in `Tools` and `3rdParty` when needed, |
| 19 | a label containing both projects has to be created (either ''explicitly'' or |
| 20 | ''implicitly'', see [#SpecialLabels below]) . |
| 21 | |
| 22 | This document also suggests alternatives and approaches to implement some |
| 23 | features defined in |
| 24 | [wiki:TracDev/Proposals/MultipleProject Multi-Project Support for Trac]. Some |
| 25 | content may actually overlap aforementioned specification. |
| 26 | |
| 27 | == URL space for different projects == #UrlMapping |
| 28 | |
| 29 | A constraint should be imposed in order to simplify dispatching strategy so as |
| 30 | to map projects to ''URL''s. Project short name '''MUST''' be unique in the |
| 31 | context of an environment. |
| 32 | |
| 33 | - '''host mapping''': the name of the (virtual) host used to access the |
| 34 | ''Trac'' environment is taken to be the name of the project. A given host |
| 35 | can be configured to be an alias for the default, top-level project. Label |
| 36 | names are not allowed to be used this way. |
| 37 | - '''prefix mapping''': if the `PATH_INFO` starts with `/p/<project name>/` |
| 38 | prefix, name of a project will be taken to be `<project_name>` . Otherwise if |
| 39 | it starts with `/l/<label_name>/` then the request is addressed to the set |
| 40 | of projects included in label `<label_name>`. In general this is less |
| 41 | ambiguous than the |
| 42 | [wiki:TracDev/Proposals/MultipleProject#URLspacefordifferentprojects mapping suggested in original proposal]. |
| 43 | Explanation and implementation details provided [#UrlExplained below]. |
| 44 | |
| 45 | == The Data Model and the API == #DataModelApi |
| 46 | |
| 47 | Labels may be considered as resources bound to the environment rather |
| 48 | than to particular projects (e.g. like `Changeset` and `Source` which belong |
| 49 | to a given repository - see MultiRepos). Hence only an |
| 50 | additional `labels` table is also needed, and it can take the form of a |
| 51 | ''resource table specialization'' from the GenericTrac. Project labels should |
| 52 | have at least short name (and maybe description) field. Project labels can be |
| 53 | linked explicitly to projects and labels (if using [#NestedLabels nested labels]). |
| 54 | These connections can take the form of ''relations'' from |
| 55 | [wiki:TracDev/Proposals/TracRelations Trac Relations]. |
| 56 | |
| 57 | === URL prefix mapping explained === #UrlExplained |
| 58 | |
| 59 | Project-specific URLs will start with `/p/<project name>` prefix. |
| 60 | Requests involving multiple projects will be made available on a per-label |
| 61 | basis at ''URL''s starting with `/l/<label name>` prefix. Remaining path after |
| 62 | this will be used to select what instance of `IRequestHandler` should process |
| 63 | the request. Examples below illustrate some use cases. In all cases |
| 64 | multi-project environment root ''URL'' is `http://server.com/path/to/trac/` and |
| 65 | it will contain the reference project hierarchy used throughout this document : |
| 66 | |
| 67 | || '''URL''' || '''Target projects''' || '''Comments''' || |
| 68 | || `http://server.com/path/to/trac/` || top-level project (i.e. `''` ) || || |
| 69 | || `http://server.com/path/to/trac/roadmap` || top-level project (i.e. `''` ) || Top-level milestone view. This may be used to show top-level (e.g. product, current year, ...) milestones. || |
| 70 | || `http://server.com/path/to/trac/p/FamilyB/roadmap` || project '''FamilyB''' || '''FamilyB''' project-specific milestones. || |
| 71 | || `http://server.com/path/to/trac/p/product_c/roadmap` || project '''product_c''' || '''product c''' project-specific milestones. || |
| 72 | || `http://server.com/path/to/trac/l/javascript/roadmap` || all projects in label '''javascript''' || display milestones for javascript projects. || |
| 73 | |
| 74 | By doing things this way request dispatch may be implemented as a combination of |
| 75 | two existing architectural features , namely '''request filters''' and |
| 76 | '''request handlers'''. First of all by supporting multi-project |
| 77 | specifications the context associated to the request has to contain |
| 78 | information about target project(s) . One component acting as a request filter |
| 79 | intercepts the request before match is performed. If any multiproject |
| 80 | prefix (i.e. `/p/<project name>` or `/l/<label name>`) is detected then |
| 81 | project resolution takes place. Single-project requests only |
| 82 | need to add corresponding internal project resource to context. |
| 83 | In the case of labels the context should contain ''label name'' as well as a |
| 84 | list of resources identifying target projects . In the case of |
| 85 | [#SpecialLabels more complex project selector expressions] the context should contain the |
| 86 | expression itself, the instance of `IProjectLabelManager` matching label name, |
| 87 | and the list of resource objects identifying target projects . If this |
| 88 | advanced feature will be supported, it may be considered as a generic way to |
| 89 | encapsulate multi-project context in spite of having flexibility and uniformity, |
| 90 | considering the fact that first two variants are just particular cases. |
| 91 | Aforementioned data may be retrieved right away at dispatch time or loaded |
| 92 | on demand. |
| 93 | |
| 94 | Immediately after multi-project context resolution, the request filter rewrites |
| 95 | `PATH_INFO` by removing project selection prefix. The request is then |
| 96 | matched as usual so as to determine the handler responsible for processing it |
| 97 | (e.g. `wiki`, `ticket`, ...). The target instance of `IRequestHandler` will |
| 98 | rely on request context so as to determine target projects involved and |
| 99 | build the response accordingly. |
| 100 | |
| 101 | == Advanced labels features == #LabelsAdvanced |
| 102 | |
| 103 | Subsequent sub-sections deal with some advanced features that may be useful |
| 104 | under certain circumstances but may also over-complicate core design . |
| 105 | Nonetheless I mention them here for the sake of |
| 106 | ~~could not find the right word~~. |
| 107 | |
| 108 | === Project alias === #LabelAlias |
| 109 | |
| 110 | A label related to a single project may be considered a project alias. This |
| 111 | scenario may happen when two or more projects are merged and previous project |
| 112 | name is to be kept so as not to break external references, for instance. |
| 113 | |
| 114 | === Nested labels === #NestedLabels |
| 115 | |
| 116 | It might be convenient as well to provide a way to specify a hierarchy of |
| 117 | labels (rather than projects). In order to illustrate this with a particular |
| 118 | example which might be very common in practice, let's consider we have the |
| 119 | [wiki:TracDev/Proposals/MultipleProject#ProjectTree sample hierarchy of projects] |
| 120 | and still need to |
| 121 | group them according to programming languages and frameworks used to build |
| 122 | them (let them be explicit project dependencies or not). In that case it will |
| 123 | be useful to have some labels like `javascript`, `python`, `c#`, `vb.net`, |
| 124 | `f#`, `ruby`, `php` and so on. Let's also consider a similar situation |
| 125 | and project classification also includes frameworks, so there are further |
| 126 | tags like e.g. `trac`, `wcf`, `jquery`, `mootools`, `wpf`, `django`, `dojo`, ... |
| 127 | Nonetheless : |
| 128 | |
| 129 | - It may be useful to know which projects are related to ''.NET framework''. |
| 130 | - It may be useful to ease the process by tagging projects using a single |
| 131 | label identifying a framework and having them auto-magically included in |
| 132 | the label for the corresponding programming language . |
| 133 | |
| 134 | In order to do that the following label hierarchy might help : |
| 135 | |
| 136 | {{{ |
| 137 | +-- python |
| 138 | | +-- trac |
| 139 | | +-- django |
| 140 | +-- ruby |
| 141 | +-- javascript |
| 142 | | +-- jquery |
| 143 | | +-- dojo |
| 144 | | +-- mootools |
| 145 | +-- .net |
| 146 | | +-- .net languages |
| 147 | | | +-- c# |
| 148 | | | +-- vb.net |
| 149 | | | +-- f# |
| 150 | | +-- .net technologies |
| 151 | | | +-- wpf |
| 152 | | | +-- wcf |
| 153 | | | +-- wwf |
| 154 | +-- php |
| 155 | |
| 156 | }}} |
| 157 | |
| 158 | For instance , [http://trac-hacks.org Trac-Hacks] website may be one such |
| 159 | example where there's a flat one-level project hierarchy and labels to group |
| 160 | hacks. In [#TracHacksLabels Apendix B] it is possible to see |
| 161 | sample label hierarchy based on hack classifiers available at present. Idea |
| 162 | is , for instance, that if somebody tags a project using `macro` label then |
| 163 | it also belongs auto-magically in `plugins` label. |
| 164 | |
| 165 | There's another precision that needs to be mentioned up to this point and it |
| 166 | is whether it is more convenient to define label relationships using graphs |
| 167 | rather than a tree . Considering the same case mentioned above , |
| 168 | labels like `iron_python` , `iron_ruby` would be hard to |
| 169 | classify considering aforementioned hierarchy as they may be related to both |
| 170 | `.net` and (`python` | `ruby`) (same reasoning for e.g. `jpype` , `jython` for |
| 171 | `python` & `java`; `rython` , `unholy` for `python` & `ruby` ... and it's |
| 172 | possible to find more examples even in totally different business domains). |
| 173 | |
| 174 | === Project context extensions === #SpecialLabels |
| 175 | |
| 176 | It may be useful to be able to specify ''special'' project groups like : |
| 177 | |
| 178 | - ''all parents of project A'' |
| 179 | - ''direct children of project B'' |
| 180 | - ''descendant of project C'' |
| 181 | - `*` all the projects (mentioned in [wiki:TracDev/Proposals/MultipleProject#URLspacefordifferentprojects original Multi-Project specification]) |
| 182 | - glob pattern (mentioned in [wiki:TracDev/Proposals/MultipleProject#URLspacefordifferentprojects original Multi-Project specification]) |
| 183 | - `!` prefix to exclude projects (mentioned in [wiki:TracDev/Proposals/MultipleProject#URLspacefordifferentprojects original Multi-Project specification]) |
| 184 | - comma-separated list of project names (e.g. `FamilyA,product_d,3rdParty`) |
| 185 | - ''XPath expressions'' |
| 186 | |
| 187 | These are just a few examples. In order to prepare the system for flexibilty |
| 188 | and maybe allow the definition of other project selector expressions (e.g. in |
| 189 | plugins) it is convenient to introduce a new interface |
| 190 | (namely `IProjectLabelManager`) used to determine which projects belong in a |
| 191 | given label, provided its name. Selection should work using a chain of |
| 192 | responsibilty similar to the one already used for `IRequestHandler`. All |
| 193 | instances of `IProjectLabelManager` are requested to expand a project selector |
| 194 | expression. This will consist of returning a list of project names ''matching'' |
| 195 | a given label name (aka ''project selector expression'' <= this seems to be |
| 196 | more generic ''';)''' , or `None` if such match is not found. In the later case |
| 197 | the next instance of `IProjectLabelManager` is considered and so on ... until |
| 198 | either a match is found (and subsequent request handling takes place) or all |
| 199 | options are exhausted (and error handling occurs e.g. ''HTTP 404 Not Found'' |
| 200 | returned to the client) . |
| 201 | |
| 202 | == User interface == #LabelsGUI |
| 203 | |
| 204 | Considering everything mentioned up to this point , the following variants of |
| 205 | project selector GUI control are suggested. |
| 206 | |
| 207 | === Project selector (drop-down menu) === #LabelsMenu |
| 208 | |
| 209 | The use of labels makes possible to present a flat drop-down menu to the user |
| 210 | in order to select a set of projects like shown below. This may be considered |
| 211 | more appropriate than always having to display a hierarchy. |
| 212 | |
| 213 | {{{ |
| 214 | #!html |
| 215 | |
| 216 | <select id="SampleProjectMenu" name="field_milestone"> |
| 217 | <option></option> |
| 218 | <optgroup label="Projects"> |
| 219 | <option>Top-level</option> |
| 220 | <option>Family A</option> |
| 221 | <option> product a</option> |
| 222 | <option> product b</option> |
| 223 | <option>Family B</option> |
| 224 | <option> product c</option> |
| 225 | <option> product d</option> |
| 226 | <option>Tools</option> |
| 227 | <option>3rdParty</option> |
| 228 | </optgroup> |
| 229 | <optgroup label="Labels"> |
| 230 | <option>Product families</option> |
| 231 | <option selected="true">Products</option> |
| 232 | <option><i>Create new label ...</i></option> |
| 233 | </optgroup> |
| 234 | </select> |
| 235 | }}} |
| 236 | |
| 237 | '''PS''': ''Create new label ...'' option should be visible only if user can |
| 238 | create labels. If the user can modify labels (i.e. classify projects in |
| 239 | categories) then it may be useful to include shortcut links to update projects |
| 240 | membership. In both cases a dialog (see picture below) should be displayed. |
| 241 | |
| 242 | {{{ |
| 243 | #!html |
| 244 | |
| 245 | <div id="SampleLabelsEditor" style="width:50%;margin-left:auto;margin-right:auto;background-color:#666666;"> |
| 246 | <div style="background-color:#666666;color:#ffffff;">Create new label</div> |
| 247 | <div style="background-color:#ffffff;padding:15px;"> |
| 248 | <label for="label_id">Label ID :</label> |
| 249 | <input type="text" id="label_id"></input> |
| 250 | <br/> |
| 251 | <label for="label_name">Label name :</label> |
| 252 | <input type="text" id="label_name"></input> |
| 253 | <br/> |
| 254 | <fieldset style="display: inline;clear:both;"> |
| 255 | <legend>Select projects</legend> |
| 256 | <form> |
| 257 | <ul style="list-style-type: none"> |
| 258 | <li> |
| 259 | <input type="checkbox">Top-level</input> |
| 260 | <ul style="list-style-type: none"> |
| 261 | <li> |
| 262 | <input type="checkbox" checked="checked"><b>Family A</b></input> |
| 263 | <ul style="list-style-type: none"> |
| 264 | <li><input type="checkbox">product a</input></li> |
| 265 | <li><input type="checkbox">product b</input></li> |
| 266 | </ul> |
| 267 | </li> |
| 268 | <li> |
| 269 | <input type="checkbox" checked="checked"><b>Family B</b></input> |
| 270 | <ul style="list-style-type: none"> |
| 271 | <li ><input type="checkbox">product c</input></li> |
| 272 | <li><input type="checkbox">product d</input></li> |
| 273 | </ul> |
| 274 | </li> |
| 275 | <li><input type="checkbox">Tools</input></li> |
| 276 | <li><input type="checkbox">3rdParty</input></li> |
| 277 | </ul> |
| 278 | </li> |
| 279 | </ul> |
| 280 | </form> |
| 281 | </fieldset> |
| 282 | <br/> |
| 283 | <button>Ok</button> |
| 284 | <button>Cancel</button> |
| 285 | </div> |
| 286 | </div> |
| 287 | }}} |
| 288 | |
| 289 | === Project selector (tree view) === #LabelsTreeView |
| 290 | |
| 291 | Another option is to provide a more ellaborate version of the box suggested in |
| 292 | [wiki:TracDev/Proposals/MultipleProject Multi-Project Support specification]. |
| 293 | One of the benefits is that it will be possible to select either projects or |
| 294 | labels. It should look like this |
| 295 | |
| 296 | {{{ |
| 297 | #!html |
| 298 | <fieldset style="display: inline" id="SampleProjectTreeView"> |
| 299 | <legend>Project Selector</legend> |
| 300 | <form> |
| 301 | <ul style="list-style-type: none"> |
| 302 | <li> |
| 303 | <input type="checkbox">Top-level</input> |
| 304 | <ul style="list-style-type: none"> |
| 305 | <li> |
| 306 | <input type="checkbox"><b style="background-color: #ffffcc;border:1px dashed #999999;">Family A</b></input> |
| 307 | <ul style="list-style-type: none"> |
| 308 | <li><input type="checkbox">product a</input></li> |
| 309 | <li><input type="checkbox">product b</input></li> |
| 310 | </ul> |
| 311 | </li> |
| 312 | <li> |
| 313 | <input type="checkbox"><b style="background-color: #ffffcc;border:1px dashed #999999;">Family B</b></input> |
| 314 | <ul style="list-style-type: none"> |
| 315 | <li ><input type="checkbox">product c</input></li> |
| 316 | <li><input type="checkbox">product d</input></li> |
| 317 | </ul> |
| 318 | </li> |
| 319 | <li><input type="checkbox">Tools</input></li> |
| 320 | <li><input type="checkbox">3rdParty</input></li> |
| 321 | </ul> |
| 322 | </li> |
| 323 | </ul> |
| 324 | <ul style="list-style-type: none"> |
| 325 | <li style="background-color: #999999; color: #ffffff"> |
| 326 | <input type="checkbox" checked="checked"><b>Product families</b><a href="#SampleProjectTreeView" style="font-size:11px;margin-left:3px;">Edit</a></input> |
| 327 | </li> |
| 328 | <li style="background-color: #CCCCCC"> |
| 329 | <input type="checkbox">Products<a href="#SampleProjectTreeView" style="font-size:11px;margin-left:3px;">Edit</a></input> |
| 330 | </li> |
| 331 | <li style="background-color: #999999; color: #ffffff"> |
| 332 | <input type="checkbox"><b>All except product b</b><a href="#SampleProjectTreeView" style="font-size:11px;margin-left:3px;">Edit</a></input> |
| 333 | </li> |
| 334 | <li> <button>New label ...</button> </li> |
| 335 | </ul> |
| 336 | </form> |
| 337 | </fieldset> |
| 338 | }}} |
| 339 | |
| 340 | Once label is selected then target projects should be highlighted like above. |
| 341 | |
| 342 | Ideally it should be possible to drag a project & drop it on an item |
| 343 | representing a label in order to add that project to that label (a confirmation |
| 344 | box may be shown so as to detect mistakes). |
| 345 | |
| 346 | Label membership editor dialog box may be displayed as well so as to edit a |
| 347 | label if user clicks on ''Edit'' link. |
| 348 | |
| 349 | == Appendix A : Other systems supporting labels == #SimilarSystems |
| 350 | |
| 351 | Other similar examples of the use of labels in other products are : |
| 352 | |
| 353 | - [http://support.google.com/plus/bin/answer.py?hl=en&answer=1047805&topic=1257347&ctx=topic Google+ circles] which allow to group people, |
| 354 | - ''GMail contact groups'' which serve to a similar purpose |
| 355 | - ''GMail labels'' which allow to mark e-mails |
| 356 | |
| 357 | Other instances of similar label hierarchies : |
| 358 | |
| 359 | - ''GMail'' nested labels. |
| 360 | |
| 361 | == Appendix B : Proposed label hierarchy for Trac-Hacks == #TracHacksLabels |
| 362 | |
| 363 | This section considers just a subset of |
| 364 | [http://trac-hacks.org Trac-Hacks] classifiers. |
| 365 | |
| 366 | {{{ |
| 367 | |
| 368 | +-- supported-version |
| 369 | | +-- 0.1 |
| 370 | | +-- 0.10 |
| 371 | | +-- 0.10.4 |
| 372 | | +-- 0.11 |
| 373 | | +-- 0.11.5 |
| 374 | | +-- 0.11.6 |
| 375 | | +-- 0.12 |
| 376 | | +-- 0.12-compatible |
| 377 | | +-- 0.12dev |
| 378 | | +-- 0.13 |
| 379 | | +-- 0.3.4 |
| 380 | | +-- 0.4 |
| 381 | | +-- 0.5 |
| 382 | | +-- 0.5dev |
| 383 | | +-- 0.8 |
| 384 | | +-- 0.9 |
| 385 | | +-- 0.9.1 |
| 386 | | +-- 0.9.2 |
| 387 | | +-- 0.9.6 |
| 388 | | +-- 1.1dev |
| 389 | | +-- trunk |
| 390 | | +-- anyrelease |
| 391 | +-- db |
| 392 | | +-- sql |
| 393 | | +-- sqlalchemy |
| 394 | | +-- sqlite |
| 395 | | | +-- sqlite3 |
| 396 | | +-- postgresql |
| 397 | | +-- mysql |
| 398 | +-- plugin |
| 399 | | +-- macro |
| 400 | | +-- theme |
| 401 | +-- scripts |
| 402 | +-- patch |
| 403 | +-- integration |
| 404 | +-- translation |
| 405 | +-- workflow |
| 406 | |
| 407 | }}} |