You are browsing the documentation for iTop 3.0 which is not the current version.

Consider browsing to iTop 3.1 documentation

Create a new portal

Prerequisite: You must be familiar with the Syntax used in Tutorials and have already created an extension.

learning:
Create a new portal from scratch
level:
Advanced
domains:
XML
min version:
2.7.0

In this tutorial, we will see what is required to create a new portal from scratch.

You still need to check the Portal XML reference as it provides all customization possibilities, while this tutorial does not.
You may read the Portal customization Overview if the below tutorial is too detailled for you.

Portal declaration

First you will have to declare that portal in XML.

  • You will specify, which users can access it and which cannot. But rather than specifying the Users, you will specify the profiles.
  • Note that the console, is a portal with a specific id (id=backoffice), but it works the same in terms of allowing or denying profiles.

Default declaration

Here is how it is declared within iTop out of the box:

itop_design
  <portals>
    <portal id="itop-portal"> <!-- This is the User Portal -->
      <...>
      <allow/> <!-- No specified profiles, means all allowed -->
      <deny/>  <!-- No restriction, which explain why normal console users have access -->
    </portal>
    <portal id="backoffice">  <!-- This is the Console -->
      <...>     
      <allow/> <!-- allow or deny can be used, combination is supported but wierd -->
      <deny>   <!-- Users having one of the below profiles, will be denied -->
        <profile id="Portal user"/>  
      </deny>  <!-- deny takes precedence on allow -->
    </portal>    
  </portals>

What do we want?

In this example, we will imagine that we want to create a new portal, but keep also the standard User Portal (id=itop-portal) and of course keep the Console

When you start to have more than 2 portals, it's a bit more complicated to define profiles. You have to imagine all the cases, but a combination of allowed and denied profiles, can quickly end up in deadlock

The new portal must be restricted to users having a newly created profile Extension Publisher. Those users must not have access to the console and may or may not have access to the standard itop-portal, depending on if they have Portal user profile or not.

Users of my company, do not have Portal user profile otherwise they could not access the console, which they need to. But they still can access the itop-portal. Let's suppose that I want to allow them to access the new portal also. In that case I will create a new profile “XX employee” where XX is my company name.

Possible declaration

Here is one way to declare the 3 portals, to achive the above requirements:

itop_design
  <portals>
    <portal id="backoffice" _delta="must_exist">
      <deny _delta="redefine">
        <profile id="Portal user"/>
        <profile id="Extension Publisher"/>
      </deny>
    </portal>
    <portal id="itop-portal" _delta="must_exist">
      <allow _delta="redefine">
        <profile id="Portal user"/>
        <profile id="XX employee"/>
       </allow>
    </portal>
    <portal id="extension-publisher-portal" _delta="define">
      <url>pages/exec.php?exec_module=itop-portal-base&amp;exec_page=index.php&amp;portal_id=extension-publisher-portal</url>
      <rank>1.0</rank>
      <handler/>
      <allow>
        <profile id="Extension Publisher"/>
        <profile id="XX employee"/>
      </allow>
      <deny/>
    </portal>
  </portals>

Portal design

You need to specify:

  • classes: which classes and objects will be displayed in the portal
  • forms: for each class, fields visibility and layout in creation, vizualisation and edition
  • bricks: define the menus and bricks allowing to navigate

Classes / Scopes

Scopes are required to specify explicitly the classes which will be used in the portal. Unless you have defined a scope for a given class, that class will never be visible in the portal, regardless of your profile. You could well be Administrator that it would not be enough.

What user can see

  • A scope will define within a class, the instances of objects that the users can see.
  • The below example specify a read scope, which is applicable to all users accessing the portal, not because the id is “all” but because there is no <allowed_profiles> tag specified for this scope, which means all profiles are allowed.
itop_design / module_designs / module_design@itop-portal / classes / class@Ticket / scopes
  <scope id="all">
    <oql_view><![CDATA[SELECT Ticket WHERE (Condition1) ]]></oql_view>
  </scope>
  • a scope can be limited to users having a particular profile, with the <allowed_profiles> tag.
  • If multiple scopes applies to a user, then they are combined with a UNION.

Example users with profile Portal power user can see Tickets defined by the scope “power”

itop_design / module_designs / module_design@itop-portal / classes / class@Ticket / scopes
  <scope id="power">
    <oql_view><![CDATA[SELECT Ticket WHERE (Condition2) ]]></oql_view>
    <allowed_profiles>
      <allowed_profile id="Portal power user"/>
    </allowed_profiles>
  <scope>

But they can see also tickets included in the scope “all”, as a result they will see any Ticket returned by this OQL

  SELECT Ticket WHERE (Condition1)   UNION   SELECT Ticket WHERE (Condition2)
A scope cannot enlarge the rights provides by the user's profiles, it can only restrict them further.
But a scope can bypass the Allowed organizations limitation put on the users:
  • A portal user, might be restricted to his own organization, by setting Allowed organizations on his iTop user. That's quite common, especially for Service providers. Nevertheless, this Organizations restriction defined at the user level, can be overwritten by a portal scope.
    • It's not automatic and the scope must explicitely mention that the allowed organizations of the users must be ignored.
    • It applies for this scope and this one only.
    • An example of this tag can be found on the standard “User portal”, to enable users to see the catalogue of Services, despite they do not belong to the user's organization
itop_design / module_designs / module_design@itop-portal / classes / class@Service / scopes
    <class id="Service">
      <scopes>
        <scope id="all">
          <oql_view>
            <![CDATA[
               SELECT Service AS s JOIN lnkCustomerContractToService AS l1 ON l1.service_id=s.id 
                  JOIN CustomerContract AS cc ON l1.customercontract_id=cc.id 
                  WHERE cc.org_id = :current_contact->org_id AND s.status != 'obsolete'
            ]]>
          </oql_view>
          <ignore_silos>true</ignore_silos>
        </scope>
      </scopes>
    </class>

Tip 1 Because of the UserProfileBrick which must be activated on any portal, the below scope must also be declared on every portal

itop_design / module_designs / module_design@my-portal
<class id="User">
  <scopes>
    <scope id="all">
      <oql_view>
        <![CDATA[SELECT User AS U JOIN Person AS P ON U.contactid=P.id WHERE P.id = :current_contact_id]]>
      </oql_view>
    </scope>
  </scopes>
</class>

Tip 2

If portal users need to add attachments or edit TagSet fields, portal users will have to be allowed for read on the special group All classes (*)
itop_design / user_rights / profiles / profile@my-new-profiles / groups
          <group id="*">
            <actions>
              <action id="action:read">allow</action>
            </actions>
          </group>

Sidenote for Combodo customers: Classes Attachments and TagSetFieldDataFor_class__field_code cannot be put in groups in the ITSM Designer in January 2021.

Tip 3

A portal user must always be allowed on his own organization, otherwise he cannot access the Portal.

Tip 4

If the class Person has an AttributeImage without a default value, this crashes the User Portal

What user can modify

  • The scope can also define the objects that the users can modify. A user is never alloweds to modify an object that he cannot see, so when specifying what he can modify, just specify additional restriction if needed. For example if the user should be allowed to modify any Ticket that he can see, then
