mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-17 06:18:44 +02:00
N°931: TagSet search form integration
This commit is contained in:
@@ -62,6 +62,7 @@ class NiceWebPage extends WebPage
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_field.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_numeric.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_enum.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_tag_set.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_key.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_hierarchical_key.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_abstract.js');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -928,6 +928,24 @@ class ScalarExpression extends UnaryExpression
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
break;
|
||||
case ($oAttDef instanceof AttributeTagSet):
|
||||
try
|
||||
{
|
||||
if (!empty($this->GetValue()))
|
||||
{
|
||||
/** @var AttributeTagSet $oAttDef */
|
||||
$aValue['label'] = $oAttDef->GetValueLabel($this->GetValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
$aValue['label'] = Dict::S('Enum:Undefined');
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
break;
|
||||
case $oAttDef->IsExternalKey():
|
||||
try
|
||||
{
|
||||
@@ -1575,7 +1593,7 @@ class ListExpression extends Expression
|
||||
{
|
||||
if ($oExpr instanceof VariableExpression)
|
||||
{
|
||||
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
|
||||
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar($aArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2119,7 +2137,7 @@ class CharConcatExpression extends Expression
|
||||
{
|
||||
if ($oExpr instanceof VariableExpression)
|
||||
{
|
||||
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
|
||||
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar($aArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -884,6 +884,9 @@ input.dp-applied {
|
||||
left: 0px;
|
||||
margin-top: -1px;
|
||||
}
|
||||
.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_buttons, .search_form_handler .sf_criterion_area .sf_more_criterion .sfc_form_group .sfc_fg_buttons, .search_form_handler .sf_criterion_area .sf_button .sfc_form_group .sfc_fg_buttons, .search_form_handler .sf_criterion_area .search_form_criteria .sfm_content .sfc_fg_buttons, .search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfc_fg_buttons, .search_form_handler .sf_criterion_area .sf_button .sfm_content .sfc_fg_buttons {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.search_form_handler .sf_criterion_area .search_form_criteria {
|
||||
/* Non editable criteria */
|
||||
/* Draft criteria (modifications not applied) */
|
||||
@@ -1127,6 +1130,15 @@ input.dp-applied {
|
||||
.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_enum .sfc_form_group .sfc_fg_operator_in > label .sfc_op_content {
|
||||
width: 100%;
|
||||
}
|
||||
.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_tag_set .sfc_form_group .sfc_fg_operator_in > label {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
line-height: initial;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_tag_set .sfc_form_group .sfc_fg_operator_in > label .sfc_op_content {
|
||||
width: 100%;
|
||||
}
|
||||
.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between .sfc_op_content_from_outer {
|
||||
display: inline;
|
||||
}
|
||||
@@ -2862,19 +2874,16 @@ table.listResults .originColor {
|
||||
.menu-icon-select > .ui-menu-item {
|
||||
padding: 0.3em 3%;
|
||||
}
|
||||
|
||||
.attribute-tagset > span, .attribute-tagset-undefined > span {
|
||||
display: inline-block;
|
||||
padding: 3px;
|
||||
margin-right: 3px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.attribute-tagset > span {
|
||||
color: white;
|
||||
background-color: grey;
|
||||
}
|
||||
|
||||
.attribute-tagset-undefined > span {
|
||||
color: grey;
|
||||
background-color: lightgrey;
|
||||
|
||||
@@ -991,6 +991,10 @@ input.dp-applied {
|
||||
min-width: 100%;
|
||||
left: 0px;
|
||||
margin-top: -1px;
|
||||
|
||||
.sfc_fg_buttons{
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1304,6 +1308,22 @@ input.dp-applied {
|
||||
}
|
||||
}
|
||||
}
|
||||
&.search_form_criteria_tag_set{
|
||||
.sfc_form_group{
|
||||
.sfc_fg_operator_in{
|
||||
> label{
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
line-height: initial;
|
||||
white-space: nowrap;
|
||||
|
||||
.sfc_op_content{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.search_form_criteria_numeric {
|
||||
//.sfc_form_group.advanced {
|
||||
// .sfc_fg_operator_between {
|
||||
|
||||
@@ -1447,6 +1447,8 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'UI:Search:Criteria:Title:Enum:In' => '%1$s: %2$s',
|
||||
'UI:Search:Criteria:Title:Enum:In:Many' => '%1$s: %2$s and %3$s others',
|
||||
'UI:Search:Criteria:Title:Enum:In:All' => '%1$s: Any',
|
||||
// - TagSet widget
|
||||
'UI:Search:Criteria:Title:TagSet:Matches' => '%1$s: %2$s',
|
||||
// - External key widget
|
||||
'UI:Search:Criteria:Title:ExternalKey:Empty' => '%1$s is defined',
|
||||
'UI:Search:Criteria:Title:ExternalKey:NotEmpty' => '%1$s is not defined',
|
||||
@@ -1480,6 +1482,8 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'UI:Search:Criteria:Operator:Numeric:LessThan' => 'Less', // => '<',
|
||||
'UI:Search:Criteria:Operator:Numeric:LessThanOrEquals' => 'Less / equals', // > '<=',
|
||||
'UI:Search:Criteria:Operator:Numeric:Different' => 'Different', // => '≠',
|
||||
// - Tag Set Widget
|
||||
'UI:Search:Criteria:Operator:TagSet:Matches' => 'Matches',
|
||||
|
||||
// - Other translations
|
||||
'UI:Search:Value:Filter:Placeholder' => 'Filter...',
|
||||
|
||||
@@ -1280,6 +1280,8 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'UI:Search:Criteria:Title:Enum:In' => '%1$s : %2$s',
|
||||
'UI:Search:Criteria:Title:Enum:In:Many' => '%1$s : %2$s et %3$s autres',
|
||||
'UI:Search:Criteria:Title:Enum:In:All' => '%1$s : Indifférent',
|
||||
// - TagSet widget
|
||||
'UI:Search:Criteria:Title:TagSet:Matches' => '%1$s : %2$s',
|
||||
// - External key widget
|
||||
'UI:Search:Criteria:Title:ExternalKey:Empty' => '%1$s est renseigné',
|
||||
'UI:Search:Criteria:Title:ExternalKey:NotEmpty' => '%1$s n\'est pas renseigné',
|
||||
@@ -1294,6 +1296,8 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'UI:Search:Criteria:Title:HierarchicalKey:In' => '%1$s : %2$s',
|
||||
'UI:Search:Criteria:Title:HierarchicalKey:In:Many' => '%1$s : %2$s et %3$s autres',
|
||||
'UI:Search:Criteria:Title:HierarchicalKey:In:All' => '%1$s : Indifférent',
|
||||
// - Tag Set Widget
|
||||
'UI:Search:Criteria:Operator:TagSet:Matches' => 'Contient',
|
||||
|
||||
/// - Criteria operators
|
||||
// - Default widget
|
||||
|
||||
86
js/search/search_form_criteria_tag_set.js
Normal file
86
js/search/search_form_criteria_tag_set.js
Normal file
@@ -0,0 +1,86 @@
|
||||
//iTop Search form criteria tag_set
|
||||
;
|
||||
$(function()
|
||||
{
|
||||
// the widget definition, where 'itop' is the namespace,
|
||||
// 'search_form_criteria_tag_set' the widget name
|
||||
$.widget( 'itop.search_form_criteria_tag_set', $.itop.search_form_criteria_enum,
|
||||
{
|
||||
// default options
|
||||
options:
|
||||
{
|
||||
// Overload default operator
|
||||
'operator': 'MATCHES',
|
||||
// Available operators
|
||||
'available_operators': {
|
||||
'MATCHES': {
|
||||
'label': Dict.S('UI:Search:Criteria:Operator:TagSet:MATCHES'),
|
||||
'code': 'matches',
|
||||
'rank': 10,
|
||||
},
|
||||
'IN': null,
|
||||
'=': null, // Remove this one from tag_set widget.
|
||||
'empty': null, // Remove as it will be handle by the "null" value in the "MATCHES" operator
|
||||
'not_empty': null, // Remove as it will be handle by the "null" value in the "MATCHES" operator
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
// the constructor
|
||||
_create: function()
|
||||
{
|
||||
var me = this;
|
||||
|
||||
this._super();
|
||||
this.element.addClass('search_form_criteria_tag_set');
|
||||
},
|
||||
// called when created, and later when changing options
|
||||
_refresh: function()
|
||||
{
|
||||
|
||||
},
|
||||
// events bound via _bind are removed automatically
|
||||
// revert other modifications here
|
||||
_destroy: function()
|
||||
{
|
||||
this.element.removeClass('search_form_criteria_tag_set');
|
||||
this._super();
|
||||
},
|
||||
// _setOptions is called with a hash of all options that are changing
|
||||
// always refresh when changing options
|
||||
_setOptions: function()
|
||||
{
|
||||
this._superApply(arguments);
|
||||
},
|
||||
// _setOption is called for each individual option that is changing
|
||||
_setOption: function( key, value )
|
||||
{
|
||||
this._super( key, value );
|
||||
},
|
||||
|
||||
//------------------
|
||||
// Inherited methods
|
||||
//------------------
|
||||
_prepareMatchesOperator: function(oOpElem, sOpIdx, oOp)
|
||||
{
|
||||
this._prepareInOperator(oOpElem, sOpIdx, oOp);
|
||||
},
|
||||
|
||||
// Operators helpers
|
||||
// Reset operator's state
|
||||
_resetMatchesOperator: function(oOpElem)
|
||||
{
|
||||
this._resetInOperator(oOpElem);
|
||||
},
|
||||
// Get operator's values
|
||||
_getMatchesOperatorValues: function(oOpElem)
|
||||
{
|
||||
return this._getInOperatorValues(oOpElem);
|
||||
},
|
||||
// Set operator's values
|
||||
_setMatchesOperatorValues: function(oOpElem, aValues)
|
||||
{
|
||||
return this._setInOperatorValues(oOpElem, aValues);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -74,6 +74,7 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
self::OP_BETWEEN => 'BetweenToOql',
|
||||
self::OP_REGEXP => 'RegexpToOql',
|
||||
self::OP_IN => 'InToOql',
|
||||
self::OP_MATCHES => 'MatchesToOql',
|
||||
self::OP_ALL => 'AllToOql',
|
||||
);
|
||||
|
||||
@@ -118,7 +119,10 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
$aValues = self::GetValues($aCriteria);
|
||||
$sValue = self::GetValue($aValues, 0);
|
||||
|
||||
if (empty($sValue)) return "1";
|
||||
if (empty($sValue))
|
||||
{
|
||||
return "1";
|
||||
}
|
||||
|
||||
return "({$sRef} LIKE '%{$sValue}%')";
|
||||
}
|
||||
@@ -128,7 +132,10 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
$aValues = self::GetValues($aCriteria);
|
||||
$sValue = self::GetValue($aValues, 0);
|
||||
|
||||
if (empty($sValue)) return "1";
|
||||
if (empty($sValue))
|
||||
{
|
||||
return "1";
|
||||
}
|
||||
|
||||
return "({$sRef} LIKE '{$sValue}%')";
|
||||
}
|
||||
@@ -138,7 +145,10 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
$aValues = self::GetValues($aCriteria);
|
||||
$sValue = self::GetValue($aValues, 0);
|
||||
|
||||
if (empty($sValue)) return "1";
|
||||
if (empty($sValue))
|
||||
{
|
||||
return "1";
|
||||
}
|
||||
|
||||
return "({$sRef} LIKE '%{$sValue}')";
|
||||
}
|
||||
@@ -148,7 +158,10 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
$aValues = self::GetValues($aCriteria);
|
||||
$sValue = self::GetValue($aValues, 0);
|
||||
|
||||
if (empty($sValue)) return "1";
|
||||
if (empty($sValue))
|
||||
{
|
||||
return "1";
|
||||
}
|
||||
|
||||
return "({$sRef} = '{$sValue}')";
|
||||
}
|
||||
@@ -158,11 +171,32 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
$aValues = self::GetValues($aCriteria);
|
||||
$sValue = self::GetValue($aValues, 0);
|
||||
|
||||
if (empty($sValue)) return "1";
|
||||
if (empty($sValue))
|
||||
{
|
||||
return "1";
|
||||
}
|
||||
|
||||
return "({$sRef} REGEXP '{$sValue}')";
|
||||
}
|
||||
|
||||
protected static function MatchesToOql($oSearch, $sRef, $aCriteria)
|
||||
{
|
||||
$aValues = self::GetValues($aCriteria);
|
||||
$aRawValues = array();
|
||||
for($i = 0; $i < count($aValues); $i++)
|
||||
{
|
||||
$aRawValues[] = self::GetValue($aValues, $i);
|
||||
}
|
||||
$sValue = implode(' ', $aRawValues);
|
||||
|
||||
if (empty($sValue))
|
||||
{
|
||||
return "1";
|
||||
}
|
||||
|
||||
return "({$sRef} MATCHES '{$sValue}')";
|
||||
}
|
||||
|
||||
protected static function EmptyToOql($oSearch, $sRef, $aCriteria)
|
||||
{
|
||||
if (isset($aCriteria['widget']))
|
||||
@@ -197,18 +231,18 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
return "({$sRef} != '')";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObjectSearch $oSearch
|
||||
* @param string $sRef
|
||||
* @param array $aCriteria
|
||||
*
|
||||
* @return mixed|string
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
/**
|
||||
* @param \DBObjectSearch $oSearch
|
||||
* @param string $sRef
|
||||
* @param array $aCriteria
|
||||
*
|
||||
* @return mixed|string
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
protected static function InToOql($oSearch, $sRef, $aCriteria)
|
||||
{
|
||||
$sAttCode = $aCriteria['code'];
|
||||
@@ -225,8 +259,7 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
try
|
||||
{
|
||||
$aAttributeDefs = MetaModel::ListAttributeDefs($sClass);
|
||||
}
|
||||
catch (\CoreException $e)
|
||||
} catch (\CoreException $e)
|
||||
{
|
||||
return "1";
|
||||
}
|
||||
@@ -254,8 +287,7 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
try
|
||||
{
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sTargetClass);
|
||||
}
|
||||
catch (\CoreException $e)
|
||||
} catch (\CoreException $e)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -371,9 +403,10 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
else
|
||||
{
|
||||
// Add 'AND 1' to group the 'OR' inside an AND list for OQL parsing
|
||||
$sCondition = "(({$sCondition} OR {$sFilterOnUndefined}) AND 1)";
|
||||
$sCondition = "(({$sCondition} OR {$sFilterOnUndefined}) AND 1)";
|
||||
}
|
||||
}
|
||||
|
||||
return $sCondition;
|
||||
}
|
||||
|
||||
@@ -406,8 +439,7 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
$oDate = $oFormat->parse($sStartDate);
|
||||
$sStartDate = $oDate->format($sAttributeClass::GetSQLFormat());
|
||||
$aOQL[] = "({$sRef} >= '$sStartDate')";
|
||||
}
|
||||
catch (Exception $e)
|
||||
} catch (Exception $e)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -420,8 +452,7 @@ class CriterionToOQL extends CriterionConversionAbstract
|
||||
$oDate = $oFormat->parse($sEndDate);
|
||||
$sEndDate = $oDate->format($sAttributeClass::GetSQLFormat());
|
||||
$aOQL[] = "({$sRef} <= '$sEndDate')";
|
||||
}
|
||||
catch (Exception $e)
|
||||
} catch (Exception $e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ class CriterionToSearchForm extends CriterionConversionAbstract
|
||||
AttributeDefinition::SEARCH_WIDGET_TYPE_EXTERNAL_KEY => 'ExternalKeyToSearchForm',
|
||||
AttributeDefinition::SEARCH_WIDGET_TYPE_HIERARCHICAL_KEY => 'ExternalKeyToSearchForm',
|
||||
AttributeDefinition::SEARCH_WIDGET_TYPE_ENUM => 'EnumToSearchForm',
|
||||
AttributeDefinition::SEARCH_WIDGET_TYPE_TAG_SET => 'TagSetToSearchForm',
|
||||
);
|
||||
|
||||
foreach($aAndCriterionRaw as $aCriteria)
|
||||
@@ -666,6 +667,36 @@ class CriterionToSearchForm extends CriterionConversionAbstract
|
||||
return $aCriteria;
|
||||
}
|
||||
|
||||
protected static function TagSetToSearchForm($aCriteria, $aFields)
|
||||
{
|
||||
$sOperator = $aCriteria['operator'];
|
||||
switch ($sOperator)
|
||||
{
|
||||
case 'MATCHES':
|
||||
// Nothing special to do
|
||||
break;
|
||||
|
||||
case 'ISNULL':
|
||||
$aCriteria['operator'] = CriterionConversionAbstract::OP_EQUALS;
|
||||
if (isset($aCriteria['has_undefined']) && $aCriteria['has_undefined'])
|
||||
{
|
||||
if (!isset($aCriteria['values']))
|
||||
{
|
||||
$aCriteria['values'] = array();
|
||||
}
|
||||
// Convention for 'undefined' enums
|
||||
$aCriteria['values'][] = array('value' => 'null', 'label' => Dict::S('Enum:Undefined'));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown operator
|
||||
$aCriteria['widget'] = AttributeDefinition::SEARCH_WIDGET_TYPE_RAW;
|
||||
break;
|
||||
}
|
||||
return $aCriteria;
|
||||
}
|
||||
|
||||
protected static function ExternalKeyToSearchForm($aCriteria, $aFields)
|
||||
{
|
||||
$sOperator = $aCriteria['operator'];
|
||||
|
||||
@@ -37,6 +37,7 @@ abstract class CriterionConversionAbstract
|
||||
const OP_BETWEEN = 'between';
|
||||
const OP_REGEXP = 'REGEXP';
|
||||
const OP_ALL = 'all';
|
||||
const OP_MATCHES = 'MATCHES';
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user