NAME RT::Extension::ConditionalCustomFields - CF conditioned by the value of another CF DESCRIPTION This plugin provides the ability to display/edit a custom field – called the "conditioned by custom field " throughout this documentation – conditioned by the value of another custom field – the "condition custom field " – for the same object, which can be anything that can have custom fields (ticket , queue , user , group , article or asset ). The condition can be setup on the Admin page for editing the conditioned by custom field . From version 0.99, any custom field can be chosen as the condition custom field (whereas for earlier version, only Select custom fields were eligible), and you can specify which operator is to be applied against which value(s) for the condition to be met. Available operators are: * is The condition is met if and only if the current value of the instanciated conditioned by custom field is equal to the value (or one of the values, see below for multivalued condition) setup for this condition. With isn't operator described below, is operator is the only one which is eligible for selectable custom fields – with Select, Combobox or Autocomplete type –, since their values are to be selected from a set of values. For Date and DateTime custom fields , this operator is named on. * isn't The condition is met if and only if the current value of the instanciated conditioned by custom field is different from the value (or none of the values, see below for multivalued condition) setup for this condition. With is operator described above, isn't operator is the only one which is eligible for selectable custom fields – with Select, Combobox or Autocomplete type –, since their values are to be selected from a set of values. For Date and DateTime custom fields , this operator is named not on. * match The condition is met if and only if the current value of the instanciated conditioned by custom field is included in the value setup for this condition, typically if the current value is a substring of the condition value. As said above, selectable custom fields – with Select, Combobox or Autocomplete type are not eligible for this operator. Also, Date and DateTime custom fields are not eligible for this operator. * doesn't match The condition is met if and only if the current value of the instanciated conditioned by custom field isn't included in the value setup for this condition, typically if the current value isn't a substring of the condition value. As said above, selectable custom fields – with Select, Combobox or Autocomplete type are not eligible for this operator. Also, Date and DateTime custom fields are not eligible for this operator. * less than The condition is met if and only if the current value of the instanciated conditioned by custom field is less than or equal to the value setup for this condition. The comparison is achieved according to some kind of natural sort order , that is: number values are compared as numbers, strings are compared alphabetically, insensitive to case and accents (a = á, a = A). Moreover, IP Adresses (IPv4 and IPv6) are expanded to be compared as expected. As said above, selectable custom fields – with Select, Combobox or Autocomplete type are not eligible for this operator. * greater than The condition is met if and only if the current value of the instanciated conditioned by custom field is greater than or equal to the value setup for this condition. The comparison is achieved according to some kind of natural sort order , that is: number values are compared as numbers, strings are compared alphabetically, insensitive to case and accents (a = á, a = A), and dates with or without times are compared chronogically. Moreover, IP Adresses (IPv4 and IPv6) are expanded to be compared as expected. As said above, selectable custom fields – with Select, Combobox or Autocomplete type are not eligible for this operator. * between The condition is met if and only if the current value of the instanciated conditioned by custom field is greater than or equal to the first value setup for this condition and is less than or equal to the second value setup for this condition. That means that when this operator is selected, two values have to be entered. The comparison is achieved according to some kind of natural sort order , that is: number values are compared as numbers, strings are compared alphabetically, insensitive to case and accents (a = á, a = A), and dates with or without times are compared chronogically. Moreover, IP Adresses (IPv4 and IPv6) are expanded to be compared as expected. As said above, selectable custom fields – with Select, Combobox or Autocomplete type are not eligible for this operator. As an exception, IPAddressRange custom fields are not eligible as condition custom fields , since there is not really any sense in comparing two ranges of IP addresses. IPAddress custom fields , combined with between operator, should be sufficient for most cases checking whether an IP address is included in a range. If the condition custom field is selectable – with Select, Combobox or Autocomplete type – it can be multivalued. Then, the condition for an object is met as soon as the condition is met by at least one value of the instanciated conditioned by custom field for this object. If a custom field is based on another (parent) custom field which is conditioned by, this (child) custom field will of course also be conditioned by (with the same condition as its parent). From version 0.07, the condition can be multivalued, that is: the conditioned custom field can be displayed/edited if the condition custom field has one of these values (In other words: there is an OR bewteen the values of the condition). The condition custom field can be a select custom field with values defined by CustomFieldValues or an external custom field . *Note that version 0.07 is a complete redesign: the API described below has changed; also, the way that ConditionedBy property is store has changed. If you upgrade from a previous version, you have to reconfigure the custom fields which are conditionned by.* Version 0.99 is also a complete redesign, with API changed, but backward compatibility with previously configured custom fields , assuming the default condition operator is is. RT VERSION Works with RT 4.2 or greater INSTALLATION perl Makefile.PL make make install May need root permissions Patch your RT ConditionalCustomFields requires a small patch to add necessary Callbacks on versions of RT superior to 4.2.3. (The patch has been submitted to BestPractical in order to be included in future RT releases, as of RT 4.4.2, some parts of the patch are already included, but some other parts still required to apply this patch.) For RT 4.2, apply the included patch: cd /opt/rt4 # Your location may be different patch -p1 < /download/dir/RT-Extension-ConditionalCustomFields/patches/4.2-add-callbacks-to-extend-customfields-capabilities.patch For RT 4.4.1, apply the included patch: cd /opt/rt4 # Your location may be different patch -p1 < /download/dir/RT-Extension-ConditionalCustomFields/patches/4.4.1-add-callbacks-to-extend-customfields-capabilities.patch For RT 4.4.2 or greater, apply the included patch: cd /opt/rt4 # Your location may be different patch -p1 < /download/dir/RT-Extension-ConditionalCustomFields/patches/4.4.2-add-callbacks-to-extend-customfields-capabilities.patch Edit your /opt/rt4/etc/RT_SiteConfig.pm If you are using RT 4.2 or greater, add this line: Plugin('RT::Extension::ConditionalCustomFields'); For RT 4.0, add this line: Set(@Plugins, qw(RT::Extension::ConditionalCustomFields)); or add RT::Extension::ConditionalCustomFields to your existing @Plugins line. Clear your mason cache rm -rf /opt/rt4/var/mason_data/obj Restart your webserver METHODS ConditionalCustomFields adds a ConditionedBy property, that is a condition CustomField , an operator and one or more values, along with the following methods, to conditioned by CustomField objects: SetConditionedBy CF, OP, VALUE Set the ConditionedBy property for this CustomField object to CustomField CF with operator set to OP and value set to VALUE. CF should be an existing CustomField object or the id of an existing CustomField object, or the name of an unambiguous existing CustomField object. OP should be is, isn't, match, doesn't match, less than, greater than or between. VALUE should be a string or an anonymous array of strings (for selectable custom fields or between operator). Current user should have SeeCustomField and ModifyCustomField rights for this conditioned by CustomField and SeeCustomField right for the condition CustomField . Returns (1, 'Status message') on success and (0, 'Error Message') on failure. ConditionedBy Returns the current ConditionedBy property for this conditioned by CustomField object as a hash with keys CF containing the id of the condition CustomField , op and vals containing the condition operator as string, and the condition value as an array of strings (so we can store several values for selectable custom fields or between operator, but generally the vals array includes only one string). If neither this conditioned by CustomField nor one of its ancestor is conditioned by the CF condition CustomField , that is: if their ConditionedBy property is not (recursively) defined, returns undef. Current user should have SeeCustomField right for both this conditioned by CustomField and the condition CustomField which this CustomField is conditioned recursively by. *"Recursively"* means that this method will search for a ConditionedBy property for this CustomField object, then for the CustomField this one is BasedOn, and so on until it finds an ancestor Category with a ConditionedBy property or, the CustomField which is being looked up, is not based on any ancestor Category. INITIALDATA Also, ConditionalCustomFields allows to set the ConditionedBy property when creating CustomFields from an initialdata file, with one of the following syntaxes: @CustomFields = ( { Name => 'Condition', Type => 'SelectSingle', RenderType => 'Dropdown', Queue => [ 'General' ], LookupType => 'RT::Queue-RT::Ticket', Values => [ { Name => 'Passed', SortOrder => 0 }, { Name => 'Failed', SortOrder => 1 }, { Name => 'Schrödingerized', SortOrder => 2 }, ], Pattern => '(?#Mandatory).', DefaultValues => [ 'Failed' ], }, { Name => 'Conditioned with cf name and value', Type => 'FreeformSingle', Queue => [ 'General' ], LookupType => 'RT::Queue-RT::Ticket', ConditionedByCF => 'Condition', ConditionedBy => 'Passed', }, { Name => 'Conditioned with cf id and value', Type => 'FreeformSingle', Queue => [ 'General' ], LookupType => 'RT::Queue-RT::Ticket', ConditionedByCF => 66, ConditionOp => "isn't", ConditionedBy => 'Failed', }, { Name => 'Conditioned with multiple values', Type => 'Freeform', MaxValues => 1, Queue => [ 'General' ], LookupType => 'RT::Queue-RT::Ticket', ConditionedByCF => 'Condition', ConditionedBy => ['Passed', 'Schrödingerized'], }, ); This examples creates a Select condition CustomField , named Condition and three conditioned by CustomFields . CustomField Condition should have the value Passed, for CustomField Conditioned with cf name and value to be displayed or edited. CustomField Condition should not have the value Failed for CustomField Conditioned with cf id and value to be displayed or edited. CustomField Condition should have one of the values Passed or Schrödingerized for CustomField Conditioned with multiple values to be displayed or edited. Additional fields for an element of @CustomFields are: ConditonedByCF The condition CustomField that this new CustomField should conditioned by. It can be either the id or the Name of a previously created CustomField . This implies that the condition CustomField should be declared before this one in the initialdata file, or it should already exist. When ConditionedByCF attribute is set, ConditionedBy field should always also be set. ConditonedBy The value as a string of the condition CustomField defined by the ConditionedByCF field (which is mandatory). ConditonOp The operator as a string to use for comparison, either is, isn't, match, doesn't match, less than, greater than or between. This field is optional, defaults to is. TEST SUITE ConditionalCustomFields comes with a fairly complete test suite. As for every RT extention , to run it, you will need a installed RT, set up in development mode . But, since ConditionalCustomFields operates dynamically to show or hide custom fields , most of its magic happens in Javascript. Therefore, the test suite requires a scriptable headless browser with Javascript capabilities. So you also need to install PhantomJS , along with WWW::Mechanize::PhantomJS and Selenium::Remote::Driver. It should be noted that with version 0.99, the number of cases to test has exponentially expanded. Not only any object which can have custom fields (ticket , queue , user , group , article or asset ) should be tested. But also, any type of custom fields (Select, Freeform, Text, Wikitext, Image, Binary, Combobox, Autocomplete, Date, DateTime and IPAddress) should be tested both for condition custom field and conditioned by custom field . And this both for Single and Multiple versions (when available) of each type of custom fields . Select custom fields should also be tested for each render type (Select box, List, Dropdown and also Chosen when the number of values is greater than ten). Adding to these required unitary tests, some special cases should also be included, for instance when a condition custom field is in turn conditioned by another condition custom field , or when a condition custom field is not applied to a queue , etc. Eventually, the test suite includes 1904 unitary tests and 63 test files. Nevertheless some special cases may have been left over, so you're encourage to fill a bug report, so they can be fixed. AUTHOR Gérald Sédrati-Dinet REPOSITORY BUGS All bugs should be reported via email to bug-RT-Extension-ConditionalCustomFields@rt.cpan.org or via the web at rt.cpan.org . LICENSE AND COPYRIGHT This software is Copyright (c) 2017-2019 by Gérald Sédrati-Dinet, Easter-Eggs This is free software, licensed under: The GNU General Public License, Version 3, June 2007