itop_design / module_designs / module_design@itop-portal / classes / class@Ticket / scopes
  <scope id="all"> 
    <oql_edit><![CDATA[SELECT Ticket]]></oql_edit>

will do the job, regardless of the <oql_view> queries applying to the user.

Other example with more restriction on the Tickets which can be modified versus those which can be viewed

itop_design / module_designs / module_design@itop-portal / classes / class@Ticket / scopes
  <scope id="all">
    <oql_view><![CDATA[SELECT Ticket WHERE (Condition3) ]]></oql_view> 
    <oql_edit><![CDATA[SELECT Ticket WHERE (Condition4) ]]></oql_edit>

Then users will be only allowed to modify Tickets returned by this OQL

SELECT Ticket WHERE (Condition1) AND (Condition2)
You may define a Portal, in which a user could create or modify an object which he could not see anymore just after his creation/modification, because the object would not/no more be included in his scopes

Classes / others

Deny transitions

Allow to prevent users with some profile, to perform transitions that they are allowed to do in general, but that should not do it in this Portal, but rather on the Console or on another portal.

FIXME Propose an example of denying transitions on Ticket for Support Agent

Lists display

This part allow to specify which fields from a given class, should be displayed when those objects are inside the form of another class, as a LinkedSet or LinkedSetIndirect attributes. If not specified, then the list of fields displayed will be the same as in the console, which may be fine.

FIXME add example of contacts within Ticket with screenshot

Forms

A form specify how objects of a class are displayed in the portal, including fields presentation and their flags: read only, writable, mandatory.

For a given class, you can have only one single form, defining how to visualize the objects.

This means that you cannot:
  • show or hide some fields based on the user profiles
  • show or hide some fields based on object status

In fact you can have different forms per object, assuming they are used in different situations (modes). You can have at maximum:

  • one form for object creation,
  • one form for modification,
  • one form for visualization,
  • and a form for each transition.

Those forms can be specific to a case or reuse in multiple situations.

Bricks

UrlMaker

UrlMaker classes allows iTop to build URLs pointing to a specific GUI (eg. your new portal). If no UrlMaker is registered for the portal, URL will be malformed in several places (eg. in notifications).

To do so, you should also have at least one class extending the AbstractPortalUrlMaker class to overload the default behavior portal ID with the new portal ID. Then register it so it can be used in the portal, notifications and such.

<?php
 
use Combodo\iTop\Portal\UrlMaker\AbstractPortalUrlMaker;
 
require_once APPROOT.'/lib/autoload.php';
 
/**
 * Hyperlinks to the "edition" of the object (vs view)
 */
class ThirdPartyDevelopersPortalEditUrlMaker extends AbstractPortalUrlMaker
{
        const PORTAL_ID = 'extension-publisher-portal';
}
 
/**
 * Hyperlinks to the "view" of the object (vs edition)
 */
class ThirdPartyDevelopersPortalViewUrlMaker extends MyPortalEditUrlMaker
{
        /**
         * @inheritDoc
         */
        public static function MakeObjectURL($sClass, $iId)
        {
                return static::PrepareObjectURL($sClass, $iId, 'view');
        }
 
}
 
// Default portal hyperlink (for notifications) is the edit hyperlink
DBObject::RegisterURLMakerClass('extension-publisher-portal', 'ThirdPartyDevelopersPortalEditUrlMaker');

Full XML

itop_design / module_designs
  <bricks>
    <brick id="user-profile" xsi:type="Combodo\iTop\Portal\Brick\UserProfileBrick">
      <rank>
        <!-- Can be either a <default> tag for both home page and navigation menu or distinct <home> or/and <navigation_menu> tags-->
        <default>1</default>
      </rank>
      <title>
        <!-- Can be either a <default> tag for both home page and navigation menu or distinct <home> or/and <navigation_menu> tags-->
        <default>Brick:Portal:UserProfile:Navigation:Dropdown:MyProfil</default>
      </title>
      <decoration_class>
        <default>fas fa-user fa-2x</default>
      </decoration_class>
      <!-- Show / hide some of the user profile forms by setting the tag value to true|false -->
      <!--<show_picture_form>true</show_picture_form>-->
      <!--<show_preferences_form>true</show_preferences_form>-->
      <!--<show_password_form>true</show_password_form>-->
      <form>
        <!-- Optional tag to list the fields. If empty only fields from <twig> tag will be displayed, if omitted fields from zlist details will. -->
        <fields/>
        <!-- Optional tag to specify the form layout. Fields that are not positioned in the layout will be placed at the end of the form -->
        <twig>
          <!-- data-field-id attribute must be an attribute code of the class -->
          <!-- data-field-flags attribute contains flags among read_only/hidden/mandatory/must_prompt/must_change -->
          <div class="form_field" data-field-id="first_name" data-field-flags="read_only">
                                                        </div>
          <div class="form_field" data-field-id="name" data-field-flags="read_only">
                                                        </div>
          <div class="form_field" data-field-id="org_id" data-field-flags="read_only">
                                                        </div>
          <div class="form_field" data-field-id="email" data-field-flags="read_only">
                                                        </div>
          <div class="form_field" data-field-id="phone">
                                                        </div>
          <div class="form_field" data-field-id="location_id">
                                                        </div>
          <div class="form_field" data-field-id="function">
                                                        </div>
          <div class="form_field" data-field-id="manager_id" data-field-flags="read_only">
                                                        </div>
        </twig>
      </form>
    </brick>
    <brick id="services" xsi:type="Combodo\iTop\Portal\Brick\BrowseBrick">
      <active>true</active>
      <width>6</width>
      <rank>
        <default>10</default>
      </rank>
      <title>
        <default>Brick:Portal:NewRequest:Title</default>
      </title>
      <description>Brick:Portal:NewRequest:Title+</description>
      <decoration_class>
        <default>fc fc-new-request fc-2x</default>
      </decoration_class>
      <!-- <fields  /> Optional tag to add attributes to the table by their code, can be specified for each level -->
      <levels>
        <level id="1">
          <class>ServiceFamily</class>
          <image_att>icon</image_att>
          <levels>
            <!-- Level IDs must be numeric -->
            <level id="1">
              <!-- Can be either a class tag with the class name or an oql tag with the query -->
              <class>Service</class>
              <!-- Attribute code of the above class [from the OQL] that point to the upper level class -->
              <parent_att>servicefamily_id</parent_att>
              <!-- Attribute code of the above class [from the OQL] used to display the object name, default is 'name'. -->
              <name_att/>
              <!-- Attribute code of the above class [from the OQL] used to display in a tooltip when mouse is over the object -->
              <tooltip_att>description</tooltip_att>
              <!-- Attribute code of the above class [from the OQL] used to display a small text beside the object's name -->
              <!-- Note: This is not used in "list" mode -->
              <description_att>description</description_att>
              <!-- Attribute code of the above class [from the OQL] used to display a image beside the object's name -->
              <!-- Note: This is used in "mosaic" mode only for now -->
              <image_att>icon</image_att>
              <!-- Title of the level, will be display in lists and others browse modes -->
              <title>Class:Service</title>
              <!-- Optional tag to add attributes to the table by their code, can be specified for each level -->
              <!-- Note: Fields will only be displayed in "list" mode but will still be used for filter in other modes -->
              <!-- <fields  /> -->
              <!-- Can be empty on intermediate levels, default is drilldown -->
              <actions>
                <action id="drilldown" xsi:type="drilldown"/>
              </actions>
              <levels>
                <level id="1">
                  <!-- Note : We could have used just a class tag and put the OQL in the scope for everybody -->
                  <oql><![CDATA[SELECT ServiceSubcategory WHERE ServiceSubcategory.status != 'obsolete']]></oql>
                  <parent_att>service_id</parent_att>
                  <name_att/>
                  <tooltip_att>description</tooltip_att>
                  <description_att>description</description_att>
                  <title>Class:ServiceSubcategory</title>
                  <actions>
                    <action id="create_from_this" xsi:type="create_from_this">
                      <!-- Can be either a class tag containing the class of the object to create, or a static method taking the origin object as a parameter and that will return a object of the desired class -->
                      <!-- (eg. \Ticket::FromServiceSubcategory($oOrigin) that should return either a UserRequest or Incident regarding the request type) -->
                      <class>UserRequest</class>
                      <!-- Optional tag that can be used on any action type -->
                      <!--<title>Create a ticket</title>-->
                      <!-- Optional tag to define if the action should be done in a modal window ("modal"), a new window ("new") or the current window ("self") -->
                      <!--<opening_target>modal</opening_target>-->
                      <icon_class>fc fc-new-request fc-1-6x fc-flip-horizontal</icon_class>
                      <!-- Optional tag to order actions -->
                      <!--<rank>1</rank>-->
                      <rules>
                        <rule id="contact-to-userrequest"/>
                        <rule id="servicesubcategory-to-userrequest"/>
                        <rule id="go-to-open-request-on-submit"/>
                      </rules>
                    </action>
                    <action id="view" xsi:type="view"/>
                  </actions>
                  <levels/>
                </level>
              </levels>
            </level>
          </levels>
        </level>
      </levels>
      <browse_modes>
        <availables>
          <mode id="list"/>
          <mode id="tree"/>
          <mode id="mosaic"/>
        </availables>
        <default>list</default>
      </browse_modes>
      <!-- Optional. Set the default number of item lists will display. -->
      <!-- <default_list_length>20</default_list_length> -->
      <data_loading>auto</data_loading>
      <!-- lazy|full|auto. Let the consultant choose if the list/tree data are load progressively at each page/level or in one-shot or if it is up to the system regarding the "lazy_loading_threshold" parameter -->
    </brick>
    <brick id="ongoing-tickets-for-portal-user" xsi:type="Combodo\iTop\Portal\Brick\ManageBrick">
      <active>true</active>
      <rank>
        <default>20</default>
      </rank>
      <width>6</width>
      <title>
        <default>Brick:Portal:OngoingRequests:Title</default>
      </title>
      <!-- Optional tag to define which display modes can be used in the brick's page and the brick's tile -->
      <!--<display_modes>-->
      <!-- Optional tag that must contain at least 1 <mode> tag. -->
      <!--<availables>-->
      <!--<mode id="list"/>-->
      <!--<mode id="pie-chart"/>-->
      <!--<mode id="bar-chart"/>-->
      <!--</availables>-->
      <!-- Optional tag to define which display mode will be used by default when opening the brick -->
      <!--<default>list</default>-->
      <!-- Optional tag to define which display mode will be used to render the brick's tile -->
      <!--<tile>text</tile>-->
      <!--</display_modes>-->
      <description>Brick:Portal:OngoingRequests:Title+</description>
      <decoration_class>
        <default>fc fc-ongoing-request fc-2x</default>
      </decoration_class>
      <oql><![CDATA[SELECT Ticket]]></oql>
      <!-- Optional tag to define if the action should be done in a modal window ("modal"), a new window ("new") or the current window ("self") -->
      <!--<opening_target>modal</opening_target>-->
      <!-- Optional tag to define the how the objects should be opened. Values can be edit|view. Note that even if this is set to edit, objects not allowed in edition mode for the user (cf. scopes and security layers) will open in view mode -->
      <!-- <opening_mode>edit</opening_mode> -->
      <!-- Can be either a class tag with the class name or an oql tag with the query -->
      <!-- <class>Ticket</class> -->
      <fields>
        <field id="title"/>
        <field id="start_date"/>
        <field id="status"/>
        <field id="service_id"/>
        <field id="servicesubcategory_id"/>
        <field id="priority"/>
        <field id="caller_id"/>
      </fields>
      <!-- Optional tag to add attributes to the table by their code -->
      <grouping>
        <!-- Mandatory -->
        <tabs>
          <!-- Optional. Show object count for each tabs. Available values are true|false. Default is false. -->
          <show_tab_counts>true</show_tab_counts>
          <!-- Mandatory. Grouping by tabs -->
          <!--<attribute>operational_status</attribute>-->
          <!-- attribute xor groups tag -->
          <groups>
            <!-- Can be used only with ../oql tag, not ../class tag. Reason is that we can't know the class alias to apply to the condition's fields. We might have an exception saying that the field in ambiguous for the generated query. -->
            <group id="opened">
              <rank>1</rank>
              <title>Brick:Portal:OngoingRequests:Tab:OnGoing</title>
              <!-- Optional. A string or dictionary entry to display under the page title for this tab -->
              <!-- <description>Brick:Portal:OngoingRequests:Tab:OnGoing+</description> -->
              <condition><![CDATA[SELECT Ticket AS T WHERE operational_status NOT IN ('closed', 'resolved')]]></condition>
            </group>
            <group id="resolved">
              <rank>2</rank>
              <title>Brick:Portal:OngoingRequests:Tab:Resolved</title>
              <condition><![CDATA[SELECT Ticket AS T WHERE operational_status = 'resolved']]></condition>
            </group>
          </groups>
        </tabs>
        <!-- Implicit grouping on y axis by finalclass -->
      </grouping>
      <!-- Optional. Set the default number of item lists will display. -->
      <!-- <default_list_length>20</default_list_length> -->
      <data_loading>full</data_loading>
      <export>
        <export_default_fields>true</export_default_fields>
      </export>
    </brick>
    <brick id="closed-tickets-for-portal-user" xsi:type="Combodo\iTop\Portal\Brick\ManageBrick">
      <active>true</active>
      <rank>
        <navigation_menu>50</navigation_menu>
      </rank>
      <visible>
        <home>false</home>
      </visible>
      <width>12</width>
      <title>
        <default>Brick:Portal:ClosedRequests:Title</default>
      </title>
      <description/>
      <decoration_class>
        <default>fc fc-closed-request fc-2x</default>
      </decoration_class>
      <oql><![CDATA[SELECT Ticket WHERE operational_status = 'closed']]></oql>
      <!-- Can be either a class tag with the class name or an oql tag with the query -->
      <!-- <class>Ticket</class> -->
      <fields>
        <field id="finalclass"/>
        <field id="title"/>
        <field id="start_date"/>
        <field id="status"/>
        <field id="servicesubcategory_id"/>
        <field id="priority"/>
        <field id="caller_id"/>
      </fields>
      <grouping>
        <tabs>
          <!-- Optional. Show object count for each tabs. Available values are true|false. Default is false. -->
          <!--<show_tab_counts>false</show_tab_counts>-->
          <groups>
            <group id="all">
              <rank>1</rank>
              <title>Brick:Portal:ClosedRequests:Title</title>
              <condition><![CDATA[SELECT Ticket]]></condition>
            </group>
          </groups>
        </tabs>
        <!-- Implicit grouping on y axis by finalclass -->
      </grouping>
      <data_loading>auto</data_loading>
      <export>
        <export_default_fields>true</export_default_fields>
      </export>
    </brick>
    <brick id="approvals" xsi:type="Combodo\iTop\Portal\Brick\ApprovalBrick">
      <!-- TODO: restreindre les droits de visibilité à cette brique -->
      <active>true</active>
      <rank>
        <default>60</default>
      </rank>
      <width>12</width>
      <title>
        <default>Approval:Portal:Menu</default>
      </title>
      <description>Approval:Portal:Menu+</description>
      <decoration_class>
        <default>fa fa-check-circle fa-2x</default>
      </decoration_class>
      <classes>
        <!-- Class to be considered (inc. derived classes) -->
        <class id="UserRequest">
          <fields>
            <field id="title"/>
            <field id="start_date"/>
            <field id="status"/>
            <field id="service_id"/>
            <field id="servicesubcategory_id"/>
            <field id="priority"/>
            <field id="caller_id"/>
          </fields>
        </class>
      </classes>
      <!-- TODO: get rid of this? -->
      <data_loading>full</data_loading>
    </brick>
    <brick id="communication" xsi:type="Combodo\iTop\Portal\Brick\CommunicationBrick">
      <!-- Should be the class name (eg : CommunicationBrick) -->
      <active>true</active>
      <!-- yes|no -->
      <rank>1</rank>
      <!-- float -->
      <height>15</height>
      <!-- integer , size in em -->
      <width>12</width>
      <!-- integer , must be between 1 and 12 -->
      <title>Portal:Communications</title>
      <!-- string -->
      <oql/>
      <!-- Query for the displayed communications (if authorized to the current user, see Communication::IsAllowedToUser). Leave empty to preserve the default behavior. Use :now instead of NOW(). -->
      <security>
        <!-- Order is deny/allow Pseudo OQL traduction : WHERE user_profile NOT IN (:denied_profiles) AND user_profile IN (:allowed_profiles) -->
        <denied_profiles/>
        <!-- OQL query. Used only when not empty -->
        <allowed_profiles/>
        <!-- OQL query. Used only when not empty -->
      </security>
    </brick>
  </bricks>
  <forms>
    <form id="service-view">
      <class>Service</class>
      <fields/>
      <twig>
        <div class="row">
          <div class="col-sm-6">
            <div class="form_field" data-field-id="name">
                                                                </div>
            <div class="form_field" data-field-id="description">
                                                                </div>
          </div>
          <div class="col-sm-6">
            <div class="form_field" data-field-id="org_id">
                                                                </div>
            <div class="form_field" data-field-id="servicefamily_id">
                                                                </div>
            <div class="form_field" data-field-id="status">
                                                                </div>
          </div>
        </div>
      </twig>
      <modes>
        <mode id="view"/>
      </modes>
    </form>
    <form id="servicesubcategory">
      <class>ServiceSubcategory</class>
      <!-- Optional tag to list the fields. If empty only fields from <twig> tag will be displayed, if omitted fields from zlist details will. -->
      <fields/>
      <!-- Optional tag to specify the form layout. Fields that are not positioned in the layout will be placed at the end of the form -->
      <twig>
        <div class="row">
          <div class="col-sm-6">
            <!-- data-field-id attribute must be an attribute code of the class -->
            <div class="form_field" data-field-id="service_id">
                                                                </div>
            <!-- data-field-flags attribute contains flags among read_only/hidden/mandatory/must_prompt/must_change -->
            <div class="form_field" data-field-id="name" data-field-flags="read_only">
                                                                </div>
            <div class="form_field" data-field-id="status" data-field-flags="read_only">
                                                                </div>
          </div>
          <div class="col-sm-6">
            <div class="form_field" data-field-id="service_org_id">
                                                                </div>
            <div class="form_field" data-field-id="request_type">
                                                                </div>
          </div>
        </div>
        <div>
          <div class="form_field" data-field-id="description">
                                                        </div>
        </div>
      </twig>
    </form>
    <form id="ticket-create">
      <class>Ticket</class>
      <properties>
        <navigation_rules>
          <submit>
            <default>go-to-open-requests</default>
          </submit>
        </navigation_rules>
      </properties>
      <fields/>
      <twig>
        <div class="row">
          <div class="col-sm-6">
            <div class="form_field" data-field-id="service_id" data-field-flags="mandatory">
                                                                </div>
          </div>
          <div class="col-sm-6">
            <div class="form_field" data-field-id="servicesubcategory_id" data-field-flags="mandatory">
                                                                </div>
          </div>
        </div>
        <div id="service_details_placeholder">
          <div class="form_field" data-field-id="service_details">
                                                        </div>
        </div>
        <div class="row">
          <div class="col-sm-6">
            <div class="form_field" data-field-id="impact">
                                                                </div>
          </div>
          <div class="col-sm-6">
            <div class="form_field" data-field-id="urgency">
                                                                </div>
          </div>
        </div>
        <div>
          <div class="form_field" data-field-id="title">
                                                        </div>
          <div class="form_field" data-field-id="description">
                                                        </div>
          <div class="form_field" data-field-id="contacts_list">
                                                        </div>
        </div>
      </twig>
      <modes>
        <!-- mode id can among create / edit / view -->
        <mode id="create"/>
      </modes>
    </form>
    <form id="ticket-edit">
      <class>Ticket</class>
      <properties>
        <!-- Optional, display mode of the form fields. "cosy" for a regular labels over values layout; "compact" for a side-by-side
                                             layout with input aligned; "dense" for a side-by-side layout with input filling all available space. You can also use a custom css class that will be used on the form as "form_xxx", as well as on the fields as "form_field_xxx".-->
        <!--<display_mode>cosy</display_mode>-->
        <!-- Optional, when set to false, submit button is hidden when transitions are available on the object (in creation and edit
                                             mode). Default is false. -->
        <!--<always_show_submit>false</always_show_submit>-->
        <!-- Optional, navigation rules to define where to go when clicking on the submit/cancel buttons of the form -->
        <navigation_rules>
          <submit>
            <default>go-to-open-requests</default>
          </submit>
        </navigation_rules>
      </properties>
      <fields/>
      <twig>
        <div class="row">
          <div class="col-sm-7">
            <fieldset>
              <legend>{{'Ticket:baseinfo'|dict_s}}</legend>
              <div class="col-sm-6">
                <div class="form_field" data-field-id="title" data-field-flags="read_only"/>
                <div class="form_field" data-field-id="service_id" data-field-flags="read_only"/>
              </div>
              <div class="col-sm-6">
                <div class="form_field" data-field-id="caller_id" data-field-flags="read_only"/>
                <div class="form_field" data-field-id="servicesubcategory_id" data-field-flags="read_only"/>
              </div>
              <div class="col-sm-12">
                <div class="form_field" data-field-id="description" data-field-flags="read_only"/>
                <div class="form_field" data-field-id="solution" data-field-flags="read_only"/>
              </div>
              <div class="col-sm-6">
                <div class="form_field" data-field-id="user_satisfaction" data-field-flags="read_only"/>
              </div>
              <div class="col-sm-6">
                <div class="form_field" data-field-id="user_comment" data-field-flags="read_only"/>
              </div>
            </fieldset>
          </div>
          <div class="col-sm-5">
            <fieldset>
              <legend>{{'Ticket:Type'|dict_s}} &amp; {{'Ticket:date'|dict_s}}</legend>
              <div class="col-sm-6">
                <div class="form_field" data-field-id="status" data-field-flags="read_only"/>
                <div class="form_field" data-field-id="impact" data-field-flags="read_only"/>
                <div class="form_field" data-field-id="urgency" data-field-flags="read_only"/>
                <div class="form_field" data-field-id="priority" data-field-flags="read_only"/>
              </div>
              <div class="col-sm-6">
                <div class="form_field" data-field-id="start_date" data-field-flags="read_only"/>
                <div class="form_field" data-field-id="last_update" data-field-flags="read_only"/>
                <div class="form_field" data-field-id="resolution_date" data-field-flags="read_only"/>
                <div class="form_field" data-field-id="agent_id" data-field-flags="read_only"/>
              </div>
            </fieldset>
          </div>
        </div>
        <div>
          <div class="form_field" data-field-id="contacts_list"/>
          <div class="form_field" data-field-id="public_log"/>
        </div>
      </twig>
      <modes>
        <mode id="edit"/>
        <mode id="view"/>
      </modes>
    </form>
    <form id="ticket-reopen">
      <class>Ticket</class>
      <properties>
        <navigation_rules>
          <submit>
            <default>go-to-open-requests</default>
          </submit>
        </navigation_rules>
      </properties>
      <fields/>
      <twig>
        <div>
          <div class="form_field" data-field-id="public_log" data-field-flags="must_change"/>
          <div class="form_field" data-field-id="team_id" data-field-flags="hidden"/>
          <div class="form_field" data-field-id="agent_id" data-field-flags="hidden"/>
        </div>
      </twig>
      <modes>
        <mode id="apply_stimulus">
          <stimuli>
            <stimulus id="ev_reopen"/>
          </stimuli>
        </mode>
      </modes>
    </form>
    <form id="ticket-apply-stimulus">
      <class>Ticket</class>
      <properties>
        <navigation_rules>
          <submit>
            <default>go-to-open-requests</default>
          </submit>
        </navigation_rules>
      </properties>
      <fields/>
      <twig/>
      <modes>
        <mode id="apply_stimulus"/>
      </modes>
    </form>
    <form id="person-view">
      <class>Person</class>
      <fields/>
      <twig>
        <div class="row">
          <div class="col-sm-4">
            <div class="form_field" data-field-id="picture" data-field-flags="read_only">
                                                                </div>
          </div>
          <div class="col-sm-4">
            <div class="form_field" data-field-id="name" data-field-flags="read_only">
                                                                </div>
            <div class="form_field" data-field-id="first_name" data-field-flags="read_only">
                                                                </div>
            <div class="form_field" data-field-id="status" data-field-flags="read_only">
                                                                </div>
          </div>
          <div class="col-sm-4">
            <div class="form_field" data-field-id="org_id" data-field-flags="read_only">
                                                                </div>
            <div class="form_field" data-field-id="function" data-field-flags="read_only">
                                                                </div>
            <div class="form_field" data-field-id="manager_id" data-field-flags="read_only">
                                                                </div>
          </div>
        </div>
      </twig>
    </form>
  </forms>
    <action_rules>
    <action_rule id="contact-to-userrequest">
      <!-- source_oql|source_class is only necessary if there is some copy preset|retrofit -->
      <source_oql><![CDATA[SELECT Contact AS C WHERE C.id = :current_contact_id]]></source_oql>
      <presets>
        <!-- Only set() and copy() are supported for now -->
        <preset id="1">set(caller_id, $current_contact_id$)</preset>
        <preset id="2">copy(org_id, org_id)</preset>
        <preset id="3">set(origin, portal)</preset>
      </presets>
      <retrofits/>
    </action_rule>
    <action_rule id="service-to-userrequest">
      <source_class>Service</source_class>
      <presets>
        <preset id="1">copy(id, service_id)</preset>
      </presets>
    </action_rule>
    <action_rule id="servicesubcategory-to-userrequest">
      <source_class>ServiceSubcategory</source_class>
      <presets>
        <preset id="1">copy(id, servicesubcategory_id)</preset>
        <preset id="2">copy(service_id, service_id)</preset>
      </presets>
    </action_rule>
    <!-- Deprecated, will be removed in iTop 2.8 -->
    <action_rule id="go-to-open-request-on-submit">
      <submit xsi:type="goto">
        <brick>ongoing-tickets-for-portal-user</brick>
      </submit>
    </action_rule>
  </action_rules>
  <navigation_rules>
    <!-- Close form (either the modal or the whole page) -->
    <navigation_rule id="close-form" xsi:type="close"/>
    <!-- Go to the homepage -->
    <navigation_rule id="go-to-homepage" xsi:type="go-to-homepage"/>
    <!-- Open a manage brick (simple method) -->
    <navigation_rule id="go-to-open-requests" xsi:type="go-to-manage-brick">
      <!-- Mandatory, ID of the ManageBrick to go to -->
      <id>ongoing-tickets-for-portal-user</id>
      <!-- Optional, must be an ID of the available display modes of the brick (//brick/display_modes/availables/mode) -->
      <!-- <display_mode>list</mode> -->
      <!-- Optional, must be an ID of the grouping tab of the brick (//brick/grouping/tabs/groups/group)-->
      <!-- <grouping_tab>resolved</grouping_tab> -->
      <!-- Optional, a string to preset as filter in the brick. ":this->XXX" can be used for the current object -->
      <!-- <filter>:this->caller_id_friendlyname</filter> -->
    </navigation_rule>
    <!-- Open a browse brick -->
    <navigation_rule id="go-to-services" xsi:type="go-to-browse-brick">
      <!-- Mandatory, ID of the BrowseBrick to go to -->
      <id>services</id>
      <!-- Optional, must be an ID of the available browse modes of the brick (//brick/browse_modes/availables/mode) -->
      <!-- <browse_mode>tree</browse_mode> -->
      <!-- Optional, a string to preset as filter in the brick. ":this->XXX" can be used for the current object -->
      <!-- <filter>computer</filter> -->
    </navigation_rule>
    <!-- Open a brick, developer method -->
    <!-- <navigation_rule id="go-to-open-requests-alternate-way" xsi:type="go-to-brick"> -->
    <!-- <route> -->
    <!-- <id>p_manage_brick_display_as</id> -->
    <!-- <params> -->
    <!-- <param id="sBrickId">ongoing-tickets-for-portal-user</param> -->
    <!-- <param id="sDisplayMode">pie-chart</param> -->
    <!-- <param id="sGroupingTab">resolved</param> -->
    <!-- </params> -->
    <!-- </route> -->
    <!-- </navigation_rule> -->
  </navigation_rules>
itop_design / module_designs
    <module_design id="combodo-developers-portal" _delta="define">
      <properties>
        <name>Developers portal</name>
        <urlmaker_class>ThirdPartyDevelopersPortalEditUrlMaker</urlmaker_class>
        <triggers_query>
          <![CDATA[SELECT TriggerOnPortalUpdate AS t WHERE t.target_class IN (:parent_classes)]]>
        </triggers_query>
      </properties>
      <classes>
        <class id="User">
          <scopes>
            <scope id="all">
              <oql_view>
                <![CDATA[SELECT User AS U JOIN Person AS P ON U.contactid=P.id WHERE P.id = :current_contact_id]]>
              </oql_view>
            </scope>
          </scopes>
        </class>
        <class id="Organization" _delta="define">
          <scopes>
            <scope id="all">
              <oql_view><![CDATA[SELECT Organization WHERE id = :current_contact->org_id]]></oql_view>
            </scope>
          </scopes>
        </class>
        <class id="Contact" _delta="define">
          <scopes>
            <scope id="all">
              <oql_view><![CDATA[SELECT Contact WHERE org_id = :current_contact->org_id]]></oql_view>
            </scope>
          </scopes>
        </class>
        <class id="Extension" _delta="define">
          <scopes>
            <scope id="all">
              <oql_view><![CDATA[SELECT Extension WHERE org_id = :current_contact->org_id]]></oql_view>
              <oql_edit><![CDATA[SELECT Extension]]></oql_edit>
            </scope>
          </scopes>
        </class>
        <class id="TargetExtension" _delta="define">
          <scopes>
            <scope id="all">
              <oql_view><![CDATA[SELECT TE FROM TargetExtension AS TE JOIN Extension AS E ON TE.extension_id = E.id WHERE E.org_id = :current_contact->org_id]]></oql_view>
              <oql_edit><![CDATA[SELECT TargetExtension]]></oql_edit>
            </scope>
          </scopes>
          <lists>
            <list id="list">
              <items>
                <item id="target_date">
                  <rank>2</rank>
                </item>
                <item id="step">
                  <rank>3</rank>
                </item>
              </items>
            </list>
            <list id="default">
              <items>
                <item id="extension_id">
                  <rank>2</rank>
                </item>
                <item id="step">
                  <rank>3</rank>
                </item>
              </items>
            </list>
          </lists>
        </class>
        <class id="LicenseType" _delta="define">
          <scopes>
            <scope id="all">
              <oql_view><![CDATA[SELECT LicenseType]]></oql_view>
            </scope>
          </scopes>
        </class>
      </classes>
      <action_rules>
        <action_rule id="contact-to-extension">
          <source_oql><![CDATA[SELECT Contact AS C WHERE C.id = :current_contact_id]]></source_oql>
          <presets>
            <preset id="1">copy(org_id, org_id)</preset>
            <preset id="2">set(person_id, $current_contact_id$)</preset>
            <preset id="3">set(category, public)</preset>
            <preset id="4">set(status, beta)</preset>
            <preset id="5">set(acquisition_cost, 0)</preset>
          </presets>
        </action_rule>
        <action_rule id="extension-to-targetextension">
          <source_class>Extension</source_class>
          <presets>
            <preset id="1">copy(id, extension_id)</preset>
            <preset id="2">set(freeze_date,$current_date$)</preset>
          </presets>
        </action_rule>
      </action_rules>
      <navigation_rules>
        <navigation_rule id="go-to-extension" xsi:type="go-to-object">
          <!-- Mandatory, opens the first result from the OQL. Result may vary ¯\_(ツ)_/¯  but ":this" available! -->
          <oql>SELECT Extension WHERE id = :this-&gt;id</oql>
          <!-- Optional, mode of the object form, either view|edit -->
          <mode>edit</mode>
          <!-- Optional, how to open the object form, replace the current form (current), in a modal (modal) or in the page (page) -->
          <opening_target>current</opening_target>
        </navigation_rule>
        <navigation_rule id="go-to-extension-from-targetextension" xsi:type="go-to-object">
          <!-- Mandatory, opens the first result from the OQL. Result may vary ¯\_(ツ)_/¯  but ":this" available! -->
          <oql>SELECT Extension WHERE id = :this-&gt;extension_id</oql>
          <!-- Optional, mode of the object form, either view|edit -->
          <mode>edit</mode>
          <!-- Optional, how to open the object form, replace the current form (current), in a modal (modal) or in the page (page) -->
          <opening_target>current</opening_target>
        </navigation_rule>
        <navigation_rule id="go-to-workshop" xsi:type="go-to-browse-brick">
          <id>workshop</id>
          <browse_mode>mosaic</browse_mode>
        </navigation_rule>
        <navigation_rule id="go-to-version" xsi:type="go-to-object">
          <!-- Mandatory, opens the first result from the OQL. Result may vary ¯\_(ツ)_/¯  but ":this" available! -->
          <oql>SELECT TargetExtension WHERE id = :this-&gt;id</oql>
          <!-- Optional, mode of the object form, either view|edit -->
          <mode>edit</mode>
          <!-- Optional, how to open the object form, replace the current form (current), in a modal (modal) or in the page (page) -->
          <opening_target>current</opening_target>
        </navigation_rule>
        <navigation_rule id="go-to-new-version" xsi:type="go-to-brick">
          <route>
            <id>p_create_brick</id>
            <params>
              <param id="sBrickId">new-version</param>
            </params>
          </route>
        </navigation_rule>
      </navigation_rules>
      <forms>
        <form id="extension-create" _delta="define">
          <class>Extension</class>
          <properties>
            <display_mode>compact</display_mode>
            <navigation_rules>
              <submit>
                <default>go-to-workshop</default>
              </submit>
            </navigation_rules>
          </properties>
          <fields/>
          <twig>
            <div class="row">
              <div class="col-sm-4">
                <fieldset>
                  <legend>General information</legend>
                  <div class="form_field" data-field-id="org_id_friendlyname" data-field-flags="read_only"/>
                  <div class="form_field" data-field-id="name" data-field-flags="mandatory"/>
                  <div class="form_field" data-field-id="build_identifier" data-field-flags="mandatory"/>
                  <div class="form_field" data-field-id="licensetype_id" data-field-flags="mandatory"/>
                </fieldset>
              </div>
              <div class="col-sm-8">
                <fieldset>
                  <legend>Description</legend>
                  <div class="form_field" data-field-id="short" data-field-flags="mandatory" data-field-display-mode="dense"/>
                  <div class="form_field" data-field-id="description" data-field-flags="mandatory"/>
                  <div class="form_field" data-field-id="wiki" data-field-flags="mandatory" data-field-display-mode="dense"/>
                  <div class="form_field" data-field-id="repository_url" data-field-flags="" data-field-display-mode="dense"/>
                  <div class="form_field" data-field-id="images" data-field-flags=""/>
                </fieldset>
              </div>
            </div>
            <br/>
            <div class="alert alert-info">
              <div><b>Important:</b> Upload the cover image as an attachment. it will be used to represent the extension on iTop Hub.</div>
              <ul>
                <li>Accepted formats are JPG/PNG</li>
                <li>File must be named <b>&lt;Extension Code&gt;-icon.jpg</b> or <b>&lt;Extension Code&gt;-icon.png</b></li>
                <li>Size must be 256x170 pixels</li>
              </ul>
            </div>
          </twig>
          <modes>
            <mode id="create"/>
          </modes>
        </form>
        <form id="extension-edit" _delta="define">
          <class>Extension</class>
          <properties>
            <display_mode>compact</display_mode>
          </properties>
          <fields/>
          <twig>
            <div class="row">
              <div class="col-sm-6">
                <fieldset>
                  <legend>General information</legend>
                  <div class="form_field" data-field-id="name" data-field-flags="mandatory"/>
                  <div class="form_field" data-field-id="build_identifier" data-field-flags="read_only"/>
                  <div class="form_field" data-field-id="licensetype_id" data-field-flags="mandatory"/>
                  <div class="form_field" data-field-id="short" data-field-flags="mandatory" data-field-display-mode="dense"/>
                  <div class="form_field" data-field-id="description" data-field-flags="mandatory"/>
                  <div class="form_field" data-field-id="wiki" data-field-flags="mandatory" data-field-display-mode="dense"/>
                  <div class="form_field" data-field-id="repository_url" data-field-flags="" data-field-display-mode="dense"/>
                  <div class="form_field" data-field-id="images" data-field-flags=""/>
                  <div class="form_field" data-field-id="tags" data-field-flags=""/>
                  <div class="form_field" data-field-id="icon" data-field-flags="read_only"/>
                  <div class="form_field" data-field-id="publication_date" data-field-flags="read_only" data-field-display-mode="dense"/>
                  <div class="form_field" data-field-id="last_publication" data-field-flags="read_only" data-field-display-mode="dense"/>
                  <div class="form_field" data-field-id="last_update" data-field-flags="read_only" data-field-display-mode="dense"/>
                  <div class="form_field" data-field-id="org_id_friendlyname" data-field-flags="read_only"/>
                </fieldset>
              </div>
              <div class="col-sm-6">
                <div class="form_field" data-field-id="targetextensions_list" data-field-flags="read_only" data-field-opened="true"/>
                <div class="form_field" data-field-id="log" data-field-flags=""/>
              </div>
            </div>
            <div class="alert alert-info">
              <div><b>Important:</b> To change the cover image, upload it as an attachment. it will be used to represent the extension on iTop Hub.</div>
              <ul>
                <li>Accepted formats are JPG/PNG</li>
                <li>File must be named <b>&lt;Extension Code&gt;-icon.jpg</b> or <b>&lt;Extension Code&gt;-icon.png</b></li>
                <li>Size must be 256x170 pixels</li>
              </ul>
            </div>
          </twig>
          <modes>
            <mode id="edit"/>
            <mode id="view"/>
          </modes>
        </form>
        <form id="targetextension-create" _delta="define">
          <class>TargetExtension</class>
          <properties>
            <display_mode>dense</display_mode>
            <always_show_submit>true</always_show_submit>
            <navigation_rules>
              <submit>
                <default>go-to-extension-from-targetextension</default>
              </submit>
            </navigation_rules>
          </properties>
          <fields/>
          <twig>
            <div class="row">
              <div class="col-sm-4">
                <fieldset>
                  <legend>General information</legend>
                  <div class="form_field" data-field-id="extension_id_friendlyname" data-field-flags=""/>
                  <div class="form_field" data-field-id="extension_build_identifier" data-field-flags="read_only"/>
                  <div class="form_field" data-field-id="version" data-field-flags=""/>
                  <div class="form_field" data-field-id="itop_min_version" data-field-flags=""/>
                  <div class="form_field" data-field-id="itop_max_version" data-field-flags=""/>
                  <div class="form_field" data-field-id="step" data-field-flags="read_only"/>
                  <div class="form_field" data-field-id="freeze_date" data-field-flags="read_only"/>
                </fieldset>
              </div>
              <div class="col-sm-8">
                <div class="form_field" data-field-id="changelog" data-field-flags=""/>
              </div>
            </div>
            <br/>
            <div class="alert alert-info">
              <div><b>Important:</b> Upload the zip package as an attachment.</div>
              <ul>
                <li>Accepted formats is ZIP only</li>
                <li>File must be named <b>&lt;Extension Code&gt;-X.Y.Z-ABC.zip</b></li>
                <li>X, Y, Z must be version numbers (decimals) eg. 2.0.1</li>
                <li>ABC must be the build number (decimals) eg. 541 (internal build number) or 20201004120000 (date time)</li>
              </ul>
            </div>
          </twig>
          <modes>
            <mode id="create"/>
          </modes>
        </form>
        <form id="targetextension-edit" _delta="define">
          <class>TargetExtension</class>
          <properties>
            <display_mode>dense</display_mode>
            <always_show_submit>true</always_show_submit>
          </properties>
          <fields/>
          <twig>
            <div class="row">
              <div class="col-sm-4">
                <fieldset>
                  <legend>General information</legend>
                  <div class="form_field" data-field-id="extension_id_friendlyname"/>
                  <div class="form_field" data-field-id="extension_build_identifier" data-field-flags="read_only"/>
                  <div class="form_field" data-field-id="version" data-field-flags=""/>
                  <div class="form_field" data-field-id="itop_min_version" data-field-flags=""/>
                  <div class="form_field" data-field-id="itop_max_version" data-field-flags=""/>
                  <div class="form_field" data-field-id="step" data-field-flags="read_only"/>
                  <div class="form_field" data-field-id="freeze_date" data-field-flags="read_only"/>
                  <div class="form_field" data-field-id="target_date" data-field-flags="read_only"/>
                  <div class="form_field" data-field-id="last_update" data-field-flags="read_only"/>
                </fieldset>
              </div>
              <div class="col-sm-8">
                <div class="form_field" data-field-id="changelog" data-field-flags=""/>
                <div class="form_field" data-field-id="package" data-field-flags=""/>
              </div>
            </div>
            <br/>
            <div class="alert alert-info">
              <div><b>Important:</b> To change the zip package, upload it as an attachment.</div>
              <ul>
                <li>Accepted formats is ZIP only</li>
                <li>File must be named <b>&lt;Extension Code&gt;-X.Y.Z-ABC.zip</b></li>
                <li>X, Y, Z must be version numbers (decimals) eg. 2.0.1</li>
                <li>ABC must be the build number (decimals) eg. 541 (internal build number) or 20201004120000 (date time)</li>
              </ul>
            </div>
          </twig>
          <modes>
            <mode id="edit"/>
            <mode id="view"/>
          </modes>
        </form>
        <form id="targetextension-stimulus" _delta="define">
          <class>TargetExtension</class>
          <properties>
            <navigation_rules>
              <submit>
                <default>go-to-version</default>
              </submit>
              <cancel>
                <default>go-to-version</default>
              </cancel>
            </navigation_rules>
          </properties>
          <fields/>
          <twig>
            <div>
              <div class="form_field" data-field-id="log" data-field-flags="must_prompt"/>
            </div>
          </twig>
          <modes>
            <mode id="apply_stimulus">
              <stimuli>
                <stimulus id="ev_cancel"/>
                <stimulus id="ev_open"/>
              </stimuli>
            </mode>
          </modes>
        </form>
        <form id="targetextension-submit-stimulus" _delta="define">
          <class>TargetExtension</class>
          <properties>
            <display_mode>dense</display_mode>
            <navigation_rules>
              <submit>
                <default>go-to-version</default>
              </submit>
              <cancel>
                <default>go-to-version</default>
              </cancel>
            </navigation_rules>
          </properties>
          <fields/>
          <twig>
            <div class="row">
              <div class="col-sm-6">
                <div class="form_field" data-field-id="itop_min_version" data-field-flags="must_prompt"/>
              </div>
              <div class="col-sm-6">
                <div class="form_field" data-field-id="itop_max_version" data-field-flags="must_prompt"/>
              </div>
            </div>
            <div>
              <div class="form_field" data-field-id="changelog" data-field-flags="must_prompt"/>
              <div class="form_field" data-field-id="log" data-field-flags="must_prompt"/>
            </div>
          </twig>
          <modes>
            <mode id="apply_stimulus">
              <stimuli>
                <stimulus id="ev_request_validation"/>
                <stimulus id="ev_republish"/>
              </stimuli>
            </mode>
          </modes>
        </form>
        <form id="contact" _delta="define">
          <class>Person</class>
          <properties>
            <display_mode>compact</display_mode>
          </properties>
          <fields/>
          <twig>
            <div class="row">
              <div class="form_field" data-field-id="civility" data-field-flags="read_only"/>
              <div class="form_field" data-field-id="first_name" data-field-flags="read_only"/>
              <div class="form_field" data-field-id="name" data-field-flags="read_only"/>
              <div class="form_field" data-field-id="email" data-field-flags="read_only"/>
              <div class="form_field" data-field-id="org_id_friendlyname" data-field-flags="read_only"/>
            </div>
          </twig>
          <modes>
            <mode id="view"/>
          </modes>
        </form>
        <form id="organization" _delta="define">
          <class>Organization</class>
          <fields/>
          <twig>
            <div class="form_field" data-field-id="name" data-field-flags="read_only"/>
          </twig>
        </form>
      </forms>
      <bricks>
        <brick id="workshop" xsi:type="Combodo\iTop\Portal\Brick\BrowseBrick" _delta="define">
          <active>true</active>
          <rank>
            <default>10</default>
          </rank>
          <width>6</width>
          <title>
            <default>Workshop</default>
          </title>
          <description>Modify your Extensions, add new versions, request publication,...</description>
          <decoration_class>
            <default>fas fa-drafting-compass fa-2x</default>
          </decoration_class>
          <levels>
            <level id="1">
              <oql><![CDATA[SELECT Extension WHERE status !='obsolete']]></oql>
              <description_att>short</description_att>
              <image_att>icon</image_att>
              <fields>
                <field id="short"/>
                <field id="publication_date"/>
                <field id="last_publication"/>
                <field id="last_update"/>
                <field id="status"/>
                <field id="description">
                  <hidden>true</hidden>
                </field>
              </fields>
              <actions>
                <action id="edit" xsi:type="edit">
                  <rank>1</rank>
                </action>
              </actions>
            </level>
          </levels>
          <browse_modes>
            <availables>
              <mode id="mosaic"/>
              <mode id="list"/>
            </availables>
            <default>mosaic</default>
          </browse_modes>
          <data_loading>lazy</data_loading>
        </brick>
        <brick id="new-extension" xsi:type="Combodo\iTop\Portal\Brick\CreateBrick" _delta="define">
          <active>true</active>
          <rank>
            <default>20</default>
          </rank>
          <width>6</width>
          <title>
            <default>New extension</default>
          </title>
          <description>Submit a brand new extension (new version of existing extensions can be added through the workshop)</description>
          <decoration_class>
            <default>fas fa-plus fa-2x</default>
          </decoration_class>
          <modal>true</modal>
          <class>Extension</class>
          <rules>
            <rule id="contact-to-extension"/>
          </rules>
        </brick>
        <!-- <brick id="new-version" xsi:type="Combodo\iTop\Portal\Brick\CreateBrick" _delta="define">
          <active>false</active>
          <rank>
            <default>40</default>
          </rank>
          <width>6</width>
          <title>
            <default>New version</default>
          </title>
          <description>Submit a new version on the current extension</description>
          <decoration_class>
            <default>fas fa-plus fa-2x</default>
          </decoration_class>
          <modal>true</modal>
          <class>Extension</class>
          <rules>
            <rule id="extension-to-targetextension"/>
          </rules>
        </brick>-->
        <brick id="communication" xsi:type="Combodo\iTop\Portal\Brick\CommunicationBrick" _delta="define">
          <rank>1</rank>
          <!-- float -->
          <oql><![CDATA[SELECT Communication WHERE portals MATCHES ('developer') AND status = 'ongoing' AND start_date <= :now]]></oql>
          <height>15</height>
          <!-- integer , size in em -->
          <width>12</width>
          <!-- integer , must be between 1 and 12 -->
          <title>Portal:Communications</title>
        </brick>
        <brick id="user-profile" xsi:type="Combodo\iTop\Portal\Brick\UserProfileBrick">
          <rank>
            <default>1</default>
          </rank>
          <title>
            <default>Brick:Portal:UserProfile:Navigation:Dropdown:MyProfil</default>
          </title>
          <decoration_class>
            <default>fa fa-user fa-2x</default>
          </decoration_class>
          <!-- Show / hide some of the user profile forms by setting the tag value to true|false -->
          <!--<show_picture_form>true</show_picture_form>-->
          <!--<show_preferences_form>true</show_preferences_form>-->
          <!--<show_password_form>true</show_password_form>-->
          <form>
            <fields/>
            <twig>
              <div class="form_field" data-field-id="first_name" data-field-flags="read_only"/>
              <div class="form_field" data-field-id="name" data-field-flags="read_only"/>
              <div class="form_field" data-field-id="org_id" data-field-flags="read_only"/>
              <div class="form_field" data-field-id="email"/>
              <div class="form_field" data-field-id="phone"/>
              <div class="form_field" data-field-id="function"/>
            </twig>
          </form>
        </brick>
      </bricks>
    </module_design>
3_0_0/customization/new_portal.txt · Last modified: 2022/01/21 16:52 (external edit)
Back to top
Contact us