diff --git a/.hg/branchheads.cache b/.hg/branchheads.cache index fe9dad67c..c4d37d1a3 100644 --- a/.hg/branchheads.cache +++ b/.hg/branchheads.cache @@ -1,4 +1,4 @@ -a74fcab8266a49dcbf5434b89eff7182dfbd51c6 7298 +441679d8f08a562de20bd2d3e327652fa2eb2ded 7307 528aeb46da83bbc059a81856f22080d3afcbafcc 0.6.9-development b54558ec1152000af342afa1a8e8d71e410fd308 newuserinterface 2653dd0a3d797fbe612f7b80af3f99dfa70a4d28 webApi2 @@ -8,13 +8,13 @@ b5bf0195a342f5fb90a2503d4e5eba6c71360769 Iteration18 33d15992195a243b446fafcf706979eac97dfa9e functionalTests 134cda65e593500869641853e41156b2a78207b6 redbean3.0 b4e083129e977178f041ca290573c872a450e576 metaLabelsFix -d6e01659170f9168b66be46f4af97344b59710df candidate +e7d2aedb30634a5d3fba1161b6fd8e5124e6deec candidate e9d5ddaea0c3793d04774624508acd6089564cee profileavatar f4205aa2a8c5a5087af5ce73021e1d07d00dc123 stable 23f0d4d012bbfb8973027966a75406ae1b294beb 0.7.4-development 7dfbccadc5256db4139488e151a948e0cbb01c08 submitbugs -290f7e88f2f3db6c5d242cfcfabe1eae7bd15827 securityUI -7fd27b036654a9ec87d632568037cd3121f787a3 apiRefactoring +171ecad82f5a9c8fe6eb0bf10744051d51f9b63b optimizeFileImport +bb6dcb66116c3f8714f2018465f174f008ffff8b evalResolutionFix 0f917bee0cf77000526a9a2ab8876c2a8ae9fcbb commandLineUnitTests 95688e21aa93e1f0160044e32d2dfca3b27776f7 Mobile 2f550bd49e7bec96f20900471e9456ccaa6c6d07 classbeanrefactor @@ -22,18 +22,18 @@ f4205aa2a8c5a5087af5ce73021e1d07d00dc123 stable 24890a9d5293d9c2b7165d151c66851dd098a9cb newAttributeTypes a5e74086a840265b63c4dd92cf59583cc0fcd2fc imapEncode 4c99b60f2effb4ea6b8e51d7bd66433254e14e41 SavedSearch -6f24c0b152dcd3bc9b03ed5814d5c2d368e948af developmenttools +b42b9711a2aa1bbd30fd0e6c9a3c4adbe2b24474 Themes 6016a237a40cae0d6512d51bd55009a824e22111 0.7.60 dfcdaf8ee99e5b3afc482efc1645993ec9e26dc6 memcacheImprovements 130854662b9687a821c60f0f89e54cc9a00c58cb additionalInstallationCheck -82ebff8069bf3b13b01ac3cf92d1e142d441cb56 release +e41a29c6bc8d59785a31e0324d96cdad11906898 release 5f0c06ebc1bfb2b783f0e45bebd479941e304cdf 0.7.0-development a5626156edc87b42054d306069e4235777ff0336 zurmoUpgrade 02a08af4aac4bda448afdfbeea160b92e86e662d i18nv2 a837f842ea961f5ea6cc2481dc63a8763c3c4e87 export 99cdd170c057c283307ead10f04bcda8768eb8e4 fix_email_export_header 7ea98584caac52a5aefcc781a6ea552d11aeaa33 listviewcolumnselection -b42b9711a2aa1bbd30fd0e6c9a3c4adbe2b24474 Themes +6f24c0b152dcd3bc9b03ed5814d5c2d368e948af developmenttools 55a5c3f8fde482ef3e37d431edc95566e454a33f composeAndSendEmail 254cf51f34a2764918b32e6bc2cb24eb0b2e0da0 MarketingList a1a2184f2b39a9cd27bb40ec2de64a4cb9104c47 i18nExtras @@ -48,18 +48,18 @@ f2fdd9ab8b7e2014550a42c5ad1fd44a70f0b548 TwoAttributesSorting 02f5d279c5b86e92ff4d61ca5f8b3cda38d48ed5 webApi c0b9a0a3bd3f73347e35609620707160536e3c01 kanbanBoard f00a70da7758e5cb37a7e1aeba48d1b1bae2f45d unittestargv -4c16182014bafe9525561a5c692cde6918cd23f2 reports +88120704755816e08e25d189824fcd300e037d3d logoFileUpload 17f626025b769f42a55967e3e69f80c2f895d263 products -f075150ad2a79f2ded8bc1702e75d027dc312746 Spanish d442b631e0320eb0bcefe6c1d7808146e2832b84 socialitems 8b6013834c1db7c7693da6be8066b330c8dfdb87 l10nServerUtil -171ecad82f5a9c8fe6eb0bf10744051d51f9b63b optimizeFileImport +290f7e88f2f3db6c5d242cfcfabe1eae7bd15827 securityUI 7023f8a5874c056f09b4657f57e03653841b42b2 emailPasswords 933761bbd4afdeaeeac7b31c3cb72442d7fb9a30 improvements 233f19fe5348ffee6697402b1a0f0f3b5da5e341 convoandmissions 8b27201a9531e166bad8ae588f8a4eab04567cf1 messageSourceComponent 8a16935be6f25f173e73b2c1184545fee8c53a48 userinterface2 -bc3acfe2bc1f24774836e0c062cb522f7127874c IE +4467ae59f4ac2efdcad4d9b5775cbdde0802487b performance3 +276b8a1f96c1c3d40e0b9a52eb0653440a687ecd probabilityRule 6932aade11190a08a3710c14cb4272de98ee9681 &IssueFix 480f523b88a5bc9bba5f544361a29db93e2cbd8e limitStringLengthInDb 0b65e6649e31418135864267756053b366bb0197 cliInstallationFix @@ -68,7 +68,7 @@ a3f8a7d24ffc53ac9b910cb84406640cfa73edb4 globalsearchlist ab023c7160585ea3e0e4dc22d0993b7b1d91af6e stabilizingselenium f90dcf1f4c7d8bb30d0a2142652e7583fd2e986f subqueryfix 618a88277622a6f765cf65ce3985865a638f0c75 user_default_timezone_global -a74fcab8266a49dcbf5434b89eff7182dfbd51c6 default +441679d8f08a562de20bd2d3e327652fa2eb2ded default 2e440b45637a04c6ef9ca74d2f1d018a03eec244 multibyte-label 090661edd1811c5288282e568d4bf1646a2dc87b globalsearch b600995a49ffd972c74c00252fb562f1735ca50d copyAddressAndCloning @@ -77,13 +77,13 @@ fe65a71608dde103bed28c9fc5413a834aaf433a OptimizeDemoDataInstallation 7e3f4cdee31efcacc25dc2adead14e8a2bf620fc testMakeErrorsData dc87114b543cef2e514caaf53158a0cec6c16ba7 apiMergeWithDefault cbe3d8bd7bb9330cdce8032993dc2126676b4d05 additionalApiFeatures -b485e0a0f583e08f8551677729fccb7591472ecd bugFixing +282966349e4abf1868d3a4b345531bdbe68df041 bugFixing cbd2ce866432bfab51a36dcb183ffd839c6dcf55 0.7.2-development 06c6c4d7bff588aa140a1f2634fe72317ad365b9 conversationsv2 59f5787db30191cb4d866d997c60f1a388003b65 installationTest -88120704755816e08e25d189824fcd300e037d3d logoFileUpload +4c16182014bafe9525561a5c692cde6918cd23f2 reports 0787dfecc87555afad2130e9a9bb20f5a792b317 fix_story_46344681 -bb6dcb66116c3f8714f2018465f174f008ffff8b evalResolutionFix +7fd27b036654a9ec87d632568037cd3121f787a3 apiRefactoring 85c9fa1642c1fe95bd667eeebc05f5e245eccf8e performance2 c378f2d409109c0351e614de97565ba5a75e88a4 workflow_security 02dcdd9b6d122d707bf7ae1d095cc390362879d3 newTranslateCalls @@ -100,9 +100,9 @@ bb0adb9e0c5759a69c6183c22d3050df3f17902c mapping 3d2d78c7e16a931c789c571c978049352a82a0d8 jobsAndNotifications 26615b2519a4a9da4dfeeaa60ee1e71bb5019bf5 animations 9b400573ef09b68f458aca3795fb82c9f6d11f68 UI Lab -276b8a1f96c1c3d40e0b9a52eb0653440a687ecd probabilityRule +bc3acfe2bc1f24774836e0c062cb522f7127874c IE a0c0a6986f1e133fd831ea141ab943fb95c878a3 emailNotificationsRefactor bffddc52734347d49731ea659b5f119cf2f22ae2 logoFix fb9dce13d2066c7ce8e11fea944888f7002728d6 databasePort -4467ae59f4ac2efdcad4d9b5775cbdde0802487b performance3 +f075150ad2a79f2ded8bc1702e75d027dc312746 Spanish 1cc6420a42456d6e5ab3cb06739e205beba34091 current_user_timezone diff --git a/.hg/dirstate b/.hg/dirstate index 85887dd96..8029e71a6 100644 Binary files a/.hg/dirstate and b/.hg/dirstate differ diff --git a/.hg/store/00changelog.d b/.hg/store/00changelog.d index 51e703821..ad1cfa2f5 100644 Binary files a/.hg/store/00changelog.d and b/.hg/store/00changelog.d differ diff --git a/.hg/store/00changelog.i b/.hg/store/00changelog.i index eac517c83..eb7aed9bc 100644 Binary files a/.hg/store/00changelog.i and b/.hg/store/00changelog.i differ diff --git a/.hg/store/00manifest.d b/.hg/store/00manifest.d index 2570b8ad1..71c1a21e6 100644 Binary files a/.hg/store/00manifest.d and b/.hg/store/00manifest.d differ diff --git a/.hg/store/00manifest.i b/.hg/store/00manifest.i index db94f6724..1a5b6ceda 100644 Binary files a/.hg/store/00manifest.i and b/.hg/store/00manifest.i differ diff --git a/.hg/store/data/.hgtags.i b/.hg/store/data/.hgtags.i index 55308fa3c..2ecb5f9c8 100644 Binary files a/.hg/store/data/.hgtags.i and b/.hg/store/data/.hgtags.i differ diff --git a/.hg/store/data/app/protected/core/elements/_model_element.php.i b/.hg/store/data/app/protected/core/elements/_model_element.php.i index c1a402e29..b2f9d8379 100644 Binary files a/.hg/store/data/app/protected/core/elements/_model_element.php.i and b/.hg/store/data/app/protected/core/elements/_model_element.php.i differ diff --git a/.hg/store/data/app/protected/core/utils/_modal_list_link_provider.php.i b/.hg/store/data/app/protected/core/utils/_modal_list_link_provider.php.i index ba923cf3a..d2978d009 100644 Binary files a/.hg/store/data/app/protected/core/utils/_modal_list_link_provider.php.i and b/.hg/store/data/app/protected/core/utils/_modal_list_link_provider.php.i differ diff --git a/.hg/store/data/app/protected/core/utils/_select_from_related_edit_modal_list_link_provider.php.i b/.hg/store/data/app/protected/core/utils/_select_from_related_edit_modal_list_link_provider.php.i index d66196082..2cf02f8bf 100644 Binary files a/.hg/store/data/app/protected/core/utils/_select_from_related_edit_modal_list_link_provider.php.i and b/.hg/store/data/app/protected/core/utils/_select_from_related_edit_modal_list_link_provider.php.i differ diff --git a/.hg/store/data/app/protected/core/views/_edit_and_details_view.php.i b/.hg/store/data/app/protected/core/views/_edit_and_details_view.php.i index 6830649f4..97fb894d4 100644 Binary files a/.hg/store/data/app/protected/core/views/_edit_and_details_view.php.i and b/.hg/store/data/app/protected/core/views/_edit_and_details_view.php.i differ diff --git a/.hg/store/data/app/protected/core/views/_edit_view.php.i b/.hg/store/data/app/protected/core/views/_edit_view.php.i index 30437cd9c..d4e83fcc2 100644 Binary files a/.hg/store/data/app/protected/core/views/_edit_view.php.i and b/.hg/store/data/app/protected/core/views/_edit_view.php.i differ diff --git a/.hg/store/data/app/protected/core/views/_modal_config_edit_view.php.i b/.hg/store/data/app/protected/core/views/_modal_config_edit_view.php.i index 6073b3263..63c628622 100644 Binary files a/.hg/store/data/app/protected/core/views/_modal_config_edit_view.php.i and b/.hg/store/data/app/protected/core/views/_modal_config_edit_view.php.i differ diff --git a/.hg/store/data/app/protected/modules/accounts/controllers/_default_controller.php.i b/.hg/store/data/app/protected/modules/accounts/controllers/_default_controller.php.i index 67b3be59e..73af69d2f 100644 Binary files a/.hg/store/data/app/protected/modules/accounts/controllers/_default_controller.php.i and b/.hg/store/data/app/protected/modules/accounts/controllers/_default_controller.php.i differ diff --git a/.hg/store/data/app/protected/modules/contacts/controllers/_default_controller.php.i b/.hg/store/data/app/protected/modules/contacts/controllers/_default_controller.php.i index d2538be2b..4705efc8e 100644 Binary files a/.hg/store/data/app/protected/modules/contacts/controllers/_default_controller.php.i and b/.hg/store/data/app/protected/modules/contacts/controllers/_default_controller.php.i differ diff --git a/.hg/store/data/app/protected/modules/contacts/controllers/_variable_contact_state_controller.php.i b/.hg/store/data/app/protected/modules/contacts/controllers/_variable_contact_state_controller.php.i index 00d741029..cb402083f 100644 Binary files a/.hg/store/data/app/protected/modules/contacts/controllers/_variable_contact_state_controller.php.i and b/.hg/store/data/app/protected/modules/contacts/controllers/_variable_contact_state_controller.php.i differ diff --git a/.hg/store/data/app/protected/modules/leads/controllers/_default_controller.php.i b/.hg/store/data/app/protected/modules/leads/controllers/_default_controller.php.i index 760725287..b38a81579 100644 Binary files a/.hg/store/data/app/protected/modules/leads/controllers/_default_controller.php.i and b/.hg/store/data/app/protected/modules/leads/controllers/_default_controller.php.i differ diff --git a/.hg/store/data/app/protected/modules/marketing_lists/controllers/_default_controller.php.i b/.hg/store/data/app/protected/modules/marketing_lists/controllers/_default_controller.php.i index 8cae90232..37f526f42 100644 Binary files a/.hg/store/data/app/protected/modules/marketing_lists/controllers/_default_controller.php.i and b/.hg/store/data/app/protected/modules/marketing_lists/controllers/_default_controller.php.i differ diff --git a/.hg/store/data/app/protected/modules/opportunities/controllers/_default_controller.php.i b/.hg/store/data/app/protected/modules/opportunities/controllers/_default_controller.php.i index ee561f4f3..2cbe18a42 100644 Binary files a/.hg/store/data/app/protected/modules/opportunities/controllers/_default_controller.php.i and b/.hg/store/data/app/protected/modules/opportunities/controllers/_default_controller.php.i differ diff --git a/.hg/store/data/app/protected/modules/users/controllers/_default_controller.php.i b/.hg/store/data/app/protected/modules/users/controllers/_default_controller.php.i index 0748b3e86..ad5d13cce 100644 Binary files a/.hg/store/data/app/protected/modules/users/controllers/_default_controller.php.i and b/.hg/store/data/app/protected/modules/users/controllers/_default_controller.php.i differ diff --git a/.hg/store/data/app/version.php.i b/.hg/store/data/app/version.php.i index beec76f93..d418853e1 100644 Binary files a/.hg/store/data/app/version.php.i and b/.hg/store/data/app/version.php.i differ diff --git a/.hg/store/undo b/.hg/store/undo index 66cb759ee..928b025c0 100644 Binary files a/.hg/store/undo and b/.hg/store/undo differ diff --git a/.hg/undo.desc b/.hg/undo.desc index cfdfa59ca..1b2e802b9 100644 --- a/.hg/undo.desc +++ b/.hg/undo.desc @@ -1,3 +1,3 @@ -7252 +7299 pull https://bitbucket.org/zurmo/zurmo diff --git a/.hg/undo.dirstate b/.hg/undo.dirstate index fd4fae8ad..85887dd96 100644 Binary files a/.hg/undo.dirstate and b/.hg/undo.dirstate differ diff --git a/.hgtags b/.hgtags index d58c419c8..04a2ae807 100644 --- a/.hgtags +++ b/.hgtags @@ -308,3 +308,8 @@ cfdf73acd7e1bd4597dbac7fedcb7c22d4c0bd9a stable 67bf4e0edaaafe62d51b4174009cf93180eb3d93 unstable cfdf73acd7e1bd4597dbac7fedcb7c22d4c0bd9a unstable cfdf73acd7e1bd4597dbac7fedcb7c22d4c0bd9a 1.5.15 +cfdf73acd7e1bd4597dbac7fedcb7c22d4c0bd9a stable +8c4d5d4461197bf3f2ab5f67b40b00405d9fb28d stable +cfdf73acd7e1bd4597dbac7fedcb7c22d4c0bd9a unstable +8c4d5d4461197bf3f2ab5f67b40b00405d9fb28d unstable +8c4d5d4461197bf3f2ab5f67b40b00405d9fb28d 1.6.00 diff --git a/app/protected/core/adapters/columns/IntegerListViewColumnAdapter.php b/app/protected/core/adapters/columns/IntegerListViewColumnAdapter.php index cc694964c..de6022ee6 100644 --- a/app/protected/core/adapters/columns/IntegerListViewColumnAdapter.php +++ b/app/protected/core/adapters/columns/IntegerListViewColumnAdapter.php @@ -39,9 +39,23 @@ class IntegerListViewColumnAdapter extends TextListViewColumnAdapter public function renderGridViewData() { return array( - 'type' => 'Number', 'name' => $this->attribute, + 'value' => 'IntegerListViewColumnAdapter::renderNonEditableStatically($data, "' . $this->attribute . '")', + 'type' => 'raw', ); } + + public static function renderNonEditableStatically($model, $attribute) + { + if($model instanceof RedBeanModel && $model->isAttributeFormattedAsProbability($attribute)) + { + $resolvedValue = NumberUtil::divisionForZero($model->{$attribute}, 100); + return Yii::app()->numberFormatter->formatPercentage($resolvedValue); + } + else + { + return $model->{$attribute}; + } + } } ?> \ No newline at end of file diff --git a/app/protected/core/components/DataColumn.php b/app/protected/core/components/DataColumn.php index 58d8a66df..c729aab67 100644 --- a/app/protected/core/components/DataColumn.php +++ b/app/protected/core/components/DataColumn.php @@ -41,6 +41,45 @@ */ class DataColumn extends CDataColumn { + /** + * Renders the header cell content. + * This method will render a link that can trigger the sorting if the column is sortable. + */ + protected function renderHeaderCellContent() + { + if($this->grid->enableSorting && $this->sortable && $this->name !== null) + { + echo $this->grid->dataProvider->getSort()->link($this->name, $this->header, array('class' => 'sort-link')); + } + elseif($this->name!==null && $this->header===null) + { + if($this->grid->dataProvider instanceof CActiveDataProvider) + { + echo CHtml::encode($this->grid->dataProvider->model->getAttributeLabel($this->name)); + } + elseif($this->grid->dataProvider instanceof RedBeanModelDataProvider) + { + $modelClassName = $this->grid->dataProvider->getModelClassName(); + if($modelClassName::isAnAttribute($this->name)) + { + echo CHtml::encode($modelClassName::getAnAttributeLabel($this->name)); + } + else + { + echo CHtml::encode($this->name); + } + } + else + { + echo CHtml::encode($this->name); + } + } + else + { + echo parent::renderHeaderCellContent(); + } + } + /** * Override to add in offset information * (non-PHPdoc) diff --git a/app/protected/core/elements/IntegerElement.php b/app/protected/core/elements/IntegerElement.php index b755dfe27..89bdedb1e 100644 --- a/app/protected/core/elements/IntegerElement.php +++ b/app/protected/core/elements/IntegerElement.php @@ -35,9 +35,26 @@ ********************************************************************************/ /** - * TODO + * Class for displaying an integer attribute value in the user interface */ class IntegerElement extends TextElement { + /** + * Renders the attribute from the model. + * Directs Url to open in new page. + * @return The element's content. + */ + protected function renderControlNonEditable() + { + if($this->model instanceof RedBeanModel && $this->model->isAttributeFormattedAsProbability($this->attribute)) + { + $resolvedValue = NumberUtil::divisionForZero($this->model->{$this->attribute}, 100); + return Yii::app()->numberFormatter->formatPercentage($resolvedValue); + } + else + { + return parent::renderControlNonEditable(); + } + } } ?> diff --git a/app/protected/core/elements/ModelElement.php b/app/protected/core/elements/ModelElement.php index 8c23ca362..41704ccb2 100644 --- a/app/protected/core/elements/ModelElement.php +++ b/app/protected/core/elements/ModelElement.php @@ -156,7 +156,7 @@ function clearIdFromAutoCompleteField(value, id) 'source' => Yii::app()->createUrl($this->resolveModuleId() . '/' . $this->getAutoCompleteControllerId() . '/' . static::$autoCompleteActionId), 'options' => array( - 'select' => 'js:function(event, ui){ jQuery("#' . $idInputName . '").val(ui.item["id"]);}', // Not Coding Standard + 'select' => 'js:function(event, ui){ jQuery("#' . $idInputName . '").val(ui.item["id"]).trigger("change");}', // Not Coding Standard 'appendTo' => 'js:$("#' . $this->getIdForTextField() . '").parent().parent()', 'search' => 'js: function(event, ui) { diff --git a/app/protected/core/elements/actions/CopyLinkActionElement.php b/app/protected/core/elements/actions/CopyLinkActionElement.php new file mode 100644 index 000000000..75895974d --- /dev/null +++ b/app/protected/core/elements/actions/CopyLinkActionElement.php @@ -0,0 +1,63 @@ + $this->modelId); + if (Yii::app()->request->getParam('redirectUrl') != null) + { + $params = array_merge($params, array('redirectUrl' => Yii::app()->request->getParam('redirectUrl'))); + } + elseif ($this->getRedirectUrl() != null) + { + $params = array_merge($params, array('redirectUrl' => $this->getRedirectUrl())); + } + return Yii::app()->createUrl($this->moduleId . '/' . $this->controllerId . '/copy/', $params); + } + } +?> \ No newline at end of file diff --git a/app/protected/core/elements/assets/Modal.js b/app/protected/core/elements/assets/Modal.js index a3337ff1b..708c19904 100644 --- a/app/protected/core/elements/assets/Modal.js +++ b/app/protected/core/elements/assets/Modal.js @@ -2,7 +2,7 @@ function transferModalValues(dialogId, data) { $.each(data, function(sourceFieldId, value) { - $('#'+ sourceFieldId).val(value); + $('#'+ sourceFieldId).val(value).trigger('change'); }); $(dialogId).dialog("close"); } \ No newline at end of file diff --git a/app/protected/core/models/RedBeanModel.php b/app/protected/core/models/RedBeanModel.php index 94a044c08..9a78f3780 100644 --- a/app/protected/core/models/RedBeanModel.php +++ b/app/protected/core/models/RedBeanModel.php @@ -123,6 +123,7 @@ abstract class RedBeanModel extends BeanModel implements Serializable protected $isValidating = false; protected $isSaving = false; protected $isNewModel = false; + protected $isCopied = false; /** * Can this model be saved when save is called from a related model? True if it can, false if it cannot. @@ -144,6 +145,7 @@ abstract class RedBeanModel extends BeanModel implements Serializable 'defaultCalculatedDate' => 'RedBeanModelDefaultCalculatedDateValidator', 'readOnly' => 'RedBeanModelReadOnlyValidator', 'dateTimeDefault' => 'RedBeanModelDateTimeDefaultValueValidator', + 'probability' => 'RedBeanModelProbabilityValidator', ); /** @@ -1475,6 +1477,25 @@ public function isAttributeReadOnly($attributeName) return false; } + /** + * Returns true if the attribute is formattted as probability + */ + public function isAttributeFormattedAsProbability($attributeName) + { + assert("\$this->isAttribute(\"$attributeName\")"); + foreach ($this->validators as $validator) + { + if ($validator instanceof RedBeanModelProbabilityValidator) + { + if (in_array($attributeName, $validator->attributes, true)) + { + return true; + } + } + } + return false; + } + /** * @param boolean $attributeName * @return true/false whether the attributeName specified, it is allowed to be set externally even though it is @@ -3001,5 +3022,21 @@ public static function getSortAttributesByAttribute($attribute) { return array($attribute); } + + /** + * Utilized by copy mechanism, helps elements, views, understand the model better before the new model is saved. + */ + public function setIsCopied() + { + $this->isCopied = true; + } + + /** + * @return bool + */ + public function isCopied() + { + return $this->isCopied; + } } ?> diff --git a/app/protected/core/utils/ModelDataProviderUtil.php b/app/protected/core/utils/ModelDataProviderUtil.php index 06e46aa4e..1359fbb8e 100644 --- a/app/protected/core/utils/ModelDataProviderUtil.php +++ b/app/protected/core/utils/ModelDataProviderUtil.php @@ -270,10 +270,20 @@ protected static function processMetadataClause($modelClassName, $clausePosition ArrayUtil::getArrayValue($clauseInformation, 'modifierType')); $builder->resolveJoinsAndBuildWhere( $clauseInformation['operatorType'], $clauseInformation['value'], $clausePosition, - $where, $onTableAliasName); + $where, $onTableAliasName, + static::resolveResolveSubqueryValue($clauseInformation)); } } + protected static function resolveResolveSubqueryValue(Array $clauseInformation) + { + if(null == $resolveAsSubquery = ArrayUtil::getArrayValue($clauseInformation, 'resolveAsSubquery')) + { + return false; + } + return $resolveAsSubquery; + } + /** * @param string $modelClassName * @param integer $clausePosition diff --git a/app/protected/core/utils/ModelWhereAndJoinBuilder.php b/app/protected/core/utils/ModelWhereAndJoinBuilder.php index 86688238f..ad9acd950 100644 --- a/app/protected/core/utils/ModelWhereAndJoinBuilder.php +++ b/app/protected/core/utils/ModelWhereAndJoinBuilder.php @@ -59,13 +59,15 @@ public function __construct(RedBeanModelAttributeToDataProviderAdapter * @param $clausePosition * @param $where * @param null | string $onTableAliasName + * @param boolean | $resolveAsSubquery */ public function resolveJoinsAndBuildWhere($operatorType, $value, & $clausePosition, & $where, - $onTableAliasName = null) + $onTableAliasName = null, $resolveAsSubquery = false) { assert('is_string($operatorType)'); assert('is_array($where)'); assert('is_string($onTableAliasName) || $onTableAliasName == null'); + assert('is_bool($resolveAsSubquery)'); if (!$this->modelAttributeToDataProviderAdapter->hasRelatedAttribute()) { $tableAliasName = $this->resolveJoins($onTableAliasName, @@ -83,7 +85,7 @@ public function resolveJoinsAndBuildWhere($operatorType, $value, & $clausePositi else { $this->buildJoinAndWhereForRelatedAttribute($operatorType, $value, $clausePosition, $where, - $onTableAliasName); + $onTableAliasName, $resolveAsSubquery); } } @@ -96,12 +98,13 @@ public function resolveJoinsAndBuildWhere($operatorType, $value, & $clausePositi * @param null | string $onTableAliasName */ protected function buildJoinAndWhereForRelatedAttribute($operatorType, $value, $whereKey, &$where, - $onTableAliasName = null) + $onTableAliasName = null, $resolveAsSubquery = false) { assert('is_string($operatorType)'); assert('is_int($whereKey)'); assert('is_array($where)'); assert('is_string($onTableAliasName) || $onTableAliasName == null'); + assert('is_bool($resolveAsSubquery)'); $relationWhere = array(); if ($this->modelAttributeToDataProviderAdapter->getRelationType() == RedBeanModel::MANY_MANY) { @@ -111,11 +114,12 @@ protected function buildJoinAndWhereForRelatedAttribute($operatorType, $value, $ $relationAttributeTableAliasName, $this->modelAttributeToDataProviderAdapter->resolveManyToManyColumnName()); } - elseif ($this->modelAttributeToDataProviderAdapter->isRelatedAttributeRelation() && + elseif (($this->modelAttributeToDataProviderAdapter->isRelatedAttributeRelation() && $this->modelAttributeToDataProviderAdapter->getRelatedAttributeRelationType() == RedBeanModel::HAS_MANY) + || $resolveAsSubquery) { - $relationAttributeTableAliasName = $this->resolveOnlyAttributeJoins($onTableAliasName, - ModelDataProviderUtil::resolveCanUseFromJoins($onTableAliasName)); + $relationAttributeTableAliasName = $this->resolveRelationAttributeTableAliasNameForResolveSubquery( + $onTableAliasName, $resolveAsSubquery); $this->buildWhereForRelatedAttributeThatIsItselfAHasManyRelation( $relationAttributeTableAliasName, $operatorType, @@ -137,6 +141,34 @@ protected function buildJoinAndWhereForRelatedAttribute($operatorType, $value, $ $where[$whereKey] = strtr('1', $relationWhere); } + protected function resolveRelationAttributeTableAliasNameForResolveSubquery($onTableAliasName, $resolveAsSubquery = false) + { + assert('is_string($onTableAliasName) || $onTableAliasName == null'); + assert('is_bool($resolveAsSubquery)'); + if($resolveAsSubquery) + { + return $this->resolveRelationAttributeTableAliasNameForResolveSubqueryAsTrue($onTableAliasName); + } + else + { + return $this->resolveOnlyAttributeJoins($onTableAliasName, + ModelDataProviderUtil::resolveCanUseFromJoins($onTableAliasName)); + } + } + + protected function resolveRelationAttributeTableAliasNameForResolveSubqueryAsTrue($onTableAliasName) + { + assert('is_string($onTableAliasName) || $onTableAliasName == null'); + if($onTableAliasName == null) + { + return $this->modelAttributeToDataProviderAdapter->getModelTableName(); + } + else + { + return $onTableAliasName; + } + } + /** * Given a related attribute on a model and the related attribute is a has_many relation, * build the join and where sql string information. @@ -156,27 +188,32 @@ protected function buildWhereForRelatedAttributeThatIsItselfAHasManyRelation($on { assert('is_string($onTableAliasName)'); assert('is_string($operatorType)'); - assert('(is_array($value) && count($value) > 0) || is_string($value)'); + assert('(is_array($value) && count($value) > 0) || is_string($value) || is_int($value)'); assert('is_array($where)'); assert('is_int($whereKey)'); + if(!$this->modelAttributeToDataProviderAdapter->getRelatedAttributeRelationType() == RedBeanModel::HAS_MANY) + { + throw new NotSupportedException(); + } $relationAttributeModelClassName = $this->modelAttributeToDataProviderAdapter->getRelatedAttributeRelationModelClassName(); if ($relationAttributeModelClassName != 'CustomFieldValue' && $operatorType != 'allOf') { - //Until we can add a third parameter to the search adapter metadata, we have to assume we are only doing - //this for CustomFieldValue searches. Below we have $joinColumnName, since we don't have any other way - //of ascertaining this information for now. - - //Once we add allOf, need to have an alternative sub-query - //below that uses if/else logic to compare count against how many possibles. then return 1 or 0. - throw new NotSupportedException('modelClassName: ' . $relationAttributeModelClassName . - ' operatorType: ' . $operatorType); + $modelClassName = $this->modelAttributeToDataProviderAdapter->getRelationModelClassName(); + $relationAttributeTableName = RedBeanModel::getTableName($modelClassName); + $joinColumnName = $modelClassName::getColumnNameByAttribute( + $this->modelAttributeToDataProviderAdapter->getRelatedAttribute()); + $relationColumnName = self::resolveForeignKey(RedBeanModel::getTableName( + $this->modelAttributeToDataProviderAdapter->getModelClassName())); } - $relationAttributeTableName = RedBeanModel::getTableName($relationAttributeModelClassName); - $tableAliasName = $relationAttributeTableName; - $joinColumnName = 'value'; - $relationColumnName = self::resolveForeignKey(RedBeanModel::getTableName( - $this->modelAttributeToDataProviderAdapter-> + else + { + $relationAttributeTableName = RedBeanModel::getTableName($relationAttributeModelClassName); + $joinColumnName = 'value'; + $relationColumnName = self::resolveForeignKey(RedBeanModel::getTableName( + $this->modelAttributeToDataProviderAdapter-> getRelatedAttributeModelClassName())); + } + $tableAliasName = $relationAttributeTableName; $quote = DatabaseCompatibilityUtil::getQuote(); $where[$whereKey] = "(1 = (select 1 from $quote$relationAttributeTableName$quote $tableAliasName " . // Not Coding Standard "where $quote$tableAliasName$quote.$quote$relationColumnName$quote = " . // Not Coding Standard diff --git a/app/protected/core/utils/NumberUtil.php b/app/protected/core/utils/NumberUtil.php new file mode 100644 index 000000000..20a7870f9 --- /dev/null +++ b/app/protected/core/utils/NumberUtil.php @@ -0,0 +1,62 @@ + diff --git a/app/protected/core/utils/RedBeanDatabaseBuilderUtil.php b/app/protected/core/utils/RedBeanDatabaseBuilderUtil.php index 21f3699ea..d7c4c6dd6 100644 --- a/app/protected/core/utils/RedBeanDatabaseBuilderUtil.php +++ b/app/protected/core/utils/RedBeanDatabaseBuilderUtil.php @@ -584,6 +584,7 @@ protected static function setMadeUpMemberValue($model, $memberName) case 'CUnsafeValidator': case 'RedBeanModelCompareDateTimeValidator': case 'RedBeanModelRequiredValidator': + case 'RedBeanModelProbabilityValidator': case 'UsernameLengthValidator': case 'ValidateTimeZone': case 'AtLeastOneContentAreaRequiredValidator': diff --git a/app/protected/core/validators/RedBeanModelProbabilityValidator.php b/app/protected/core/validators/RedBeanModelProbabilityValidator.php new file mode 100644 index 000000000..febf2b684 --- /dev/null +++ b/app/protected/core/validators/RedBeanModelProbabilityValidator.php @@ -0,0 +1,52 @@ + diff --git a/app/protected/core/views/EditAndDetailsView.php b/app/protected/core/views/EditAndDetailsView.php index ff5f5e091..54ec03b7d 100644 --- a/app/protected/core/views/EditAndDetailsView.php +++ b/app/protected/core/views/EditAndDetailsView.php @@ -96,7 +96,15 @@ protected function renderContent() ); $content .= $formStart; $content .= '
'; - $content .= $this->renderFormLayout($form); + if ($form != null && $this->renderRightSideFormLayoutForEdit($form) == null) + { + $class = ' full-width'; + } + else + { + $class = ''; + } + $content .= ZurmoHtml::tag('div', array('class' => 'left-column' . $class), $this->renderFormLayout($form)); $content .= $this->renderRightSideContent($form); $content .= '
'; $content .= $this->renderAfterFormLayout($form); @@ -129,9 +137,8 @@ protected function renderRightSideContent($form = null) $rightSideContent = $this->renderRightSideFormLayoutForEdit($form); if ($rightSideContent != null) { - $content = '
'; - $content .= $rightSideContent; - $content .= '
'; + $content = ZurmoHtml::tag('div', array('class' => 'right-side-edit-view-panel'), $rightSideContent); + $content = ZurmoHtml::tag('div', array('class' => 'right-column'), $content); return $content; } } diff --git a/app/protected/core/views/EditView.php b/app/protected/core/views/EditView.php index 0eb81aca0..7098cd2b7 100644 --- a/app/protected/core/views/EditView.php +++ b/app/protected/core/views/EditView.php @@ -85,10 +85,20 @@ protected function renderContent() ); $content .= $formStart; $content .= $this->renderOperationDescriptionContent(); + $content .= '
'; - $content .= $this->renderFormLayout($form); + if ($form != null && $this->renderRightSideFormLayoutForEdit($form) == null) + { + $class = ' full-width'; + } + else + { + $class = ''; + } + $content .= ZurmoHtml::tag('div', array('class' => 'left-column' . $class), $this->renderFormLayout($form)); $content .= $this->renderRightSideContent($form); $content .= '
'; + $content .= $this->renderAfterFormLayout($form); $actionElementContent = $this->renderActionElementBar(true); if ($actionElementContent != null) @@ -113,9 +123,8 @@ protected function renderRightSideContent($form = null) $rightSideContent = $this->renderRightSideFormLayoutForEdit($form); if ($rightSideContent != null) { - $content = '
'; - $content .= $rightSideContent; - $content .= '
'; + $content = ZurmoHtml::tag('div', array('class' => 'right-side-edit-view-panel'), $rightSideContent); + $content = ZurmoHtml::tag('div', array('class' => 'right-column'), $content); return $content; } } diff --git a/app/protected/core/views/InlineEditView.php b/app/protected/core/views/InlineEditView.php index 23e3a7e64..be8597057 100644 --- a/app/protected/core/views/InlineEditView.php +++ b/app/protected/core/views/InlineEditView.php @@ -103,8 +103,8 @@ protected function renderContent() CClientScript::POS_END ); $content .= $formStart; - $content .= $this->renderFormLayout($form); - $content .= $this->renderAfterFormLayout($form); + $content .= ZurmoHtml::tag('div', array('class' => 'left-column full-width'), $this->renderFormLayout($form) . + $this->renderAfterFormLayout($form)); $actionElementContent = $this->renderActionElementBar(true); if ($actionElementContent != null) { diff --git a/app/protected/core/views/SequentialProcessView.php b/app/protected/core/views/SequentialProcessView.php index 4bdcbb6ec..cf83493c6 100644 --- a/app/protected/core/views/SequentialProcessView.php +++ b/app/protected/core/views/SequentialProcessView.php @@ -89,7 +89,7 @@ public function __construct($route, $nextStep, $nextParams, $message, $completio protected function renderContent() { $content = '
' . "\n"; - $content .= '

' . $this->message . '

'; + $content .= '

' . $this->message . '

'; $content .= ''; $content .= '
'; $this->registerAjaxScript(); diff --git a/app/protected/core/views/assets/interactions.js b/app/protected/core/views/assets/interactions.js index 19d8e3b24..041319dde 100644 --- a/app/protected/core/views/assets/interactions.js +++ b/app/protected/core/views/assets/interactions.js @@ -143,10 +143,19 @@ $(window).ready(function(){ }); $(".overlay-label-field > input").live('blur', function(){ - if($(this).val() == "") { + if($(this).val() == "") + { $(this).prev().fadeIn(250); } }); + + $(".overlay-label-field input").live('change', function(){ + if($(this).val() != "") + { + $(this).prev().fadeOut(250); + } + }); + $(".overlay-label-field > input").each( function(){ if($(this).val() == "") { $('label', $(this)).fadeIn(250); diff --git a/app/protected/core/widgets/assets/designer/Designer.js b/app/protected/core/widgets/assets/designer/Designer.js index d7396d7eb..831c728f9 100644 --- a/app/protected/core/widgets/assets/designer/Designer.js +++ b/app/protected/core/widgets/assets/designer/Designer.js @@ -530,7 +530,7 @@ var designer = { }, updateFlashBarAfterSaveLayout : function(data, flashBarId) { - // TODO: @Shoaibi/@Jason: Medium: Port this to a global scope and get rid of MarketingListMemberSelectAutoCompleteBaseElement:123 + // TODO: @Shoaibi/@Jason: Medium: Port this to a global scope and get rid of MarketingListMemberSelectAutoCompleteBaseElement:123 , LoginPageView:registerUpdateFlashBarScript() $('#' + flashBarId).jnotifyAddMessage( { text: data.message, diff --git a/app/protected/modules/accounts/controllers/DefaultController.php b/app/protected/modules/accounts/controllers/DefaultController.php index 40e82bb2c..e0f2273c1 100644 --- a/app/protected/modules/accounts/controllers/DefaultController.php +++ b/app/protected/modules/accounts/controllers/DefaultController.php @@ -114,10 +114,28 @@ public function actionEdit($id, $redirectUrl = null) { $account = Account::getById(intval($id)); ControllerSecurityUtil::resolveAccessCanCurrentUserWriteModel($account); + $this->processEdit($account, $redirectUrl); + } + + public function actionCopy($id) + { + $copyToAccount = new Account(); + $postVariableName = get_class($copyToAccount); + if (!isset($_POST[$postVariableName])) + { + $account = Account::getById((int)$id); + ControllerSecurityUtil::resolveAccessCanCurrentUserReadModel($account); + ZurmoCopyModelUtil::copy($account, $copyToAccount); + } + $this->processEdit($copyToAccount); + } + + protected function processEdit(Account $account, $redirectUrl = null) + { $view = new AccountsPageView(ZurmoDefaultViewUtil:: - makeStandardViewForCurrentUser($this, - $this->makeEditAndDetailsView( - $this->attemptToSaveModelFromPost($account, $redirectUrl), 'Edit'))); + makeStandardViewForCurrentUser($this, + $this->makeEditAndDetailsView( + $this->attemptToSaveModelFromPost($account, $redirectUrl), 'Edit'))); echo $view->render(); } diff --git a/app/protected/modules/accounts/tests/functional/AccountsTestSuite.html b/app/protected/modules/accounts/tests/functional/AccountsTestSuite.html index d1aed7b7c..a690aaa2d 100644 --- a/app/protected/modules/accounts/tests/functional/AccountsTestSuite.html +++ b/app/protected/modules/accounts/tests/functional/AccountsTestSuite.html @@ -19,6 +19,7 @@ ListViewHideShowColumns Mass Delete Import +Create Account For Auto Poppulation Of Address In Contacts \ No newline at end of file diff --git a/app/protected/modules/accounts/tests/functional/cases/CreateAccountForAutoPoppulationOfAddressInContacts.html b/app/protected/modules/accounts/tests/functional/cases/CreateAccountForAutoPoppulationOfAddressInContacts.html new file mode 100644 index 000000000..ce1d14258 --- /dev/null +++ b/app/protected/modules/accounts/tests/functional/cases/CreateAccountForAutoPoppulationOfAddressInContacts.html @@ -0,0 +1,404 @@ + + + + + + +CreateAccount + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Create Account
setTimeout45000
storeGlobaljavascript{Math.floor(Math.random()*11000)}randomSuffix
openindex.php/accounts/default/create
waitForPageToLoad
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
waitForTextPresentCreate Account
typeAccount_namemy accountc ${randomSuffix}
clickAccount_owner_SelectLink
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
waitForElementPresentUsersSearchForm_anyMixedAttributes
typeUsersSearchForm_anyMixedAttributesSam Smith
keyUpUsersSearchForm_anyMixedAttributes\10
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
waitForText//div[@id='UsersModalListView']/div/table/tbody/tr/td/aSam Smith
clicklink=Sam Smith
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
waitForValueAccount_owner_nameSam Smith
assertNotValueAccount_owner_id
typeAccount_employees5
typeAccount_officeFax123555
typeAccount_officePhone456777
typeAccount_annualRevenue500
selectAccount_industry_valuelabel=Financial Services
selectAccount_type_valuelabel=Vendor
typeAccount_websitehttp://www.testingcompany.com
typeAccount_billingAddress_street1123 ABC Street
typeAccount_billingAddress_street2suite 100
typeAccount_billingAddress_cityChicago
typeAccount_billingAddress_stateIL
typeAccount_billingAddress_postalCode60611
typeAccount_billingAddress_countryUSA
typeAccount_shippingAddress_street1456 Main Street
typeAccount_shippingAddress_street2Suite 200
typeAccount_shippingAddress_cityNew York
typeAccount_shippingAddress_stateNY
typeAccount_shippingAddress_postalCode12133
typeAccount_shippingAddress_countryUSA
typeAccount_descriptionThis is a test account
clickAndWaitsave
waitForPageToLoad
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
waitForTextPresentmy accountc ${randomSuffix}
assertTextlink=EditEdit
clickAndWait//div[contains(@class, 'ContactsForAccountRelatedListView ')]/div[1]/div/a
waitForPageToLoad
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
waitForTextPresentCreate Contact
assertValueContact_primaryAddress_street1123 ABC Street
assertValueContact_primaryAddress_street2suite 100
assertValueContact_primaryAddress_cityChicago
assertValueContact_primaryAddress_stateIL
assertValueContact_primaryAddress_postalCode60611
assertValueContact_primaryAddress_countryUSA
setSpeed3000
openindex.php/home/default
waitForPageToLoad
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
clickAndWait//ul[@id='ShortcutsMenu']/li/ul/li[2]/a/span
waitForPageToLoad
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
clickContact_account_SelectLink
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
waitForElementPresentAccountsSearchForm_anyMixedAttributes
typeAccountsSearchForm_anyMixedAttributesmy accountc ${randomSuffix}
keyUpAccountsSearchForm_anyMixedAttributes\10
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
waitForText//div[@id='list-viewmodal']/table/tbody/tr[1]/td/amy accountc ${randomSuffix}
click//div[@id='list-viewmodal']/table/tbody/tr[1]/td/a
waitForConditionselenium.browserbot.getCurrentWindow().jQuery.active == 030000
waitForValueContact_account_namemy accountc ${randomSuffix}
setSpeed0
assertValueContact_primaryAddress_street1123 ABC Street
assertValueContact_primaryAddress_street2suite 100
assertValueContact_primaryAddress_cityChicago
assertValueContact_primaryAddress_stateIL
assertValueContact_primaryAddress_postalCode60611
assertValueContact_primaryAddress_countryUSA
+ + \ No newline at end of file diff --git a/app/protected/modules/accounts/views/AccountEditAndDetailsView.php b/app/protected/modules/accounts/views/AccountEditAndDetailsView.php index 9bf6a4af7..ef2bc71fa 100644 --- a/app/protected/modules/accounts/views/AccountEditAndDetailsView.php +++ b/app/protected/modules/accounts/views/AccountEditAndDetailsView.php @@ -46,6 +46,7 @@ public static function getDefaultMetadata() array('type' => 'CancelLink', 'renderType' => 'Edit'), array('type' => 'EditLink', 'renderType' => 'Details'), array('type' => 'AuditEventsModalListLink', 'renderType' => 'Details'), + array('type' => 'CopyLink', 'renderType' => 'Details'), array('type' => 'AccountDeleteLink', 'renderType' => 'Details'), ), ), diff --git a/app/protected/modules/activities/components/ActivityModelsDefaultController.php b/app/protected/modules/activities/components/ActivityModelsDefaultController.php index a47c33642..f41d6866b 100644 --- a/app/protected/modules/activities/components/ActivityModelsDefaultController.php +++ b/app/protected/modules/activities/components/ActivityModelsDefaultController.php @@ -98,6 +98,25 @@ public function actionEdit($id, $redirectUrl = null) $modelClassName = $this->getModule()->getPrimaryModelName(); $activity = $modelClassName::getById(intval($id)); ControllerSecurityUtil::resolveAccessCanCurrentUserWriteModel($activity); + $this->processEdit($activity, $redirectUrl); + } + + public function actionCopy($id, $redirectUrl = null) + { + $modelClassName = $this->getModule()->getPrimaryModelName(); + $copyToActivity = new $modelClassName(); + $postVariableName = get_class($copyToActivity); + if (!isset($_POST[$postVariableName])) + { + $activity = $modelClassName::getById((int)$id); + ControllerSecurityUtil::resolveAccessCanCurrentUserReadModel($activity); + ActivityCopyModelUtil::copy($activity, $copyToActivity); + } + $this->processEdit($copyToActivity, $redirectUrl); + } + + protected function processEdit(Activity $activity, $redirectUrl = null) + { $pageViewClassName = $this->getPageViewClassName(); $view = new $pageViewClassName(ZurmoDefaultViewUtil:: makeStandardViewForCurrentUser($this, diff --git a/app/protected/modules/activities/tests/unit/ActivityCopyModelUtilTest.php b/app/protected/modules/activities/tests/unit/ActivityCopyModelUtilTest.php new file mode 100644 index 000000000..6e415f47d --- /dev/null +++ b/app/protected/modules/activities/tests/unit/ActivityCopyModelUtilTest.php @@ -0,0 +1,68 @@ +user->userModel = $super; + AccountTestHelper::createAccountByNameForOwner('anAccount', $super); + } + + public function testCopy() + { + Yii::app()->user->userModel = User::getByUsername('super'); + $accounts = Account::getByName('anAccount'); + $task = new Task(); + $task->name = 'My Task'; + $task->owner = Yii::app()->user->userModel; + $task->completedDateTime = '0000-00-00 00:00:00'; + $task->activityItems->add($accounts[0]); + $saved = $task->save(); + $this->assertTrue($saved); + $taskId = $task->id; + $task->forget(); + unset($task); + $task = Task::getById($taskId); + $copyToTask = new Task(); + ActivityCopyModelUtil::copy($task, $copyToTask); + $this->assertEquals('My Task', $copyToTask->name); + $this->assertEquals(1, $copyToTask->activityItems->count()); + } + } \ No newline at end of file diff --git a/app/protected/modules/activities/utils/ActivityCopyModelUtil.php b/app/protected/modules/activities/utils/ActivityCopyModelUtil.php new file mode 100644 index 000000000..4737b255d --- /dev/null +++ b/app/protected/modules/activities/utils/ActivityCopyModelUtil.php @@ -0,0 +1,55 @@ +activityItems as $activityItem) + { + $copyToModel->activityItems->add($activityItem); + } + } + } +?> \ No newline at end of file diff --git a/app/protected/modules/api/tests/unit/ApiRestOpportunityTest.php b/app/protected/modules/api/tests/unit/ApiRestOpportunityTest.php index 935e77994..273821183 100644 --- a/app/protected/modules/api/tests/unit/ApiRestOpportunityTest.php +++ b/app/protected/modules/api/tests/unit/ApiRestOpportunityTest.php @@ -149,7 +149,6 @@ public function testCreateOpportunity() $data['name'] = "Michael"; $data['closeDate'] = "2002-04-03"; - $data['probability'] = "10"; $data['description'] = "Opportunity description"; $data['source']['value'] = $sourceValues[1]; @@ -180,6 +179,7 @@ public function testCreateOpportunity() ); // We need to unset some empty values from response. + $data['probability'] = '50'; unset($response['data']['createdDateTime']); unset($response['data']['modifiedDateTime']); unset($response['data']['stage']['id']); diff --git a/app/protected/modules/contacts/controllers/DefaultController.php b/app/protected/modules/contacts/controllers/DefaultController.php index 745e64911..a09424d1d 100644 --- a/app/protected/modules/contacts/controllers/DefaultController.php +++ b/app/protected/modules/contacts/controllers/DefaultController.php @@ -113,6 +113,7 @@ public function actionCreateFromRelation($relationAttributeName, $relationModelI $relationAttributeName, (int)$relationModelId, $relationModuleId); + ContactsUtil::resolveAddressesFromRelatedAccount($contact); $this->actionCreateByModel($contact, $redirectUrl); } @@ -129,10 +130,29 @@ public function actionEdit($id, $redirectUrl = null) { $contact = Contact::getById(intval($id)); ControllerSecurityUtil::resolveAccessCanCurrentUserWriteModel($contact); + $this->processEdit($contact, $redirectUrl); + + } + + public function actionCopy($id) + { + $copyToContact = new Contact(); + $postVariableName = get_class($copyToContact); + if (!isset($_POST[$postVariableName])) + { + $contact = Contact::getById((int)$id); + ControllerSecurityUtil::resolveAccessCanCurrentUserReadModel($contact); + ZurmoCopyModelUtil::copy($contact, $copyToContact); + } + $this->processEdit($copyToContact); + } + + protected function processEdit(Contact $contact, $redirectUrl = null) + { $view = new ContactsPageView(ZurmoDefaultViewUtil:: - makeStandardViewForCurrentUser($this, - $this->makeEditAndDetailsView( - $this->attemptToSaveModelFromPost($contact, $redirectUrl), 'Edit'))); + makeStandardViewForCurrentUser($this, + $this->makeEditAndDetailsView( + $this->attemptToSaveModelFromPost($contact, $redirectUrl), 'Edit'))); echo $view->render(); } @@ -331,6 +351,22 @@ public function actionAutoComplete($term) echo CJSON::encode($autoCompleteResults); } + public function actionGetAccountAddressesToCopy($id) + { + $account = static::getModelAndCatchNotFoundAndDisplayError('Account', intval($id)); + ControllerSecurityUtil::resolveAccessCanCurrentUserReadModel($account); + $addressData = array(); + foreach($account->billingAddress->getAttributeNames() as $attribute) + { + $addressData['billingAddress_' . $attribute] = $account->billingAddress->{$attribute}; + } + foreach($account->shippingAddress->getAttributeNames() as $attribute) + { + $addressData['shippingAddress_' . $attribute] = $account->shippingAddress->{$attribute}; + } + echo CJSON::encode($addressData); + } + protected static function getSearchFormClassName() { return 'ContactsSearchForm'; diff --git a/app/protected/modules/contacts/tests/unit/ContactsUtilTest.php b/app/protected/modules/contacts/tests/unit/ContactsUtilTest.php index 5a165b198..4df21dcb0 100644 --- a/app/protected/modules/contacts/tests/unit/ContactsUtilTest.php +++ b/app/protected/modules/contacts/tests/unit/ContactsUtilTest.php @@ -132,5 +132,44 @@ public function testGetContactStateDataFromStartingStateKeyedByIdAndLabelByLangu $customerStates[0]->id => 'Client'); $this->assertEquals($compareData, $data); } + + /** + * @depends testGetContactStateDataFromStartingStateKeyedByIdAndLabelByLanguage + */ + public function testResolveAddressesFromRelatedAccount() + { + Yii::app()->user->userModel = User::getByUsername('super'); + $contact = new Contact(); + $account = new Account(); + $account->name = 'some name'; + $account->billingAddress->city = 'some city'; + $account->billingAddress->country = 'some country'; + $account->billingAddress->postalCode = 'some postalCode'; + $account->billingAddress->state = 'some state'; + $account->billingAddress->street1 = 'some street1'; + $account->billingAddress->street2 = 'some street2'; + $account->shippingAddress->city = 'some2 city'; + $account->shippingAddress->country = 'some2 country'; + $account->shippingAddress->postalCode = 'some2 postalCode'; + $account->shippingAddress->state = 'some2 state'; + $account->shippingAddress->street1 = 'some2 street1'; + $account->shippingAddress->street2 = 'some2 street2'; + $saved = $account->save(); + $this->assertTrue($saved); + $contact->account = $account; + ContactsUtil::resolveAddressesFromRelatedAccount($contact); + $this->assertEquals('some city', $contact->primaryAddress->city); + $this->assertEquals('some country', $contact->primaryAddress->country); + $this->assertEquals('some postalCode', $contact->primaryAddress->postalCode); + $this->assertEquals('some state', $contact->primaryAddress->state); + $this->assertEquals('some street1', $contact->primaryAddress->street1); + $this->assertEquals('some street2', $contact->primaryAddress->street2); + $this->assertEquals('some2 city', $contact->secondaryAddress->city); + $this->assertEquals('some2 country', $contact->secondaryAddress->country); + $this->assertEquals('some2 postalCode', $contact->secondaryAddress->postalCode); + $this->assertEquals('some2 state', $contact->secondaryAddress->state); + $this->assertEquals('some2 street1', $contact->secondaryAddress->street1); + $this->assertEquals('some2 street2', $contact->secondaryAddress->street2); + } } ?> \ No newline at end of file diff --git a/app/protected/modules/contacts/tests/unit/walkthrough/ContactsSuperUserWalkthroughTest.php b/app/protected/modules/contacts/tests/unit/walkthrough/ContactsSuperUserWalkthroughTest.php index dc3ba71e1..9649b3678 100644 --- a/app/protected/modules/contacts/tests/unit/walkthrough/ContactsSuperUserWalkthroughTest.php +++ b/app/protected/modules/contacts/tests/unit/walkthrough/ContactsSuperUserWalkthroughTest.php @@ -434,6 +434,10 @@ public function testSuperUserCreateFromRelationAction() $contacts = Contact::getAll(); $this->assertEquals(12, count($contacts)); $account = Account::getByName('superAccount2'); + $account[0]->billingAddress->street1 = 'some street'; + $account[0]->shippingAddress->street1 = 'some street 2'; + $saved = $account[0]->save(); + $this->assertTrue($saved); $opportunity = OpportunityTestHelper::createOpportunityWithAccountByNameForOwner( 'superOpp', $super, $account[0]); @@ -454,6 +458,10 @@ public function testSuperUserCreateFromRelationAction() $this->assertTrue($contacts[0]->owner == $super); $this->assertTrue($contacts[0]->account == $account[0]); $this->assertTrue($contacts[0]->state == $startingState); + $this->assertEquals('some street', $contacts[0]->primaryAddress->street1); + $this->assertEquals('some street 2', $contacts[0]->secondaryAddress->street1); + $this->assertEquals('some street', $contacts[0]->account->billingAddress->street1); + $this->assertEquals('some street 2', $contacts[0]->account->shippingAddress->street1); $this->assertEquals('456765421', $contacts[0]->officePhone); $contacts = Contact::getAll(); $this->assertEquals(13, count($contacts)); @@ -568,6 +576,7 @@ public function testMassDeleteActionsForSelectedIds() /** *Test Bug with mass delete and multiple pages when using select all + * @depends testMassDeleteActionsForSelectedIds */ public function testMassDeletePagesProperlyAndRemovesAllSelected() { @@ -604,5 +613,25 @@ public function testMassDeletePagesProperlyAndRemovesAllSelected() $contacts = contact::getAll(); $this->assertEquals(0, count($contacts)); } + + /** + * @depends testMassDeletePagesProperlyAndRemovesAllSelected + */ + public function testGetAccountAddressesToCopy() + { + $super = $this->logoutCurrentUserLoginNewUserAndGetByUsername('super'); + + $account = Account::getByName('superAccount2'); + $this->setGetArray(array('id' => $account[0]->id)); + //Run Mass Delete using progress save for page2. + $content = $this->runControllerWithNoExceptionsAndGetContent('contacts/default/getAccountAddressesToCopy'); + $compareContent = '{"billingAddress_city":null,"billingAddress_country":null,"billingAddress_invalid":"0","billingAddre' + . 'ss_latitude":null,"billingAddress_longitude":null,"billingAddress_postalCode":null,"billingAddress_street1":' + . '"some street","billingAddress_street2":null,"billingAddress_state":null,"shippingAddress_city":null,"shippin' + . 'gAddress_country":null,"shippingAddress_invalid":"0","shippingAddress_latitude":null,"shippingAddress_longit' + . 'ude":null,"shippingAddress_postalCode":null,"shippingAddress_street1":"some street 2","shippingAddress_stree' + . 't2":null,"shippingAddress_state":null}'; + $this->assertEquals($compareContent, $content); + } } ?> \ No newline at end of file diff --git a/app/protected/modules/contacts/utils/ContactsUtil.php b/app/protected/modules/contacts/utils/ContactsUtil.php index 0c8be751b..7ee185db3 100644 --- a/app/protected/modules/contacts/utils/ContactsUtil.php +++ b/app/protected/modules/contacts/utils/ContactsUtil.php @@ -301,5 +301,30 @@ public static function resolveStateLabelByLanguage(ContactState $state, $languag assert('is_string($language)'); return $state->resolveTranslatedNameByLanguage($language); } + + /** + * Given a contact with a related account, set the contact address information from the account address information + * @param Contact $contact + */ + public static function resolveAddressesFromRelatedAccount(Contact & $contact) + { + if($contact->account->id > 0) + { + if($contact->account->billingAddress->id > 0) + { + foreach($contact->account->billingAddress->getAttributeNames() as $attribute) + { + $contact->primaryAddress->{$attribute} = $contact->account->billingAddress->{$attribute}; + } + } + if($contact->account->shippingAddress->id > 0) + { + foreach($contact->account->billingAddress->getAttributeNames() as $attribute) + { + $contact->secondaryAddress->{$attribute} = $contact->account->shippingAddress->{$attribute}; + } + } + } + } } ?> \ No newline at end of file diff --git a/app/protected/modules/contacts/views/ContactEditAndDetailsView.php b/app/protected/modules/contacts/views/ContactEditAndDetailsView.php index e4d4152b3..e2b3932d6 100644 --- a/app/protected/modules/contacts/views/ContactEditAndDetailsView.php +++ b/app/protected/modules/contacts/views/ContactEditAndDetailsView.php @@ -46,6 +46,7 @@ public static function getDefaultMetadata() array('type' => 'CancelLink', 'renderType' => 'Edit'), array('type' => 'EditLink', 'renderType' => 'Details'), array('type' => 'AuditEventsModalListLink', 'renderType' => 'Details'), + array('type' => 'CopyLink', 'renderType' => 'Details'), array('type' => 'ContactDeleteLink', 'renderType' => 'Details'), ), ), @@ -198,10 +199,61 @@ public static function getDefaultMetadata() return $metadata; } + protected function renderContent() + { + $this->registerCopyAddressFromAccountScript(); + return parent::renderContent(); + } + protected function getNewModelTitleLabel() { return Zurmo::t('ContactsModule', 'Create ContactsModuleSingularLabel', LabelUtil::getTranslationParamsForAllModules()); } + + protected function registerCopyAddressFromAccountScript() + { + $url = Yii::app()->createUrl('contacts/default/getAccountAddressesToCopy'); + $successScript = null; + foreach($this->model->primaryAddress->getAttributeNames() as $attribute) + { + $successScript .= "$('#Contact_primaryAddress_" . $attribute . "').val(data.billingAddress_" . $attribute . ").trigger('change'); \n"; + $successScript .= "$('#Contact_secondaryAddress_" . $attribute . "').val(data.shippingAddress_" . $attribute . ").trigger('change'); \n"; + } + Yii::app()->clientScript->registerScript('copyAddressFromAccountToContactScript', " + $('#Contact_account_id').live('change', function() + { + if($('#Contact_account_id').val() && + !$('#Contact_primaryAddress_street1').val() && + !$('#Contact_primaryAddress_street2').val() && + !$('#Contact_primaryAddress_city').val() && + !$('#Contact_primaryAddress_state').val() && + !$('#Contact_primaryAddress_postalCode').val() && + !$('#Contact_primaryAddress_country').val() && + !$('#Contact_secondaryAddress_street1').val() && + !$('#Contact_secondaryAddress_street2').val() && + !$('#Contact_secondaryAddress_city').val() && + !$('#Contact_secondaryAddress_state').val() && + !$('#Contact_secondaryAddress_postalCode').val() && + !$('#Contact_secondaryAddress_country').val()) + { + $.ajax({ + url : '" . $url . "?id=' + $('#Contact_account_id').val(), + type : 'GET', + dataType: 'json', + success : function(data) + { + " . $successScript . " + }, + error : function() + { + //todo: error call + } + }); + } + } + ); + "); + } } ?> diff --git a/app/protected/modules/conversations/views/ConversationDetailsView.php b/app/protected/modules/conversations/views/ConversationDetailsView.php index 6e02ec089..9333635b8 100644 --- a/app/protected/modules/conversations/views/ConversationDetailsView.php +++ b/app/protected/modules/conversations/views/ConversationDetailsView.php @@ -53,7 +53,11 @@ public static function getDefaultMetadata() protected function renderFormLayout($form = null) { - //override since the details are done @see renderConversationContent + $content = $this->renderConversationContent(); + $content .= $this->renderConversationCommentsContent(); + $content .= $this->renderConversationCreateCommentContent(); + $content = ZurmoHtml::tag('div', array('class' => 'left-column'), $content); + return $content; } public function getTitle() @@ -64,13 +68,13 @@ public function getTitle() protected function renderRightSideContent($form = null) { assert('$form == null'); - $content = '
'; + $content = null; $content .= $this->renderConversationOpenCloseElement(); - $content .= '
'; $content .= $this->renderConversationRelatedToAndAttachmentsContent(); $content .= "

".Zurmo::t('ConversationsModule', 'Participants') . '

'; $content .= $this->renderConversationParticipantsContent(); - $content .= '
'; + $content = ZurmoHtml::tag('div', array('class' => 'right-side-edit-view-panel thread-info'), $content); + $content = ZurmoHtml::tag('div', array('class' => 'right-column'), $content); return $content; } @@ -81,14 +85,6 @@ protected function renderConversationOpenCloseElement() return $content; } - protected function renderAfterFormLayoutForDetailsContent() - { - $content = $this->renderConversationContent(); - $content .= $this->renderConversationCommentsContent(); - $content .= $this->renderConversationCreateCommentContent(); - return $content; - } - protected function renderConversationParticipantsContent() { $clipWidget = new ClipWidget(); @@ -119,7 +115,7 @@ protected function renderConversationRelatedToAndAttachmentsContent() $element->nonEditableTemplate = '{content}'; $contentForTable .= $element->render(); } - $content = ZurmoHtml::tag('table', array('class' => 'thred-details'), $contentForTable); + $content = ZurmoHtml::tag('table', array('class' => 'thread-details'), $contentForTable); return $content; } diff --git a/app/protected/modules/conversations/views/ConversationEditView.php b/app/protected/modules/conversations/views/ConversationEditView.php index b487ea9c4..563c5751b 100644 --- a/app/protected/modules/conversations/views/ConversationEditView.php +++ b/app/protected/modules/conversations/views/ConversationEditView.php @@ -111,7 +111,7 @@ protected function renderRightSideFormLayoutForEdit($form) $content = null; if ($this->getModel() instanceof OwnedSecurableItem) { - $content .= "

".Zurmo::t('ConversationsModule', 'Participants') . '

'; + $content .= '

' . Zurmo::t('ConversationsModule', 'Participants') . '

'; $element = new MultiplePeopleForConversationElement($this->getModel(), null, $form); $element->editableTemplate = '{content}{error}'; $content .= $element->render().'
'; diff --git a/app/protected/modules/designer/DesignerModule.php b/app/protected/modules/designer/DesignerModule.php index 4b7157bf8..9f957a130 100644 --- a/app/protected/modules/designer/DesignerModule.php +++ b/app/protected/modules/designer/DesignerModule.php @@ -54,7 +54,7 @@ public static function getAdminTabMenuItems($user = null) { $tabMenuItems = array( array( - 'label' => 'Designer', + 'label' => "eval:Zurmo::t('DesignerModule', 'Designer')", 'url' => array('/designer/default'), 'right' => self::RIGHT_ACCESS_DESIGNER, ), diff --git a/app/protected/modules/designer/elements/derived/LabelElement.php b/app/protected/modules/designer/elements/derived/LabelElement.php index b71c32907..3d5f1e164 100644 --- a/app/protected/modules/designer/elements/derived/LabelElement.php +++ b/app/protected/modules/designer/elements/derived/LabelElement.php @@ -59,7 +59,7 @@ protected function renderControlEditable() $element->editableTemplate = $editableTemplate; $content .= ZurmoHtml::tag('div', array('class' => 'has-lang-label'), $element->render()); } - return ZurmoHtml::tag('div', array('class' => 'has-lang-label'), $content); + return $content; } /** diff --git a/app/protected/modules/designer/tests/functional/cases/CreateDecimalAttribute.html b/app/protected/modules/designer/tests/functional/cases/CreateDecimalAttribute.html index 8567a6f84..301dd42ad 100644 --- a/app/protected/modules/designer/tests/functional/cases/CreateDecimalAttribute.html +++ b/app/protected/modules/designer/tests/functional/cases/CreateDecimalAttribute.html @@ -121,11 +121,6 @@ DecimalAttributeForm_defaultValue 67.894 - - type - DecimalAttributeForm_maxLength - 6 - type DecimalAttributeForm_precisionLength diff --git a/app/protected/modules/designer/tests/functional/cases/CreateIntegerAttribute.html b/app/protected/modules/designer/tests/functional/cases/CreateIntegerAttribute.html index f53fbf415..e2a5eb5d2 100644 --- a/app/protected/modules/designer/tests/functional/cases/CreateIntegerAttribute.html +++ b/app/protected/modules/designer/tests/functional/cases/CreateIntegerAttribute.html @@ -121,11 +121,6 @@ IntegerAttributeForm_defaultValue 1500 - - type - IntegerAttributeForm_maxLength - 6 - type IntegerAttributeForm_minValue diff --git a/app/protected/modules/designer/views/attributetypes/DecimalAttributeEditView.php b/app/protected/modules/designer/views/attributetypes/DecimalAttributeEditView.php index e0c985370..c29b381cf 100644 --- a/app/protected/modules/designer/views/attributetypes/DecimalAttributeEditView.php +++ b/app/protected/modules/designer/views/attributetypes/DecimalAttributeEditView.php @@ -86,15 +86,6 @@ public static function getDefaultMetadata() ), ) ), - array('cells' => - array( - array( - 'elements' => array( - array('attributeName' => 'maxLength', 'type' => 'Text'), - ), - ), - ) - ), array('cells' => array( array( diff --git a/app/protected/modules/designer/views/attributetypes/MinMaxValueAttributeEditView.php b/app/protected/modules/designer/views/attributetypes/MinMaxValueAttributeEditView.php index e40007a27..5c2d38e57 100644 --- a/app/protected/modules/designer/views/attributetypes/MinMaxValueAttributeEditView.php +++ b/app/protected/modules/designer/views/attributetypes/MinMaxValueAttributeEditView.php @@ -85,15 +85,6 @@ public static function getDefaultMetadata() ), ) ), - array('cells' => - array( - array( - 'elements' => array( - array('attributeName' => 'maxLength', 'type' => 'Text'), - ), - ), - ) - ), array('cells' => array( array( diff --git a/app/protected/modules/emailMessages/rules/EmailMessageMashableActivityRules.php b/app/protected/modules/emailMessages/rules/EmailMessageMashableActivityRules.php index 51e23464c..f2ec1a502 100644 --- a/app/protected/modules/emailMessages/rules/EmailMessageMashableActivityRules.php +++ b/app/protected/modules/emailMessages/rules/EmailMessageMashableActivityRules.php @@ -54,6 +54,7 @@ public function resolveSearchAttributesDataByRelatedItemId($relationItemId) 'relatedAttributeName' => 'personOrAccount', 'operatorType' => 'equals', 'value' => $relationItemId, + 'resolveAsSubquery' => true, ) ); $searchAttributeData['structure'] = '(1 or 2)'; @@ -75,9 +76,10 @@ public function resolveSearchAttributesDataByRelatedItemIds($relationItemIds) 'relatedAttributeName' => 'personOrAccount', 'operatorType' => 'oneOf', 'value' => $relationItemIds, + 'resolveAsSubquery' => true, ) ); - $searchAttributeData['structure'] = '1 or 2'; + $searchAttributeData['structure'] = '(1 or 2)'; return $this->resolveSearchAttributeDataForLatestActivities($searchAttributeData); } diff --git a/app/protected/modules/emailMessages/tests/functional/cases/CreateContactForEmail.html b/app/protected/modules/emailMessages/tests/functional/cases/CreateContactForEmail.html index b856bec24..8e36c0b3b 100644 --- a/app/protected/modules/emailMessages/tests/functional/cases/CreateContactForEmail.html +++ b/app/protected/modules/emailMessages/tests/functional/cases/CreateContactForEmail.html @@ -21,11 +21,6 @@ 45000 - - storeGlobal - javascript{Math.floor(Math.random()*11000)} - randomSuffix - open index.php/emailMessages/default/matchingList @@ -58,19 +53,34 @@ type - //div[@id='list-view']/table/tbody/tr/td/div/div/div/div[3]/div/form/div[2]/table/tbody/tr/td/div/div[3]/input + //div[@id='list-view']/table/tbody/tr/td/div/div/div/div[3]/div/form/div[2]/div/table/tbody/tr/td/div/div[3]/input ${randomSuffix} + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + type - //div[@id='ArchivedEmailMatchingListView']/div/table/tbody/tr/td/div/div/div/div[3]//div/form/div[2]/table/tbody/tr[5]/td/div/div/input + //div[@id='ArchivedEmailMatchingListView']/div/table/tbody/tr/td/div/div/div/div[3]/div/form/div[2]/div/table/tbody/tr[5]/td/div/div/input bob.message.zurmotest.com + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + click //div[@id='ArchivedEmailMatchingListView']/div/table/tbody/tr/td/div/div/div/div[3]/div/form/div[3]/div/a[2]/span[3] + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + assertTextPresent Email Address is not a valid email address. @@ -83,9 +93,14 @@ type - //div[@id='ArchivedEmailMatchingListView']/div/table/tbody/tr/td/div/div/div/div[3]//div/form/div[2]/table/tbody/tr[5]/td/div/div/input + //div[@id='ArchivedEmailMatchingListView']/div/table/tbody/tr/td/div/div/div/div[3]/div/form/div[2]/div/table/tbody/tr[5]/td/div/div/input bob.message@zurmotest.com + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + setSpeed 0 diff --git a/app/protected/modules/emailMessages/tests/functional/cases/CreateLeadForEmail.html b/app/protected/modules/emailMessages/tests/functional/cases/CreateLeadForEmail.html index 9808cc655..21d261442 100644 --- a/app/protected/modules/emailMessages/tests/functional/cases/CreateLeadForEmail.html +++ b/app/protected/modules/emailMessages/tests/functional/cases/CreateLeadForEmail.html @@ -21,11 +21,6 @@ 45000 - - storeGlobal - javascript{Math.floor(Math.random()*11000)} - randomSuffix - open index.php/emailMessages/demo/loadUnmatchedSampler @@ -68,19 +63,34 @@ type - //div[@id='list-view']/table/tbody/tr/td/div/div/div/div[4]/div/form/div[2]/table/tbody/tr/td/div/div[3]/input + //div[@id='list-view']/table/tbody/tr/td/div/div/div/div[4]/div/form/div[2]/div/table/tbody/tr/td/div/div[3]/input ${randomSuffix} + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + type - //div[@id='ArchivedEmailMatchingListView']/div/table/tbody/tr/td/div/div/div/div[4]//div/form/div[2]/table/tbody/tr[5]/td/div/div/input + //div[@id='ArchivedEmailMatchingListView']/div/table/tbody/tr/td/div/div/div/div[4]/div/form/div[2]/div/table/tbody/tr[5]/td/div/div/input bob.message.zurmotest.com + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + click //div[@id='ArchivedEmailMatchingListView']/div/table/tbody/tr/td/div/div/div/div[4]/div/form/div[3]/div/a[2]/span[3] + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + assertTextPresent Email Address is not a valid email address. @@ -93,9 +103,14 @@ type - //div[@id='ArchivedEmailMatchingListView']/div/table/tbody/tr/td/div/div/div/div[4]//div/form/div[2]/table/tbody/tr[5]/td/div/div/input + //div[@id='ArchivedEmailMatchingListView']/div/table/tbody/tr/td/div/div/div/div[4]/div/form/div[2]/div/table/tbody/tr[5]/td/div/div/input bob.message@zurmotest.com + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + setSpeed 0 diff --git a/app/protected/modules/emailMessages/tests/unit/EmailMessageMashableActivityRulesTest.php b/app/protected/modules/emailMessages/tests/unit/EmailMessageMashableActivityRulesTest.php new file mode 100644 index 000000000..cd8b5d8be --- /dev/null +++ b/app/protected/modules/emailMessages/tests/unit/EmailMessageMashableActivityRulesTest.php @@ -0,0 +1,154 @@ +user->userModel = User::getByUsername('super'); + } + + public function testResolveSearchAttributesDataByRelatedItemId() + { + $quote = DatabaseCompatibilityUtil::getQuote(); + $rules = new EmailMessageMashableActivityRules(); + $searchAttributeData = $rules->resolveSearchAttributesDataByRelatedItemId(5); + $joinTablesAdapter = new RedBeanModelJoinTablesQueryAdapter('EmailMessage'); + $where = RedBeanModelDataProvider::makeWhere('EmailMessage', $searchAttributeData, $joinTablesAdapter); + $compareWhere = "(({$quote}emailmessagesender{$quote}.{$quote}personoraccount_item_id{$quote} = 5) or (1 = "; + $compareWhere .= "(select 1 from {$quote}emailmessagerecipient{$quote} emailmessagerecipient where "; + $compareWhere .= "{$quote}emailmessagerecipient{$quote}.{$quote}emailmessage_id` = {$quote}emailmessage"; + $compareWhere .= "{$quote}.id and {$quote}emailmessagerecipient{$quote}.{$quote}personoraccount_item_id` = 5 limit 1)))"; + $this->assertEquals($compareWhere, $where); + + $sql = EmailMessage::makeSubsetOrCountSqlQuery('emailmessage', $joinTablesAdapter, 1, 5, $where, null); + $compareSubsetSql = "select {$quote}emailmessage{$quote}.{$quote}id{$quote} id "; + $compareSubsetSql .= "from {$quote}emailmessage{$quote} "; + $compareSubsetSql .= "left join {$quote}emailmessagesender{$quote} on "; + $compareSubsetSql .= "{$quote}emailmessagesender{$quote}.{$quote}id{$quote} = {$quote}emailmessage{$quote}."; + $compareSubsetSql .= "{$quote}sender_emailmessagesender_id{$quote} "; + $compareSubsetSql .= "where " . $compareWhere . ' '; + $compareSubsetSql .= 'limit 5 offset 1'; + $this->assertEquals($compareSubsetSql, $sql); + + //Make sure the sql runs properly. + $data = EmailMessage::getSubset($joinTablesAdapter, 0, 5, $where, null); + $this->assertEquals(0, count($data)); + } + + public function testResolveSearchAttributesDataByRelatedItemIds() + { + $quote = DatabaseCompatibilityUtil::getQuote(); + $rules = new EmailMessageMashableActivityRules(); + $searchAttributeData = $rules->resolveSearchAttributesDataByRelatedItemIds(array(4, 5)); + $joinTablesAdapter = new RedBeanModelJoinTablesQueryAdapter('EmailMessage'); + $where = RedBeanModelDataProvider::makeWhere('EmailMessage', $searchAttributeData, $joinTablesAdapter); + $compareWhere = "(({$quote}emailmessagesender{$quote}.{$quote}personoraccount_item_id{$quote} IN(4,5)) or (1 = "; // Not Coding Standard + $compareWhere .= "(select 1 from {$quote}emailmessagerecipient{$quote} emailmessagerecipient where "; + $compareWhere .= "{$quote}emailmessagerecipient{$quote}.{$quote}emailmessage_id` = {$quote}emailmessage"; + $compareWhere .= "{$quote}.id and {$quote}emailmessagerecipient{$quote}.{$quote}personoraccount_item_id` IN(4,5) limit 1)))"; + $this->assertEquals($compareWhere, $where); + + $sql = EmailMessage::makeSubsetOrCountSqlQuery('emailmessage', $joinTablesAdapter, 1, 5, $where, null); + $compareSubsetSql = "select {$quote}emailmessage{$quote}.{$quote}id{$quote} id "; + $compareSubsetSql .= "from {$quote}emailmessage{$quote} "; + $compareSubsetSql .= "left join {$quote}emailmessagesender{$quote} on "; + $compareSubsetSql .= "{$quote}emailmessagesender{$quote}.{$quote}id{$quote} = {$quote}emailmessage{$quote}."; + $compareSubsetSql .= "{$quote}sender_emailmessagesender_id{$quote} "; + $compareSubsetSql .= "where " . $compareWhere . ' '; + $compareSubsetSql .= 'limit 5 offset 1'; + $this->assertEquals($compareSubsetSql, $sql); + + //Make sure the sql runs properly. + $data = EmailMessage::getSubset($joinTablesAdapter, 0, 5, $where, null); + $this->assertEquals(0, count($data)); + } + + public function testResolveSearchAttributesDataByRelatedItemIdWithRegularUser() + { + Yii::app()->user->userModel = User::getByUsername('benny'); + $mungeIds = ReadPermissionsOptimizationUtil::getMungeIdsByUser(Yii::app()->user->userModel); + $quote = DatabaseCompatibilityUtil::getQuote(); + $rules = new EmailMessageMashableActivityRules(); + $searchAttributeData = $rules->resolveSearchAttributesDataByRelatedItemId(5); + $joinTablesAdapter = new RedBeanModelJoinTablesQueryAdapter('EmailMessage'); + $where = RedBeanModelDataProvider::makeWhere('EmailMessage', $searchAttributeData, $joinTablesAdapter); + $compareWhere = "(({$quote}emailmessagesender{$quote}.{$quote}personoraccount_item_id{$quote} = 5) or (1 = "; + $compareWhere .= "(select 1 from {$quote}emailmessagerecipient{$quote} emailmessagerecipient where "; + $compareWhere .= "{$quote}emailmessagerecipient{$quote}.{$quote}emailmessage_id` = {$quote}emailmessage"; + $compareWhere .= "{$quote}.id and {$quote}emailmessagerecipient{$quote}.{$quote}personoraccount_item_id` = 5 limit 1)))"; + $this->assertEquals($compareWhere, $where); + + $sql = EmailMessage::makeSubsetOrCountSqlQuery('emailmessage', $joinTablesAdapter, 1, 5, $where, null); + $compareSubsetSql = "select distinct {$quote}emailmessage{$quote}.{$quote}id{$quote} id "; + $compareSubsetSql .= "from ({$quote}emailmessage{$quote}, {$quote}ownedsecurableitem{$quote}) "; + $compareSubsetSql .= "left join {$quote}emailmessagesender{$quote} on "; + $compareSubsetSql .= "{$quote}emailmessagesender{$quote}.{$quote}id{$quote} = {$quote}emailmessage{$quote}."; + $compareSubsetSql .= "{$quote}sender_emailmessagesender_id{$quote} "; + $compareSubsetSql .= "left join {$quote}emailmessage_read{$quote} on "; + $compareSubsetSql .= "{$quote}emailmessage_read{$quote}.{$quote}securableitem_id{$quote} = "; + $compareSubsetSql .= "{$quote}ownedsecurableitem{$quote}.{$quote}securableitem_id{$quote} "; + $compareSubsetSql .= "and {$quote}munge_id{$quote} in ('" . join("', '", $mungeIds) . "') "; + $compareSubsetSql .= "where (" . $compareWhere . ') '; + $compareSubsetSql .= "and ({$quote}ownedsecurableitem{$quote}.{$quote}owner__user_id{$quote} = " . Yii::app()->user->userModel->id. " "; + $compareSubsetSql .= "OR {$quote}emailmessage_read{$quote}.{$quote}munge_id{$quote} IS NOT NULL) "; // Not Coding Standard + $compareSubsetSql .= "and {$quote}ownedsecurableitem{$quote}.{$quote}id{$quote} = "; + $compareSubsetSql .= "{$quote}emailmessage{$quote}.{$quote}ownedsecurableitem_id{$quote} "; + $compareSubsetSql .= 'limit 5 offset 1'; + $this->assertEquals($compareSubsetSql, $sql); + + //Make sure the sql runs properly. + $data = EmailMessage::getSubset($joinTablesAdapter, 0, 5, $where, null); + $this->assertEquals(0, count($data)); + } + } +?> \ No newline at end of file diff --git a/app/protected/modules/import/elements/ImportRulesTypeRadioDropDownElement.php b/app/protected/modules/import/elements/ImportRulesTypeRadioDropDownElement.php index 17362e0d6..59c746b89 100644 --- a/app/protected/modules/import/elements/ImportRulesTypeRadioDropDownElement.php +++ b/app/protected/modules/import/elements/ImportRulesTypeRadioDropDownElement.php @@ -71,7 +71,7 @@ protected function renderLabel() { throw new NotImplementedException(); } - return ZurmoHtml::tag('span', array(), Zurmo::t('ImportModule', 'Please select the module you would like to import to:')); + return ZurmoHtml::tag('h3', array(), Zurmo::t('ImportModule', 'Please select the module you would like to import to:')); } public function getEditableHtmlOptions() diff --git a/app/protected/modules/import/rules/ImportRules.php b/app/protected/modules/import/rules/ImportRules.php index 0016c9546..fa402129c 100644 --- a/app/protected/modules/import/rules/ImportRules.php +++ b/app/protected/modules/import/rules/ImportRules.php @@ -286,7 +286,10 @@ public static function getRequiredAttributesCollectionNotIncludingReadOnly() $requireAttributesCollection = array(); foreach ($attributesCollection as $attributeIndex => $attributeData) { - if ($attributeData['isRequired'] && !$model->isAttributeReadOnly($attributeData['attributeName'])) + if (!in_array($attributeData['attributeName'], static::getNonImportableAttributeNames()) && + !in_array($attributeData['attributeImportRulesType'], static::getNonImportableAttributeImportRulesTypes()) && + $attributeData['isRequired'] && + !$model->isAttributeReadOnly($attributeData['attributeName'])) { $requireAttributesCollection[$attributeIndex] = $attributeData; } diff --git a/app/protected/modules/import/utils/ModelAttributeRulesToDefaultValueMappingRuleUtil.php b/app/protected/modules/import/utils/ModelAttributeRulesToDefaultValueMappingRuleUtil.php index d464c2809..c3d0c8f83 100644 --- a/app/protected/modules/import/utils/ModelAttributeRulesToDefaultValueMappingRuleUtil.php +++ b/app/protected/modules/import/utils/ModelAttributeRulesToDefaultValueMappingRuleUtil.php @@ -110,6 +110,10 @@ public static function getApplicableRulesByModelClassNameAndAttributeName($model //Ignore dateTimeDefault validator for this as it is not applicable to import //It would map to RedBeanModelDateTimeDefaultValueValidator and is unneeded continue; + case 'probability': + //Ignore probability validator for this as it is not applicable to import + //It would map to RedBeanModelProbabilityValidator and is unneeded + continue; case 'RedBeanModelCompareDateTimeValidator': //Ignore dateTimeDefault validator for this as it is not applicable to import //We can't control if the user is mapping both the dates that are part of this diff --git a/app/protected/modules/import/views/ImportWizardImportRulesView.php b/app/protected/modules/import/views/ImportWizardImportRulesView.php index 7c90ed376..2f2fb61d0 100644 --- a/app/protected/modules/import/views/ImportWizardImportRulesView.php +++ b/app/protected/modules/import/views/ImportWizardImportRulesView.php @@ -52,13 +52,7 @@ protected function renderFormLayout($form = null) $element->editableTemplate = '{label}{content}'; $content = $form->errorSummary($this->model); - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '
' . "\n"; $content .= $element->render(); - $content .= '
' . "\n"; return $content; } } diff --git a/app/protected/modules/import/views/ImportWizardSetModelPermissionsView.php b/app/protected/modules/import/views/ImportWizardSetModelPermissionsView.php index d40fc14ee..ff51e22d8 100644 --- a/app/protected/modules/import/views/ImportWizardSetModelPermissionsView.php +++ b/app/protected/modules/import/views/ImportWizardSetModelPermissionsView.php @@ -58,13 +58,7 @@ protected function renderFormLayout($form = null) $element->editableTemplate = $label . '{content}'; $content = $form->errorSummary($this->model); - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '
' . "\n"; - $content .= $element->render(); - $content .= '
' . "\n"; + $content .= ZurmoHtml::tag('div', array('class' => 'right-side-edit-view-panel'), $element->render()); return $content; } diff --git a/app/protected/modules/leads/controllers/DefaultController.php b/app/protected/modules/leads/controllers/DefaultController.php index 28d761d28..164346adb 100644 --- a/app/protected/modules/leads/controllers/DefaultController.php +++ b/app/protected/modules/leads/controllers/DefaultController.php @@ -135,13 +135,31 @@ public function actionEdit($id, $redirectUrl = null) } else { - $view = new LeadsPageView(ZurmoDefaultViewUtil:: - makeStandardViewForCurrentUser($this, - $this->makeEditAndDetailsView( - $this->attemptToSaveModelFromPost($contact, $redirectUrl), 'Edit', - 'LeadTitleBarAndEditAndDetailsView'))); - echo $view->render(); + $this->processEdit($contact, $redirectUrl); + } + } + + public function actionCopy($id) + { + $copyToContact = new Contact(); + $postVariableName = get_class($copyToContact); + if (!isset($_POST[$postVariableName])) + { + $contact = Contact::getById((int)$id); + ControllerSecurityUtil::resolveAccessCanCurrentUserReadModel($contact); + ZurmoCopyModelUtil::copy($contact, $copyToContact); } + $this->processEdit($copyToContact); + } + + protected function processEdit(Contact $contact, $redirectUrl = null) + { + $view = new LeadsPageView(ZurmoDefaultViewUtil:: + makeStandardViewForCurrentUser($this, + $this->makeEditAndDetailsView( + $this->attemptToSaveModelFromPost($contact, $redirectUrl), 'Edit', + 'LeadTitleBarAndEditAndDetailsView'))); + echo $view->render(); } /** diff --git a/app/protected/modules/leads/views/LeadEditAndDetailsView.php b/app/protected/modules/leads/views/LeadEditAndDetailsView.php index 028993275..f96bf5fdc 100644 --- a/app/protected/modules/leads/views/LeadEditAndDetailsView.php +++ b/app/protected/modules/leads/views/LeadEditAndDetailsView.php @@ -47,6 +47,7 @@ public static function getDefaultMetadata() array('type' => 'EditLink', 'renderType' => 'Details'), array('type' => 'AuditEventsModalListLink', 'renderType' => 'Details'), array('type' => 'ConvertLink', 'renderType' => 'Details'), + array('type' => 'CopyLink', 'renderType' => 'Details'), array('type' => 'LeadDeleteLink', 'renderType' => 'Details'), ), ), diff --git a/app/protected/modules/marketingLists/jobs/AutoresponderMessageInQueueJob.php b/app/protected/modules/marketingLists/jobs/AutoresponderMessageInQueueJob.php index 2c2373d86..e7facae96 100644 --- a/app/protected/modules/marketingLists/jobs/AutoresponderMessageInQueueJob.php +++ b/app/protected/modules/marketingLists/jobs/AutoresponderMessageInQueueJob.php @@ -38,7 +38,6 @@ * A job for processing autoresponder messages that are not sent immediately when triggered */ - // TODO: @Shoaibi: Critical99: These needs tests. class AutoresponderMessageInQueueJob extends BaseJob { /** diff --git a/app/protected/modules/mashableInbox/tests/functional/cases/CheckInbox.html b/app/protected/modules/mashableInbox/tests/functional/cases/CheckInbox.html index 2bb15e598..5944a0909 100644 --- a/app/protected/modules/mashableInbox/tests/functional/cases/CheckInbox.html +++ b/app/protected/modules/mashableInbox/tests/functional/cases/CheckInbox.html @@ -154,12 +154,12 @@ verifyElementPresent - //div[@id='ConversationDetailsView']/div/div[2]/div/div/div/div[2]/label + //div[@id='ConversationDetailsView']/div/div[3]/div/div/div/div[2]/label click - //div[@id='ConversationDetailsView']/div/div[2]/div/div/div/div[2]/label + //div[@id='ConversationDetailsView']/div/div[3]/div/div/div/div[2]/label diff --git a/app/protected/modules/missions/views/MissionDetailsView.php b/app/protected/modules/missions/views/MissionDetailsView.php index a877ad9b1..8c2c338ab 100644 --- a/app/protected/modules/missions/views/MissionDetailsView.php +++ b/app/protected/modules/missions/views/MissionDetailsView.php @@ -66,6 +66,7 @@ protected function renderAfterFormLayoutForDetailsContent() $content = $this->renderMissionContent(); $content .= $this->renderMissionCommentsContent(); $content .= $this->renderMissionCreateCommentContent(); + $content = ZurmoHtml::tag('div', array('class' => 'left-column full-width'), $content); return $content; } diff --git a/app/protected/modules/opportunities/OpportunitiesModule.php b/app/protected/modules/opportunities/OpportunitiesModule.php index 98916e746..7b2054158 100644 --- a/app/protected/modules/opportunities/OpportunitiesModule.php +++ b/app/protected/modules/opportunities/OpportunitiesModule.php @@ -76,6 +76,14 @@ public static function getDefaultMetadata() 'globalSearchAttributeNames' => array( 'name' ), + 'stageToProbabilityMapping' => array( + 'Prospecting' => 10, + 'Qualification' => 25, + 'Negotiating' => 50, + 'Verbal' => 75, + 'Closed Won' => 100, + 'Closed Lost' => 0, + ), 'tabMenuItems' => array( array( 'label' => "eval:Zurmo::t('OpportunitiesModule', 'OpportunitiesModulePluralLabel', \$translationParams)", @@ -165,5 +173,26 @@ public static function canHaveContentTemplates() { return true; } + + public static function getStageToProbabilityMappingData() + { + $metadata = static::getMetadata(); + if (isset($metadata['global']['stageToProbabilityMapping'])) + { + return $metadata['global']['stageToProbabilityMapping']; + } + return array(); + } + + public static function getProbabilityByStageValue($value) + { + assert('is_string($value) || $value == null'); + $stageToProbabilityMapping = self::getStageToProbabilityMappingData(); + if (isset($stageToProbabilityMapping[$value])) + { + return $stageToProbabilityMapping[$value]; + } + return 0; + } } ?> diff --git a/app/protected/modules/opportunities/controllers/DefaultController.php b/app/protected/modules/opportunities/controllers/DefaultController.php index 5a5027fd3..58f0e3625 100644 --- a/app/protected/modules/opportunities/controllers/DefaultController.php +++ b/app/protected/modules/opportunities/controllers/DefaultController.php @@ -135,6 +135,25 @@ public function actionEdit($id, $redirectUrl = null) { $opportunity = Opportunity::getById(intval($id)); ControllerSecurityUtil::resolveAccessCanCurrentUserWriteModel($opportunity); + $this->processEdit($opportunity, $redirectUrl); + + } + + public function actionCopy($id) + { + $copyToOpportunity = new Opportunity(); + $postVariableName = get_class($copyToOpportunity); + if (!isset($_POST[$postVariableName])) + { + $opportunity = Opportunity::getById((int)$id); + ControllerSecurityUtil::resolveAccessCanCurrentUserReadModel($opportunity); + ZurmoCopyModelUtil::copy($opportunity, $copyToOpportunity); + } + $this->processEdit($copyToOpportunity); + } + + protected function processEdit(Opportunity $opportunity, $redirectUrl = null) + { $view = new OpportunitiesPageView(ZurmoDefaultViewUtil:: makeStandardViewForCurrentUser($this, $this->makeEditAndDetailsView( diff --git a/app/protected/modules/opportunities/data/OpportunitiesDefaultDataMaker.php b/app/protected/modules/opportunities/data/OpportunitiesDefaultDataMaker.php index 3f672f049..471d41ccf 100644 --- a/app/protected/modules/opportunities/data/OpportunitiesDefaultDataMaker.php +++ b/app/protected/modules/opportunities/data/OpportunitiesDefaultDataMaker.php @@ -39,6 +39,10 @@ */ class OpportunitiesDefaultDataMaker extends DefaultDataMaker { + /** + * If you change the stages using the custom management, then make sure to change stageToProbabilityMapping + * in OpportunitiesModule metadata as well. + */ public function make() { $values = array( diff --git a/app/protected/modules/opportunities/elements/StageToProbabilityMappingElement.php b/app/protected/modules/opportunities/elements/StageToProbabilityMappingElement.php new file mode 100644 index 000000000..cbefc042d --- /dev/null +++ b/app/protected/modules/opportunities/elements/StageToProbabilityMappingElement.php @@ -0,0 +1,82 @@ + $this->getEditableInputId(), 'style' => "display:none;")); + foreach(OpportunitiesModule::getStageToProbabilityMappingData() as $stage => $probability) + { + $htmlOptions = array( + 'name' => $this->getNameForInputField($stage), + 'value' => $probability, + ); + + $element = $this->form->textField($this->model, $this->attribute, $htmlOptions); + $element .= ZurmoHtml::tag('span', array(), $stage); + $content .= ZurmoHtml::tag('div', array('class' => 'has-lang-label'), $element); + } + return $content; + } + + protected function renderControlNonEditable() + { + throw new NotSupportedException(); + } + + protected function getIdForInputField($suffix) + { + return $this->resolveInputIdPrefix() . '_' . $this->attribute . '_'. $suffix; + } + + protected function getNameForInputField($suffix) + { + return $this->resolveInputNamePrefix() . '[' . $this->attribute . '][' . $suffix . ']'; + } + } +?> diff --git a/app/protected/modules/opportunities/forms/OpportunitiesModuleForm.php b/app/protected/modules/opportunities/forms/OpportunitiesModuleForm.php index 550bd737e..1689260e4 100644 --- a/app/protected/modules/opportunities/forms/OpportunitiesModuleForm.php +++ b/app/protected/modules/opportunities/forms/OpportunitiesModuleForm.php @@ -36,5 +36,43 @@ class OpportunitiesModuleForm extends GlobalSearchEnabledModuleForm { + public $stageToProbabilityMapping; + + public function rules() + { + return array_merge(parent::rules(), array( + array('stageToProbabilityMapping', 'validateStageToProbabilityMapping'), + )); + } + + public function attributeLabels() + { + return array_merge(parent::attributeLabels(), array( + 'stageToProbabilityMapping' => Zurmo::t('OpportunitiesModule', 'Probability Mapping'), + )); + } + + public function validateStageToProbabilityMapping() + { + $validator = new RedBeanModelTypeValidator(); + $validator->type = 'integer'; + $valid = true; + if(!is_array($this->stageToProbabilityMapping)) + { + $this->addError('stageToProbabilityMapping', Zurmo::t('Core', '{attribute} must be {type}.', + array('{type}' => 'integer'))); + $valid = false; + } + foreach($this->stageToProbabilityMapping as $probability) + { + if(!$validator->validateValue($probability)) + { + $this->addError('stageToProbabilityMapping', + Zurmo::t('OpportunitiesModule', 'Mapped Probabilities must be integers')); + $valid = false; + } + } + return $valid; + } } ?> \ No newline at end of file diff --git a/app/protected/modules/opportunities/models/Opportunity.php b/app/protected/modules/opportunities/models/Opportunity.php index 6267e59ca..d8df362ae 100644 --- a/app/protected/modules/opportunities/models/Opportunity.php +++ b/app/protected/modules/opportunities/models/Opportunity.php @@ -50,6 +50,22 @@ public static function getStageClosedWonValue() return 'Closed Won'; } + protected function beforeSave() + { + if (parent::beforeSave()) + { + if (array_key_exists('value', $this->stage->originalAttributeValues)) + { + $this->resolveStageToProbability(); + } + return true; + } + else + { + return false; + } + } + public function __toString() { try @@ -131,6 +147,7 @@ public static function getDefaultMetadata() array('probability', 'numerical', 'min' => 0, 'max' => 100), array('probability', 'required'), array('probability', 'default', 'value' => 0), + array('probability', 'probability'), array('stage', 'required'), ), 'elements' => array( @@ -173,5 +190,17 @@ public static function getGamificationRulesType() { return 'OpportunityGamification'; } + + private function resolveStageToProbability() + { + if($this->stage === null) + { + throw new NotSupportedException(); + } + else + { + $this->probability = OpportunitiesModule::getProbabilityByStageValue($this->stage->value); + } + } } ?> diff --git a/app/protected/modules/opportunities/rules/OpportunitiesImportRules.php b/app/protected/modules/opportunities/rules/OpportunitiesImportRules.php index 216a28219..f2666040e 100644 --- a/app/protected/modules/opportunities/rules/OpportunitiesImportRules.php +++ b/app/protected/modules/opportunities/rules/OpportunitiesImportRules.php @@ -43,5 +43,14 @@ public static function getModelClassName() { return 'Opportunity'; } + + /** + * Override to block out additional attributes that are not importable + * @return array + */ + public static function getNonImportableAttributeNames() + { + return array_merge(parent::getNonImportableAttributeNames(), array('probability')); + } } ?> \ No newline at end of file diff --git a/app/protected/modules/opportunities/tests/unit/OpportunitiesModuleFormTest.php b/app/protected/modules/opportunities/tests/unit/OpportunitiesModuleFormTest.php new file mode 100644 index 000000000..480445378 --- /dev/null +++ b/app/protected/modules/opportunities/tests/unit/OpportunitiesModuleFormTest.php @@ -0,0 +1,61 @@ +stageToProbabilityMapping = array('a' => 'a'); + $validated = $form->validateStageToProbabilityMapping(); + $this->assertFalse($validated); + $compareErrors = array('stageToProbabilityMapping' => array('Mapped Probabilities must be integers')); + $this->assertEquals($compareErrors, $form->getErrors()); + + $form->stageToProbabilityMapping = array('a' => '55', 'b' => 65, 'c' => 0); + $form->clearErrors(); + $validated = $form->validateStageToProbabilityMapping(); + $this->assertTrue($validated); + $this->assertEquals(0, count($form->getErrors())); + } + } +?> \ No newline at end of file diff --git a/app/protected/modules/opportunities/tests/unit/OpportunityImportTest.php b/app/protected/modules/opportunities/tests/unit/OpportunityImportTest.php index 013997bd4..46a9cbbee 100644 --- a/app/protected/modules/opportunities/tests/unit/OpportunityImportTest.php +++ b/app/protected/modules/opportunities/tests/unit/OpportunityImportTest.php @@ -80,7 +80,7 @@ public function testSimpleUserImportWhereAllRowsSucceed() Yii::getPathOfAlias('application.modules.opportunities.tests.unit.files')); //update the ids of the account column to match the parent account. - R::exec("update " . $import->getTempTableName() . " set column_4 = " . + R::exec("update " . $import->getTempTableName() . " set column_3 = " . $account->id . " where id != 1 limit 4"); $this->assertEquals(4, ImportDatabaseUtil::getCount($import->getTempTableName())); // includes header rows. @@ -90,12 +90,11 @@ public function testSimpleUserImportWhereAllRowsSucceed() $mappingData = array( 'column_0' => ImportMappingUtil::makeStringColumnMappingData ('name'), 'column_1' => ImportMappingUtil::makeDateColumnMappingData ('closeDate'), - 'column_2' => ImportMappingUtil::makeIntegerColumnMappingData ('probability'), - 'column_3' => ImportMappingUtil::makeIntegerColumnMappingData ('description'), - 'column_4' => ImportMappingUtil::makeHasOneColumnMappingData ('account'), - 'column_5' => ImportMappingUtil::makeDropDownColumnMappingData ('stage'), - 'column_6' => ImportMappingUtil::makeDropDownColumnMappingData ('source'), - 'column_7' => ImportMappingUtil::makeCurrencyColumnMappingData ('amount', $currency), + 'column_2' => ImportMappingUtil::makeIntegerColumnMappingData ('description'), + 'column_3' => ImportMappingUtil::makeHasOneColumnMappingData ('account'), + 'column_4' => ImportMappingUtil::makeDropDownColumnMappingData ('stage'), + 'column_5' => ImportMappingUtil::makeDropDownColumnMappingData ('source'), + 'column_6' => ImportMappingUtil::makeCurrencyColumnMappingData ('amount', $currency), ); $importRules = ImportRulesUtil::makeImportRulesByType('Opportunities'); @@ -132,7 +131,7 @@ public function testSimpleUserImportWhereAllRowsSucceed() $this->assertEquals(1, count($opportunities[0])); $this->assertEquals('opp2', $opportunities[0]->name); $this->assertEquals('1980-06-04', $opportunities[0]->closeDate); - $this->assertEquals(20, $opportunities[0]->probability); + $this->assertEquals(25, $opportunities[0]->probability); $this->assertEquals('desc2', $opportunities[0]->description); $this->assertTrue($opportunities[0]->account->isSame($account)); $this->assertEquals('Qualification', $opportunities[0]->stage->value); @@ -143,7 +142,7 @@ public function testSimpleUserImportWhereAllRowsSucceed() $this->assertEquals(1, count($opportunities[0])); $this->assertEquals('opp3', $opportunities[0]->name); $this->assertEquals('1980-06-05', $opportunities[0]->closeDate); - $this->assertEquals(30, $opportunities[0]->probability); + $this->assertEquals(50, $opportunities[0]->probability); $this->assertEquals('desc3', $opportunities[0]->description); $this->assertTrue($opportunities[0]->account->isSame($account)); $this->assertEquals('Negotiating', $opportunities[0]->stage->value); @@ -203,7 +202,7 @@ public function testImportWithRateAndCurrencyCodeSpecified() Yii::getPathOfAlias('application.modules.opportunities.tests.unit.files')); //update the ids of the account column to match the parent account. - R::exec("update " . $import->getTempTableName() . " set column_4 = " . + R::exec("update " . $import->getTempTableName() . " set column_3 = " . $account->id . " where id != 1 limit 4"); $this->assertEquals(4, ImportDatabaseUtil::getCount($import->getTempTableName())); // includes header rows. @@ -213,12 +212,11 @@ public function testImportWithRateAndCurrencyCodeSpecified() $mappingData = array( 'column_0' => ImportMappingUtil::makeStringColumnMappingData ('name'), 'column_1' => ImportMappingUtil::makeDateColumnMappingData ('closeDate'), - 'column_2' => ImportMappingUtil::makeIntegerColumnMappingData ('probability'), - 'column_3' => ImportMappingUtil::makeIntegerColumnMappingData ('description'), - 'column_4' => ImportMappingUtil::makeHasOneColumnMappingData ('account'), - 'column_5' => ImportMappingUtil::makeDropDownColumnMappingData ('stage'), - 'column_6' => ImportMappingUtil::makeDropDownColumnMappingData ('source'), - 'column_7' => ImportMappingUtil::makeCurrencyColumnMappingData ('amount', $currency), + 'column_2' => ImportMappingUtil::makeIntegerColumnMappingData ('description'), + 'column_3' => ImportMappingUtil::makeHasOneColumnMappingData ('account'), + 'column_4' => ImportMappingUtil::makeDropDownColumnMappingData ('stage'), + 'column_5' => ImportMappingUtil::makeDropDownColumnMappingData ('source'), + 'column_6' => ImportMappingUtil::makeCurrencyColumnMappingData ('amount', $currency), ); $importRules = ImportRulesUtil::makeImportRulesByType('Opportunities'); @@ -236,7 +234,7 @@ public function testImportWithRateAndCurrencyCodeSpecified() $messageLogger); $importResultsUtil->processStatusAndMessagesForEachRow(); - //Confirm that 6 models where created. + //Confirm that 3 models where created. $opportunities = Opportunity::getAll(); $this->assertEquals(3, count($opportunities)); @@ -257,7 +255,7 @@ public function testImportWithRateAndCurrencyCodeSpecified() $this->assertEquals(1, count($opportunities[0])); $this->assertEquals('opp2', $opportunities[0]->name); $this->assertEquals('1980-06-04', $opportunities[0]->closeDate); - $this->assertEquals(20, $opportunities[0]->probability); + $this->assertEquals(25, $opportunities[0]->probability); $this->assertEquals('desc2', $opportunities[0]->description); $this->assertTrue($opportunities[0]->account->isSame($account)); $this->assertEquals('Qualification', $opportunities[0]->stage->value); @@ -270,7 +268,7 @@ public function testImportWithRateAndCurrencyCodeSpecified() $this->assertEquals(1, count($opportunities[0])); $this->assertEquals('opp3', $opportunities[0]->name); $this->assertEquals('1980-06-05', $opportunities[0]->closeDate); - $this->assertEquals(30, $opportunities[0]->probability); + $this->assertEquals(50, $opportunities[0]->probability); $this->assertEquals('desc3', $opportunities[0]->description); $this->assertTrue($opportunities[0]->account->isSame($account)); $this->assertEquals('Negotiating', $opportunities[0]->stage->value); diff --git a/app/protected/modules/opportunities/tests/unit/OpportunityTest.php b/app/protected/modules/opportunities/tests/unit/OpportunityTest.php index 9a6e7e9d4..eed68fe5e 100644 --- a/app/protected/modules/opportunities/tests/unit/OpportunityTest.php +++ b/app/protected/modules/opportunities/tests/unit/OpportunityTest.php @@ -47,13 +47,31 @@ public function testCreateStageValues() $stageValues = array( 'Prospecting', 'Negotiating', - 'Close Won', + 'Closed Won', ); $stageFieldData = CustomFieldData::getByName('SalesStages'); $stageFieldData->serializedData = serialize($stageValues); $this->assertTrue($stageFieldData->save()); } + /** + * @depends testCreateStageValues + */ + public function testGetStageToProbabilityMappingData() + { + $this->assertEquals(6, count(OpportunitiesModule::getStageToProbabilityMappingData())); + } + + /** + * @depends testGetStageToProbabilityMappingData + */ + public function testGetProbabilityByStageValue() + { + $this->assertEquals(10, OpportunitiesModule::getProbabilityByStageValue ('Prospecting')); + $this->assertEquals(50, OpportunitiesModule::getProbabilityByStageValue ('Negotiating')); + $this->assertEquals(100, OpportunitiesModule::getProbabilityByStageValue ('Closed Won')); + } + /** * @depends testCreateStageValues */ @@ -72,8 +90,10 @@ public function testVariousCurrencyValues() $opportunity->amount = $currencyValue; $opportunity->closeDate = '2011-01-01'; $opportunity->stage->value = 'Verbal'; + $this->assertEquals(0, $opportunity->probability); $saved = $opportunity->save(); $this->assertTrue($saved); + $this->assertEquals(75, $opportunity->probability); $opportunity1Id = $opportunity->id; $opportunity->forget(); @@ -307,7 +327,7 @@ public function testSetStageAndSourceAndRetrieveDisplayName() $stageValues = array( 'Prospecting', 'Negotiating', - 'Close Won', + 'Closed Won', ); $stageFieldData = CustomFieldData::getByName('SalesStages'); $stageFieldData->serializedData = serialize($stageValues); diff --git a/app/protected/modules/opportunities/tests/unit/files/importTest.csv b/app/protected/modules/opportunities/tests/unit/files/importTest.csv index 3db21411b..57370a6d2 100644 --- a/app/protected/modules/opportunities/tests/unit/files/importTest.csv +++ b/app/protected/modules/opportunities/tests/unit/files/importTest.csv @@ -1,4 +1,4 @@ -name,closeDate,probability,description,account,stage,source,amount -opp1,06-03-1980,10,desc1,toUpdate,Prospecting,Self-Generated,500 -opp2,06-04-1980,20,desc2,toUpdate,Qualification,Inbound Call,501 -opp3,06-05-1980,30,desc3,toUpdate,Negotiating,Tradeshow,502 \ No newline at end of file +name,closeDate,description,account,stage,source,amount +opp1,06-03-1980,desc1,toUpdate,Prospecting,Self-Generated,500 +opp2,06-04-1980,desc2,toUpdate,Qualification,Inbound Call,501 +opp3,06-05-1980,desc3,toUpdate,Negotiating,Tradeshow,502 \ No newline at end of file diff --git a/app/protected/modules/opportunities/tests/unit/files/importTestIncludingRateAndCurrencyCode.csv b/app/protected/modules/opportunities/tests/unit/files/importTestIncludingRateAndCurrencyCode.csv index e0012afb2..e8220b97c 100644 --- a/app/protected/modules/opportunities/tests/unit/files/importTestIncludingRateAndCurrencyCode.csv +++ b/app/protected/modules/opportunities/tests/unit/files/importTestIncludingRateAndCurrencyCode.csv @@ -1,4 +1,4 @@ -name,closeDate,probability,description,account,stage,source,amount -opp1,06-03-1980,10,desc1,toUpdate,Prospecting,Self-Generated,500__1__USD -opp2,06-04-1980,20,desc2,toUpdate,Qualification,Inbound Call,501__2.7__GBP -opp3,06-05-1980,30,desc3,toUpdate,Negotiating,Tradeshow,502__3.2__EUR \ No newline at end of file +name,closeDate,description,account,stage,source,amount +opp1,06-03-1980,desc1,toUpdate,Prospecting,Self-Generated,500__1__USD +opp2,06-04-1980,desc2,toUpdate,Qualification,Inbound Call,501__2.7__GBP +opp3,06-05-1980,desc3,toUpdate,Negotiating,Tradeshow,502__3.2__EUR \ No newline at end of file diff --git a/app/protected/modules/opportunities/tests/unit/walkthrough/OpportunitiesDesignerSuperUserWalkthroughTest.php b/app/protected/modules/opportunities/tests/unit/walkthrough/OpportunitiesDesignerSuperUserWalkthroughTest.php index a9b8df696..9c5feac34 100644 --- a/app/protected/modules/opportunities/tests/unit/walkthrough/OpportunitiesDesignerSuperUserWalkthroughTest.php +++ b/app/protected/modules/opportunities/tests/unit/walkthrough/OpportunitiesDesignerSuperUserWalkthroughTest.php @@ -267,7 +267,6 @@ public function testCreateAnOpportunityAfterTheCustomFieldsArePlacedForOpportuni 'amount' => array('value' => 298000, 'currency' => array('id' => $baseCurrency->id)), 'account' => array('id' => $accountId), - 'probability' => '1', 'closeDate' => $date, 'stage' => array('value' => 'Prospecting'), 'source' => array('value' => 'Self-Generated'), @@ -308,7 +307,7 @@ public function testCreateAnOpportunityAfterTheCustomFieldsArePlacedForOpportuni $this->assertEquals($opportunity->amount->value , '298000'); $this->assertEquals($opportunity->amount->currency->id , $baseCurrency->id); $this->assertEquals($opportunity->account->id , $accountId); - $this->assertEquals($opportunity->probability , '1'); + $this->assertEquals($opportunity->probability , '10'); $this->assertEquals($opportunity->stage->value , 'Prospecting'); $this->assertEquals($opportunity->source->value , 'Self-Generated'); $this->assertEquals($opportunity->description , 'This is the Description'); @@ -367,7 +366,6 @@ public function testWhetherSearchWorksForTheCustomFieldsPlacedForOpportunitiesMo 'closeDate__Date' => array('value' => 'Today'), 'stage' => array('value' => 'Prospecting'), 'source' => array('value' => 'Self-Generated'), - 'probability' => '1', 'decimalCstm' => '123', 'integerCstm' => '12', 'phoneCstm' => '259-784-2169', @@ -424,7 +422,6 @@ public function testEditOfTheOpportunityForTheTagCloudFieldAfterRemovingAllTagsP 'currency' => array( 'id' => $baseCurrency->id)), 'account' => array('id' => $accountId), - 'probability' => '2', 'closeDate' => $date, 'stage' => array('value' => 'Qualification'), 'source' => array('value' => 'Inbound Call'), @@ -466,7 +463,7 @@ public function testEditOfTheOpportunityForTheTagCloudFieldAfterRemovingAllTagsP $this->assertEquals($opportunity->amount->value , '288000'); $this->assertEquals($opportunity->amount->currency->id , $baseCurrency->id); $this->assertEquals($opportunity->account->id , $accountId); - $this->assertEquals($opportunity->probability , '2'); + $this->assertEquals($opportunity->probability , '25'); $this->assertEquals($opportunity->stage->value , 'Qualification'); $this->assertEquals($opportunity->source->value , 'Inbound Call'); $this->assertEquals($opportunity->description , 'This is the Edit Description'); @@ -529,7 +526,6 @@ public function testEditOfTheOpportunityForTheCustomFieldsPlacedForOpportunities 'currency' => array( 'id' => $baseCurrency->id)), 'account' => array('id' => $accountId), - 'probability' => '2', 'closeDate' => $date, 'stage' => array('value' => 'Qualification'), 'source' => array('value' => 'Inbound Call'), @@ -571,7 +567,7 @@ public function testEditOfTheOpportunityForTheCustomFieldsPlacedForOpportunities $this->assertEquals($opportunity->amount->value , '288000'); $this->assertEquals($opportunity->amount->currency->id , $baseCurrency->id); $this->assertEquals($opportunity->account->id , $accountId); - $this->assertEquals($opportunity->probability , '2'); + $this->assertEquals($opportunity->probability , '25'); $this->assertEquals($opportunity->stage->value , 'Qualification'); $this->assertEquals($opportunity->source->value , 'Inbound Call'); $this->assertEquals($opportunity->description , 'This is the Edit Description'); diff --git a/app/protected/modules/opportunities/views/OpportunitiesMassEditView.php b/app/protected/modules/opportunities/views/OpportunitiesMassEditView.php index 1694f1bd9..9ab82f6ad 100644 --- a/app/protected/modules/opportunities/views/OpportunitiesMassEditView.php +++ b/app/protected/modules/opportunities/views/OpportunitiesMassEditView.php @@ -48,6 +48,7 @@ public static function getDefaultMetadata() ), 'nonPlaceableAttributeNames' => array( 'name', + 'probability', ), 'panelsDisplayType' => FormLayout::PANELS_DISPLAY_TYPE_ALL, 'panels' => array( diff --git a/app/protected/modules/opportunities/views/OpportunitiesModuleEditView.php b/app/protected/modules/opportunities/views/OpportunitiesModuleEditView.php index 383879ec3..f79e18ffd 100644 --- a/app/protected/modules/opportunities/views/OpportunitiesModuleEditView.php +++ b/app/protected/modules/opportunities/views/OpportunitiesModuleEditView.php @@ -36,5 +36,20 @@ class OpportunitiesModuleEditView extends GlobalSearchEnabledModuleEditView { + public static function getDefaultMetadata() + { + $metadata = parent::getDefaultMetadata(); + $metadata['global']['panels'][0]['rows'][] = + array('cells' => + array( + array( + 'elements' => array( + array('attributeName' => 'stageToProbabilityMapping', 'type' => 'StageToProbabilityMapping'), + ), + ), + ), + ); + return $metadata; + } } ?> \ No newline at end of file diff --git a/app/protected/modules/opportunities/views/OpportunityEditAndDetailsView.php b/app/protected/modules/opportunities/views/OpportunityEditAndDetailsView.php index 5e72b6eb4..b09fb798c 100644 --- a/app/protected/modules/opportunities/views/OpportunityEditAndDetailsView.php +++ b/app/protected/modules/opportunities/views/OpportunityEditAndDetailsView.php @@ -44,8 +44,9 @@ public static function getDefaultMetadata() 'elements' => array( array('type' => 'SaveButton', 'renderType' => 'Edit'), array('type' => 'CancelLink', 'renderType' => 'Edit'), - array('type' => 'EditLink', 'renderType' => 'Details'), + array('type' => 'EditLink', 'renderType' => 'Details'), array('type' => 'AuditEventsModalListLink', 'renderType' => 'Details'), + array('type' => 'CopyLink', 'renderType' => 'Details'), array('type' => 'OpportunityDeleteLink', 'renderType' => 'Details'), ), ), @@ -95,19 +96,19 @@ public static function getDefaultMetadata() ) ), array('cells' => + array( array( - array( - 'elements' => array( - array('attributeName' => 'probability', 'type' => 'Integer'), - ), + 'elements' => array( + array('attributeName' => 'stage', 'type' => 'DropDown', 'addBlank' => true), ), - ) + ), + ) ), array('cells' => array( array( 'elements' => array( - array('attributeName' => 'stage', 'type' => 'DropDown', 'addBlank' => true), + array('attributeName' => 'probability', 'type' => 'Integer'), ), ), ) @@ -141,7 +142,58 @@ public static function getDefaultMetadata() protected function getNewModelTitleLabel() { return Zurmo::t('OpportunitiesModule', 'Create OpportunitiesModuleSingularLabel', - LabelUtil::getTranslationParamsForAllModules()); + LabelUtil::getTranslationParamsForAllModules()); + } + + /** + * Override to disabling probability attribute. + */ + protected function resolveElementInformationDuringFormLayoutRender(& $elementInformation) + { + parent::resolveElementInformationDuringFormLayoutRender($elementInformation); + if($elementInformation['attributeName'] == 'probability') + { + $elementInformation['disabled'] = true; + } + } + + protected function renderAfterFormLayout($form) + { + parent::renderAfterFormLayout($form); + $this->registerStageToProbabilityMappingScript($form); + } + + protected function registerStageToProbabilityMappingScript($form) + { + $stageInputId = Element::resolveInputIdPrefixIntoString(array(get_class($this->model), 'stage', 'value')); + $probabilityInputId = Element::resolveInputIdPrefixIntoString(array(get_class($this->model), 'probability')); + $mappingData = OpportunitiesModule::getStageToProbabilityMappingData(); + if(count($mappingData) > 0) + { + $jsonEncodedMapping = CJSON::encode($mappingData); + Yii::app()->clientScript->registerScript('stageToProbabilityMapping', " + $('#" . $stageInputId . "').unbind('change'); + $('#" . $stageInputId . "').bind('change', function() + { + stageToProbabilityMapping($(this)); + } + ); + function stageToProbabilityMapping(stageInput) + { + var value = stageInput.val(); + var result = $.parseJSON('" . $jsonEncodedMapping . "'); + $('#" . $probabilityInputId . "').val(0); + $.each(result, function(stage, probability) { + if(value == stage) + { + $('#" . $probabilityInputId . "').val(probability); + return false; + } + }); + } + stageToProbabilityMapping($('#" . $stageInputId . "')); + "); + } } } ?> diff --git a/app/protected/modules/reports/adapters/columns/IntegerForReportListViewColumnAdapter.php b/app/protected/modules/reports/adapters/columns/IntegerForReportListViewColumnAdapter.php new file mode 100644 index 000000000..b949d468c --- /dev/null +++ b/app/protected/modules/reports/adapters/columns/IntegerForReportListViewColumnAdapter.php @@ -0,0 +1,70 @@ + $this->attribute, + 'value' => 'IntegerForReportListViewColumnAdapter::renderNonEditableStatically($data, "' . $this->attribute . '")', + 'type' => 'raw', + ); + } + + public static function renderNonEditableStatically($model, $attribute) + { + assert('$model instanceof ReportResultsRowData'); + if(null === $displayAttributeKey = $model::resolveKeyByAttributeName($attribute)) + { + return $model->{$attribute}; + } + $displayAttributes = $model->getDisplayAttributes(); + $displayAttribute = $displayAttributes[$displayAttributeKey]; + $realAttributeName = $displayAttribute->getResolvedAttribute(); + if($model->getModel($attribute) instanceof RedBeanModel && + $model->getModel($attribute)->isAttributeFormattedAsProbability($realAttributeName)) + { + $resolvedValue = NumberUtil::divisionForZero($model->{$attribute}, 100); + return Yii::app()->numberFormatter->formatPercentage($resolvedValue); + } + else + { + return $model->{$attribute}; + } + } + } +?> \ No newline at end of file diff --git a/app/protected/modules/reports/components/ReportResultsRowData.php b/app/protected/modules/reports/components/ReportResultsRowData.php index 20dade5cb..609c6da8f 100644 --- a/app/protected/modules/reports/components/ReportResultsRowData.php +++ b/app/protected/modules/reports/components/ReportResultsRowData.php @@ -88,6 +88,17 @@ public static function resolveAttributeNameByKey($key) return self::ATTRIBUTE_NAME_PREFIX . $key; } + public static function resolveKeyByAttributeName($attribute) + { + assert('is_string($attribute)'); + $parts = explode(self::ATTRIBUTE_NAME_PREFIX, $attribute); + if (count($parts) == 2 && $parts[1] != null) + { + return $parts[1]; + } + return null; + } + public function getDisplayAttributes() { return $this->displayAttributes; diff --git a/app/protected/modules/reports/tests/functional/cases/CreateOpportunitiesSummationReport.html b/app/protected/modules/reports/tests/functional/cases/CreateOpportunitiesSummationReport.html index 45e91719e..93f0432f4 100644 --- a/app/protected/modules/reports/tests/functional/cases/CreateOpportunitiesSummationReport.html +++ b/app/protected/modules/reports/tests/functional/cases/CreateOpportunitiesSummationReport.html @@ -202,7 +202,7 @@ Opportunity - click + doubleClick //li[@id='OrderBys_amount__Summation']/span @@ -214,7 +214,7 @@ waitForText //ul[@id='OrderBysattributeRowsUl']/li/div/div/div[1] - Opportunity + Amount -(Sum) click @@ -231,15 +231,20 @@ id=SummationReportWizardForm_ChartForReportForm_type_7 + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + select id=SummationReportWizardForm_ChartForReportForm_firstSeries label=Stage - click - //option[@value='stage'] - + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 select @@ -247,9 +252,9 @@ label=Amount -(Sum) - click - //option[@value='amount__Summation'] - + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 click diff --git a/app/protected/modules/reports/views/ChartForReportWizardView.php b/app/protected/modules/reports/views/ChartForReportWizardView.php index bdda97dbb..faf39d479 100644 --- a/app/protected/modules/reports/views/ChartForReportWizardView.php +++ b/app/protected/modules/reports/views/ChartForReportWizardView.php @@ -125,17 +125,26 @@ protected function renderFormContent() $inputPrefixData = array(get_class($this->model), get_class($this->model->chart)); $this->form->setInputPrefixData($inputPrefixData); $params = array('inputPrefix' => $inputPrefixData); - $content = '
'; - $element = new ChartTypeRadioStaticDropDownForReportElement($this->model->chart, 'type', $this->form, - array_merge($params, array('addBlank' => true))); - $leftSideContent = $element->render(); - $element = new MixedChartRangeAndSeriesElement($this->model->chart, null, $this->form, $params); - $content .= ZurmoHtml::tag('div', array('class' => 'panel'), $leftSideContent); - $rightSideContent = ZurmoHtml::tag('div', array(), $element->render()); - $rightSideContent = ZurmoHtml::tag('div', array('class' => 'buffer'), $rightSideContent); - $content .= ZurmoHtml::tag('div', array('id' => 'series-and-range-areas', 'class' => 'right-side-edit-view-panel hidden-element'), $rightSideContent); - $content .= $this->renderChartTipContent(); - $content .= '
'; + + + $leftSideContent = null; + $element = new ChartTypeRadioStaticDropDownForReportElement($this->model->chart, 'type', $this->form, + array_merge($params, array('addBlank' => true))); + $leftSideContent = $element->render(); + $element = new MixedChartRangeAndSeriesElement($this->model->chart, null, $this->form, $params); + $leftSideContent = ZurmoHtml::tag('div', array('class' => 'panel'), $leftSideContent); + $leftSideContent = ZurmoHtml::tag('div', array('class' => 'left-column'), $leftSideContent); + + $rightSideContent = $element->render(); + $rightSideContent = ZurmoHtml::tag('div', array('id' => 'series-and-range-areas', + 'class' => 'right-side-edit-view-panel hidden-element'), $rightSideContent); + $rightSideContent .= $this->renderChartTipContent(); + $rightSideContent = ZurmoHtml::tag('div', array('class' => 'right-column'), $rightSideContent); + + $content = '
'; + $content .= $leftSideContent . $rightSideContent; + $content .= '
'; + $this->form->clearInputPrefixData(); $this->registerScripts(); return $content; @@ -147,9 +156,7 @@ protected function renderChartTipContent() $content .= ZurmoHtml::tag('p', array(), Zurmo::t('WorkflowsModule', 'In order to use a grouping as a series field, ' . 'the grouping must be added as a display column.')); - $content = ZurmoHtml::tag('div', array(), $content); - $content = ZurmoHtml::tag('div', array('class' => 'buffer'), $content); - $content = ZurmoHtml::tag('div', array('class' => 'right-side-edit-view-panel'), $content); + $content = ZurmoHtml::tag('div', array('class' => 'right-side-edit-view-panel'), $content); return $content; } } diff --git a/app/protected/modules/reports/views/ComponentWithTreeForReportWizardView.php b/app/protected/modules/reports/views/ComponentWithTreeForReportWizardView.php index 74809472d..a0dcf969b 100644 --- a/app/protected/modules/reports/views/ComponentWithTreeForReportWizardView.php +++ b/app/protected/modules/reports/views/ComponentWithTreeForReportWizardView.php @@ -72,9 +72,9 @@ public static function getTreeDivId() */ protected function renderFormContent() { - $content = $this->renderAttributesAndRelationsTreeContent(); - $content .= ZurmoHtml::tag('div', array('class' => 'dynamic-droppable-area'), - $this->renderRightSideContent()); + $content = $this->renderAttributesAndRelationsTreeContent(); + $content .= ZurmoHtml::tag('div', array('class' => 'dynamic-droppable-area'), $this->renderRightSideContent()); + $content = ZurmoHtml::tag('div', array('class' => 'left-column full-width'), $content); return $content; } diff --git a/app/protected/modules/reports/views/GeneralDataForReportWizardView.php b/app/protected/modules/reports/views/GeneralDataForReportWizardView.php index 2a656bf12..f7b3d1941 100644 --- a/app/protected/modules/reports/views/GeneralDataForReportWizardView.php +++ b/app/protected/modules/reports/views/GeneralDataForReportWizardView.php @@ -68,24 +68,25 @@ public static function getNextPageLinkId() */ protected function renderFormContent() { - $content = '
'; + $leftSideContent = null; $element = new TextElement($this->model, 'name', $this->form); - $leftSideContent = '' . - '' . $element->render() . ''; - $element = new TextAreaElement( - $this->model, 'description', $this->form, array('rows' => 5)); + $leftSideContent = '
' . '' . $element->render() . ''; + $element = new TextAreaElement($this->model, 'description', $this->form, array('rows' => 5)); $leftSideContent .= '' . $element->render() . ''; - $element = new CurrencyConversionTypeStaticDropDownElement( - $this->model, 'currencyConversionType', $this->form); + $element = new CurrencyConversionTypeStaticDropDownElement($this->model, 'currencyConversionType', $this->form); $leftSideContent .= '' . $element->render() . ''; - $element = new CurrencyCodeStaticDropDownFormElement($this->model, 'spotConversionCurrencyCode', - $this->form, array('addBlank' => true)); + $element = new CurrencyCodeStaticDropDownFormElement($this->model, 'spotConversionCurrencyCode', $this->form, array('addBlank' => true)); $leftSideContent .= '' . $element->render() . '
'; - $content .= ZurmoHtml::tag('div', array('class' => 'panel'), $leftSideContent); - $rightSideContent = ZurmoHtml::tag('div', array(), $this->renderRightSideFormLayout()); - $rightSideContent = ZurmoHtml::tag('div', array('class' => 'buffer'), $rightSideContent); - $content .= ZurmoHtml::tag('div', array('class' => 'right-side-edit-view-panel'), $rightSideContent); - $content .= '
'; + $leftSideContent = ZurmoHtml::tag('div', array('class' => 'panel'), $leftSideContent); + $leftSideContent = ZurmoHtml::tag('div', array('class' => 'left-column'), $leftSideContent); + + $rightSideContent = ZurmoHtml::tag('div', array('class' => 'right-side-edit-view-panel'), $this->renderRightSideFormLayout()); + $rightSideContent = ZurmoHtml::tag('div', array('class' => 'right-column'), $rightSideContent); + + $content = '
'; + $content .= $leftSideContent . $rightSideContent; + $content .= '
'; + return $content; } diff --git a/app/protected/modules/reports/views/ModuleForReportWizardView.php b/app/protected/modules/reports/views/ModuleForReportWizardView.php index 3aa2ffd98..82ae6179c 100644 --- a/app/protected/modules/reports/views/ModuleForReportWizardView.php +++ b/app/protected/modules/reports/views/ModuleForReportWizardView.php @@ -68,18 +68,11 @@ public static function getNextPageLinkId() */ protected function renderFormContent() { - $element = new ModuleForReportRadioDropDownElement($this->model, 'moduleClassName', - $this->form); + $element = new ModuleForReportRadioDropDownElement($this->model, 'moduleClassName', $this->form); $element->editableTemplate = '{label}{content}'; - $content = $this->form->errorSummary($this->model); - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '
' . "\n"; $content .= $element->render(); - $content .= '
' . "\n"; + $content = ZurmoHtml::tag('div', array('class' => 'left-column full-width'), $content); return $content; } diff --git a/app/protected/modules/socialItems/tests/functional/cases/CommentOnNewPost.html b/app/protected/modules/socialItems/tests/functional/cases/CommentOnNewPost.html index c2cd3cb0e..6f32e8525 100644 --- a/app/protected/modules/socialItems/tests/functional/cases/CommentOnNewPost.html +++ b/app/protected/modules/socialItems/tests/functional/cases/CommentOnNewPost.html @@ -49,7 +49,7 @@ type - //div[@id='list-viewAllSocialItemsForPortletView']/table/tbody/tr/td/div/div[3]/div/div/div/form/div/table/tbody/tr/td/textarea + //div[@id='list-viewAllSocialItemsForPortletView']/table/tbody/tr/td/div/div[3]/div/div/div/form/div[2]/div/table/tbody/tr/td/textarea Test comment ${randomSuffix} diff --git a/app/protected/modules/socialItems/tests/functional/cases/CommentOnNewPostOnUserProfile.html b/app/protected/modules/socialItems/tests/functional/cases/CommentOnNewPostOnUserProfile.html index 10ba7cb2e..02e15b70e 100644 --- a/app/protected/modules/socialItems/tests/functional/cases/CommentOnNewPostOnUserProfile.html +++ b/app/protected/modules/socialItems/tests/functional/cases/CommentOnNewPostOnUserProfile.html @@ -33,7 +33,7 @@ type - //div[@id='list-viewUserSocialItemsForPortletView']/table/tbody/tr/td/div/div[3]/div/div/div/form/div[2]/table/tbody/tr/td/textarea + //div[@id='list-viewUserSocialItemsForPortletView']/table/tbody/tr/td/div/div[3]/div/div/div/form/div[2]/div/table/tbody/tr/td/textarea Test comment ${randomSuffix} diff --git a/app/protected/modules/tasks/adapters/columns/CloseTaskCheckBoxListViewColumnAdapter.php b/app/protected/modules/tasks/adapters/columns/CloseTaskCheckBoxListViewColumnAdapter.php index ba74fde2d..4a0b0407a 100644 --- a/app/protected/modules/tasks/adapters/columns/CloseTaskCheckBoxListViewColumnAdapter.php +++ b/app/protected/modules/tasks/adapters/columns/CloseTaskCheckBoxListViewColumnAdapter.php @@ -67,7 +67,7 @@ function closeOpenTaskByCheckBoxClick(checkboxId, modelId) $('#' + checkboxId).attr('disabled', true); $('#' + checkboxId).parent().addClass('c_on'); $('#' + checkboxId).parent().addClass('disabled'); - $('#' + checkboxId).parents('td').children().css('text-decoration', 'line-through'); + $('#' + checkboxId).parentsUntil('tr').parent().children().css('text-decoration', 'line-through'); $.ajax({ url : '" . Yii::app()->createUrl('tasks/default/closeTask') . "?id=' + modelId, type : 'GET', diff --git a/app/protected/modules/tasks/views/TaskEditAndDetailsView.php b/app/protected/modules/tasks/views/TaskEditAndDetailsView.php index 9211bf021..01130021b 100644 --- a/app/protected/modules/tasks/views/TaskEditAndDetailsView.php +++ b/app/protected/modules/tasks/views/TaskEditAndDetailsView.php @@ -46,6 +46,7 @@ public static function getDefaultMetadata() array('type' => 'CancelLink', 'renderType' => 'Edit'), array('type' => 'TaskDeleteLink'), array('type' => 'EditLink', 'renderType' => 'Details'), + array('type' => 'CopyLink', 'renderType' => 'Details'), array('type' => 'AuditEventsModalListLink', 'renderType' => 'Details'), ), ), diff --git a/app/protected/modules/tasks/views/related/OpenTasksRelatedListView.php b/app/protected/modules/tasks/views/related/OpenTasksRelatedListView.php index 469153a80..857e131bc 100644 --- a/app/protected/modules/tasks/views/related/OpenTasksRelatedListView.php +++ b/app/protected/modules/tasks/views/related/OpenTasksRelatedListView.php @@ -52,8 +52,9 @@ public static function getDefaultMetadata() ), 'rowMenu' => array( 'elements' => array( - array('type' => 'EditLink'), - array('type' => 'RelatedDeleteLink'), + array('type' => 'EditLink'), + array('type' => 'CopyLink',), + array('type' => 'RelatedDeleteLink'), ), ), 'derivedAttributeTypes' => array( diff --git a/app/protected/modules/users/UsersModule.php b/app/protected/modules/users/UsersModule.php index d1d863500..6c543066b 100644 --- a/app/protected/modules/users/UsersModule.php +++ b/app/protected/modules/users/UsersModule.php @@ -144,7 +144,7 @@ public static function getDefaultMetadata() $metadata['global'] = array( 'adminTabMenuItems' => array( array( - 'label' => 'Users', + 'label' => "eval:Zurmo::t('UsersModule', 'Users')", 'url' => array('/users/default'), 'right' => self::RIGHT_ACCESS_USERS, 'items' => array( diff --git a/app/protected/modules/workflows/WorkflowsModule.php b/app/protected/modules/workflows/WorkflowsModule.php index f1fab8d6d..e0353f60e 100644 --- a/app/protected/modules/workflows/WorkflowsModule.php +++ b/app/protected/modules/workflows/WorkflowsModule.php @@ -84,7 +84,7 @@ public static function getDefaultMetadata() ), 'adminTabMenuItems' => array( array( - 'label' => 'Workflows', + 'label' => "eval:Zurmo::t('WorkflowsModule', 'Workflows')", 'url' => array('/workflows/default'), 'right' => self::RIGHT_ACCESS_WORKFLOWS, ), @@ -92,8 +92,8 @@ public static function getDefaultMetadata() 'configureMenuItems' => array( array( 'category' => ZurmoModule::ADMINISTRATION_CATEGORY_GENERAL, - 'titleLabel' => "eval:Zurmo::t('UsersModule', 'Workflows')", - 'descriptionLabel' => "eval:Zurmo::t('UsersModule', 'Manage Workflows')", + 'titleLabel' => "eval:Zurmo::t('WorkflowsModule', 'Workflows')", + 'descriptionLabel' => "eval:Zurmo::t('WorkflowsModule', 'Manage Workflows')", 'route' => '/workflows/default', 'right' => self::RIGHT_CREATE_WORKFLOWS, ), diff --git a/app/protected/modules/workflows/controllers/DemoController.php b/app/protected/modules/workflows/controllers/DemoController.php index eae65dae9..8e8fd0523 100644 --- a/app/protected/modules/workflows/controllers/DemoController.php +++ b/app/protected/modules/workflows/controllers/DemoController.php @@ -65,7 +65,11 @@ public function actionLoadByTimeWorkflowInQueue() $savedWorkflow->type = Workflow::TYPE_BY_TIME; $savedWorkflow->isActive = false; $savedWorkflow->order = 1; - $savedWorkflow->serializedData = serialize(array()); + $savedWorkflow->serializedData = serialize(array( + ComponentForWorkflowForm::TYPE_TRIGGERS => array(), + ComponentForWorkflowForm::TYPE_ACTIONS => array(), + ComponentForWorkflowForm::TYPE_EMAIL_MESSAGES => array(), + )); $saved = $savedWorkflow->save(); if (!$saved) { @@ -110,7 +114,11 @@ public function actionLoadWorkflowMessageInQueue() $savedWorkflow->type = Workflow::TYPE_BY_TIME; $savedWorkflow->isActive = false; $savedWorkflow->order = 1; - $savedWorkflow->serializedData = serialize(array()); + $savedWorkflow->serializedData = serialize(array( + ComponentForWorkflowForm::TYPE_TRIGGERS => array(), + ComponentForWorkflowForm::TYPE_ACTIONS => array(), + ComponentForWorkflowForm::TYPE_EMAIL_MESSAGES => array(), + )); $saved = $savedWorkflow->save(); if (!$saved) { diff --git a/app/protected/modules/workflows/tests/functional/cases/CreateWorkflow.html b/app/protected/modules/workflows/tests/functional/cases/CreateWorkflow.html index ef7e5f6d8..df2dd5b91 100644 --- a/app/protected/modules/workflows/tests/functional/cases/CreateWorkflow.html +++ b/app/protected/modules/workflows/tests/functional/cases/CreateWorkflow.html @@ -74,14 +74,24 @@ click - //div[@id='ModuleForWorkflowWizardView']/table/tbody/tr/td/div/input + //div[@id='ModuleForWorkflowWizardView']/div/div[2]/input + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + click //a[@id='moduleNextLink']/span[3] + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + waitForText //div[@id='TriggersTreeArea']/div/ul/li[1]/span @@ -92,36 +102,46 @@ //div[@id='TriggersTreeArea']/div/ul/li[1]/ul/li[1]/span + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + waitForText - //div[@id='TriggersForWorkflowWizardView']/div[2]/div[1]/div[1]/ul/li/div/div/div[1] + //div[@id='TriggersForWorkflowWizardView']/div[1]/div[2]/div[1]/div[1]/ul/li/div/div/div[1] Annual Revenue + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + type id=OnSaveWorkflowWizardForm_Triggers_0_value 200000 + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + select id=OnSaveWorkflowWizardForm_Triggers_0_operator label=Less Than - click - //select[@id='OnSaveWorkflowWizardForm_Triggers_0_operator']/option[8] - + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 click //a[@id='triggersNextLink']/span[3] - - waitForPageToLoad - - - waitForCondition selenium.browserbot.getCurrentWindow().jQuery.active == 0 @@ -137,11 +157,6 @@ //div[@id='ActionsForWorkflowWizardView']/div/div/div/select label=Create - - click - //select[@id='actionType']/option[4] - - waitForCondition selenium.browserbot.getCurrentWindow().jQuery.active == 0 @@ -157,6 +172,11 @@ selenium.browserbot.getCurrentWindow().jQuery.active == 0 30000 + + waitForElementPresent + id=OnSaveWorkflowWizardForm_Actions_0_ActionAttributes_name_value + + type id=OnSaveWorkflowWizardForm_Actions_0_ActionAttributes_name_value @@ -167,11 +187,6 @@ selenium.browserbot.getCurrentWindow().jQuery.active == 0 30000 - - focus - id=OnSaveWorkflowWizardForm_Actions_0_ActionAttributes_owner__User_stringifiedModelForValue - - click //a[@id='OnSaveWorkflowWizardForm_Actions_0_ActionAttributes_owner__User_users_SelectLink']/span[2] @@ -297,6 +312,11 @@ OnSaveWorkflowWizardForm_name WorkflowTest ${randomSuffix} + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + click //a[@id='generalDataSaveAndRunLink']/span[3] @@ -313,9 +333,14 @@ 30000 - waitForText - //div[@id='WorkflowDetailsView']/div/div[2]/table/tbody/tr[1]/td - WorkflowTest + waitForTextPresent + WorkflowTest ${randomSuffix} + + + + assertTextPresent + WorkflowTest ${randomSuffix} + diff --git a/app/protected/modules/workflows/tests/functional/cases/EditWorkflow.html b/app/protected/modules/workflows/tests/functional/cases/EditWorkflow.html index 2bf524f6c..0216583ba 100644 --- a/app/protected/modules/workflows/tests/functional/cases/EditWorkflow.html +++ b/app/protected/modules/workflows/tests/functional/cases/EditWorkflow.html @@ -19,7 +19,7 @@ open - index.php/workflows/default + index.php/workflows/default?clearingSearch=1 @@ -32,16 +32,31 @@ selenium.browserbot.getCurrentWindow().jQuery.active == 0 30000 + + verifyElementPresent + id=WorkflowsSearchForm_anyMixedAttributes + + type id=WorkflowsSearchForm_anyMixedAttributes WorkflowTest ${randomSuffix} + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + keyUp id=WorkflowsSearchForm_anyMixedAttributes \10 + + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 + waitForText //div[@id='list-view']/table/tbody/tr[1]/td[2]/a @@ -57,9 +72,14 @@ WorkflowsSearchForm_anyMixedAttributes WorkflowTest ${randomSuffix} - + + + clickAndWait + link=WorkflowTest ${randomSuffix} @@ -73,7 +93,7 @@ 30000 - waitForText + assertText //div[@id='WorkflowDetailsView']/div/div[2]/table/tbody/tr[1]/td WorkflowTest ${randomSuffix} @@ -97,24 +117,19 @@ //a[@id='moduleNextLink']/span[3] - - waitForPageToLoad - - - waitForCondition selenium.browserbot.getCurrentWindow().jQuery.active == 0 30000 - click - //a[@id='triggersNextLink']/span[3] + waitForTextPresent + Office Fax - waitForPageToLoad - + click + //a[@id='triggersNextLink']/span[3] @@ -123,28 +138,23 @@ 30000 - click - //a[@id='actionsNextLink']/span[3] + waitForTextPresent + Create Account click - //a[@id='triggersNextLink']/span[3] - - - - waitForPageToLoad - + //a[@id='actionsNextLink']/span[3] - select - id=addRecipientType_0 - label=All users in a specific role + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 - click - //select[@id='addRecipientType_0']/option[4] + waitForTextPresent + A person associated with the triggered record @@ -153,13 +163,13 @@ - click - //a[@id='triggersNextLink']/span[3] - + waitForCondition + selenium.browserbot.getCurrentWindow().jQuery.active == 0 + 30000 - waitForPageToLoad - + waitForTextPresent + Save Workflow @@ -168,7 +178,7 @@ WorkflowTestEdit ${randomSuffix} - click + clickAndWait //a[@id='generalDataSaveAndRunLink']/span[3] @@ -183,7 +193,7 @@ 30000 - waitForText + assertText //div[@id='WorkflowDetailsView']/div/h1/span/span WorkflowTestEdit ${randomSuffix} diff --git a/app/protected/modules/workflows/views/ActionsForWorkflowWizardView.php b/app/protected/modules/workflows/views/ActionsForWorkflowWizardView.php index 1d3348a8d..be39ea5be 100644 --- a/app/protected/modules/workflows/views/ActionsForWorkflowWizardView.php +++ b/app/protected/modules/workflows/views/ActionsForWorkflowWizardView.php @@ -148,11 +148,10 @@ protected function isListContentSortable() */ protected function renderFormContent() { - $content = '
'; - $content .= $this->renderAttributeSelectorContentAndWrapper(); + $content = $this->renderAttributeSelectorContentAndWrapper(); $content .= $this->renderZeroComponentsContentAndWrapper(); $content .= $this->renderActionsContentAndWrapper(); - $content .= '
'; + $content = ZurmoHtml::tag('div', array('class' => 'left-column full-width'), $content); $this->registerScripts(); return $content; } diff --git a/app/protected/modules/workflows/views/ByTimeWorkflowInQueuesListView.php b/app/protected/modules/workflows/views/ByTimeWorkflowInQueuesListView.php index 9d63d8bdd..5f3dae4c2 100644 --- a/app/protected/modules/workflows/views/ByTimeWorkflowInQueuesListView.php +++ b/app/protected/modules/workflows/views/ByTimeWorkflowInQueuesListView.php @@ -59,6 +59,14 @@ public function __construct( $this->rowsAreSelectable = false; } + /** + * Override to remove action buttons. + */ + protected function getCGridViewLastColumn() + { + return array(); + } + /** * @return array */ diff --git a/app/protected/modules/workflows/views/ComponentWithTreeForWorkflowWizardView.php b/app/protected/modules/workflows/views/ComponentWithTreeForWorkflowWizardView.php index ae34ded67..56c82b364 100644 --- a/app/protected/modules/workflows/views/ComponentWithTreeForWorkflowWizardView.php +++ b/app/protected/modules/workflows/views/ComponentWithTreeForWorkflowWizardView.php @@ -72,9 +72,9 @@ public static function getTreeDivId() */ protected function renderFormContent() { - $content = $this->renderAttributesAndRelationsTreeContent(); - $content .= ZurmoHtml::tag('div', array('class' => 'dynamic-droppable-area'), - $this->renderRightSideContent()); + $content = $this->renderAttributesAndRelationsTreeContent(); + $content .= ZurmoHtml::tag('div', array('class' => 'dynamic-droppable-area'), $this->renderRightSideContent()); + $content = ZurmoHtml::tag('div', array('class' => 'left-column full-width'), $content); return $content; } diff --git a/app/protected/modules/workflows/views/EmailMessagesForWorkflowWizardView.php b/app/protected/modules/workflows/views/EmailMessagesForWorkflowWizardView.php index 17465105b..9d0ee094a 100644 --- a/app/protected/modules/workflows/views/EmailMessagesForWorkflowWizardView.php +++ b/app/protected/modules/workflows/views/EmailMessagesForWorkflowWizardView.php @@ -93,11 +93,10 @@ protected function isListContentSortable() */ protected function renderFormContent() { - $content = '
'; - $content .= $this->renderAddEmailMessageLinkContentAndWrapper(); + $content = $this->renderAddEmailMessageLinkContentAndWrapper(); $content .= $this->renderZeroComponentsContentAndWrapper(); $content .= $this->renderEmailMessagesContentAndWrapper(); - $content .= '
'; + $content = ZurmoHtml::tag('div', array('class' => 'left-column full-width'), $content); $this->registerScripts(); return $content; } diff --git a/app/protected/modules/workflows/views/GeneralDataForWorkflowWizardView.php b/app/protected/modules/workflows/views/GeneralDataForWorkflowWizardView.php index 21dbaf628..1106b6a52 100644 --- a/app/protected/modules/workflows/views/GeneralDataForWorkflowWizardView.php +++ b/app/protected/modules/workflows/views/GeneralDataForWorkflowWizardView.php @@ -68,21 +68,22 @@ public static function getNextPageLinkId() */ protected function renderFormContent() { - $content = '
'; + $leftSideContent = null; $element = new TextElement($this->model, 'name', $this->form); - $leftSideContent = '' . - '' . $element->render() . ''; - $element = new TextAreaElement( - $this->model, 'description', $this->form, array('rows' => 5)); + $leftSideContent = '
' . '' . $element->render() . ''; + $element = new TextAreaElement($this->model, 'description', $this->form, array('rows' => 5)); $leftSideContent .= '' . $element->render() . ''; - $element = new TriggerOnStaticDropDownElement( - $this->model, 'triggerOn', $this->form); + $element = new TriggerOnStaticDropDownElement($this->model, 'triggerOn', $this->form); $leftSideContent .= '' . $element->render() . ''; $element = new CheckBoxElement($this->model, 'isActive', $this->form); $leftSideContent .= '' . $element->render() . ''; $leftSideContent .= '
'; - $content .= ZurmoHtml::tag('div', array('class' => 'panel'), $leftSideContent); - $content .= '
'; + $leftSideContent = ZurmoHtml::tag('div', array('class' => 'panel'), $leftSideContent); + $leftSideContent = ZurmoHtml::tag('div', array('class' => 'left-column full-width'), $leftSideContent); + + $content = '
'; + $content .= $leftSideContent; + $content .= '
'; return $content; } diff --git a/app/protected/modules/workflows/views/ModuleForWorkflowWizardView.php b/app/protected/modules/workflows/views/ModuleForWorkflowWizardView.php index 0c084c1e6..011a25e92 100644 --- a/app/protected/modules/workflows/views/ModuleForWorkflowWizardView.php +++ b/app/protected/modules/workflows/views/ModuleForWorkflowWizardView.php @@ -73,13 +73,8 @@ protected function renderFormContent() $element->editableTemplate = '{label}{content}'; $content = $this->form->errorSummary($this->model); - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '' . "\n"; - $content .= '
' . "\n"; $content .= $element->render(); - $content .= '
' . "\n"; + $content = ZurmoHtml::tag('div', array('class' => 'left-column full-width'), $content); return $content; } diff --git a/app/protected/modules/workflows/views/TimeTriggerForWorkflowWizardView.php b/app/protected/modules/workflows/views/TimeTriggerForWorkflowWizardView.php index b1f8706ad..05ccb6f2d 100644 --- a/app/protected/modules/workflows/views/TimeTriggerForWorkflowWizardView.php +++ b/app/protected/modules/workflows/views/TimeTriggerForWorkflowWizardView.php @@ -100,11 +100,10 @@ protected function getItemsCount() */ protected function renderFormContent() { - $content = '
'; - $content .= $this->renderAttributeSelectorContentAndWrapper(); + $content = $this->renderAttributeSelectorContentAndWrapper(); $content .= $this->renderZeroComponentsContentAndWrapper(); $content .= $this->renderTimeTriggerContentAndWrapper(); - $content .= '
'; + $content = ZurmoHtml::tag('div', array('class' => 'left-column full-width'), $content); $this->registerScripts(); return $content; } diff --git a/app/protected/modules/workflows/views/WorkflowMessageInQueuesListView.php b/app/protected/modules/workflows/views/WorkflowMessageInQueuesListView.php index e3cba4d20..26aade4cc 100644 --- a/app/protected/modules/workflows/views/WorkflowMessageInQueuesListView.php +++ b/app/protected/modules/workflows/views/WorkflowMessageInQueuesListView.php @@ -59,6 +59,14 @@ public function __construct( $this->rowsAreSelectable = false; } + /** + * Override to remove action buttons. + */ + protected function getCGridViewLastColumn() + { + return array(); + } + /** * @return array */ diff --git a/app/protected/modules/workflows/views/assets/WorkflowUtils.js b/app/protected/modules/workflows/views/assets/WorkflowUtils.js index 4b55a2c55..e0f4363c5 100644 --- a/app/protected/modules/workflows/views/assets/WorkflowUtils.js +++ b/app/protected/modules/workflows/views/assets/WorkflowUtils.js @@ -77,10 +77,9 @@ function rebuildWorkflowTriggersAttributeRowNumbersAndStructureInput(divId){ function rebuildWorkflowActionRowNumbers(divId){ rowCount = 1; - structure = ''; + structure = ''; //@TODO AA: Jason, why so we need this? its never used.. $('#' + divId).find('.dynamic-row-number-label').each(function(){ $(this).html(rowCount + '.'); - console.log(rowCount, $(this)); rowCount ++; }); } @@ -97,15 +96,15 @@ function toggleWorkflowShouldSetValueWrapper(checkboxId) } function rebuildWorkflowEmailMessageRowNumbers(divId){ rowCount = 1; - structure = ''; - $('#' + divId).find('.dynamic-row-number-label').each(function(){ + structure = ''; //@TODO AA: Jason, why so we need this? its never used.. + $('#' + divId).find('.dynamic-row-number-label:not(.dynamic-email-message-recipient-row-number-label)').each(function(){ $(this).html(rowCount + '.'); rowCount ++; }); } function rebuildWorkflowEmailMessageRecipientRowNumbers(object){ rowCount = 1; - structure = ''; + structure = ''; //@TODO AA: Jason, why so we need this? its never used.. $(object).find('.dynamic-email-message-recipient-row-number-label').each(function(){ $(this).html(rowCount + '.'); rowCount ++; diff --git a/app/protected/modules/zurmo/components/ZurmoBaseController.php b/app/protected/modules/zurmo/components/ZurmoBaseController.php index 0b4a76b43..5e4cb7946 100644 --- a/app/protected/modules/zurmo/components/ZurmoBaseController.php +++ b/app/protected/modules/zurmo/components/ZurmoBaseController.php @@ -54,7 +54,7 @@ public function filters() 'rightName' => $moduleClassName::getAccessRight(), ); $filters[] = array( - self::getRightsFilterPath() . ' + create, createFromRelation, inlineCreateSave', + self::getRightsFilterPath() . ' + create, createFromRelation, inlineCreateSave, copy', 'moduleClassName' => $moduleClassName, 'rightName' => $moduleClassName::getCreateRight(), ); diff --git a/app/protected/modules/zurmo/components/ZurmoModuleController.php b/app/protected/modules/zurmo/components/ZurmoModuleController.php index 2405e8d51..d617f08f9 100644 --- a/app/protected/modules/zurmo/components/ZurmoModuleController.php +++ b/app/protected/modules/zurmo/components/ZurmoModuleController.php @@ -98,9 +98,15 @@ public function actionAutoComplete($term) protected function renderAutoCompleteResults($modelClassName, $term) { - $pageSize = Yii::app()->pagination->resolveActiveForCurrentUserByType( - 'autoCompleteListPageSize', get_class($this->getModule())); + $pageSize = Yii::app()->pagination->resolveActiveForCurrentUserByType( + 'autoCompleteListPageSize', get_class($this->getModule())); $autoCompleteResults = ModelAutoCompleteUtil::getByPartialName($modelClassName, $term, $pageSize); + if(empty($autoCompleteResults)) + { + $autoCompleteResults = array(array('id' => null, + 'value' => null, + 'label' => Zurmo::t('Core', 'No results found'))); + } return CJSON::encode($autoCompleteResults); } @@ -143,6 +149,16 @@ protected function resolveNewModelByRelationInformation( $model, $relationAtt return $model; } + /** + * Override to implement + * @param $id + * @throws NotImplementedException + */ + public function actionCopy($id) + { + throw new NotImplementedException(); + } + public function actionAuditEventsModalList($id) { $modelClassName = $this->getModule()->getPrimaryModelName(); diff --git a/app/protected/modules/zurmo/elements/derived/DerivedExplicitReadWriteModelPermissionsElement.php b/app/protected/modules/zurmo/elements/derived/DerivedExplicitReadWriteModelPermissionsElement.php index ae01b5d2e..3a3f5b6f6 100644 --- a/app/protected/modules/zurmo/elements/derived/DerivedExplicitReadWriteModelPermissionsElement.php +++ b/app/protected/modules/zurmo/elements/derived/DerivedExplicitReadWriteModelPermissionsElement.php @@ -106,7 +106,7 @@ public static function getDisplayName() */ protected function resolveSelectedType() { - if (!$this->isModelCreateAction()) + if (!$this->isModelCreateAction() || $this->model->isCopied()) { return parent::resolveSelectedType(); } @@ -129,7 +129,7 @@ protected function resolveSelectedType() */ protected function resolveSelectedGroup() { - if (!$this->isModelCreateAction()) + if (!$this->isModelCreateAction()|| $this->model->isCopied()) { return parent::resolveSelectedGroup(); } diff --git a/app/protected/modules/zurmo/modules/GroupsModule.php b/app/protected/modules/zurmo/modules/GroupsModule.php index c1b77a1c0..8f45bc2b0 100644 --- a/app/protected/modules/zurmo/modules/GroupsModule.php +++ b/app/protected/modules/zurmo/modules/GroupsModule.php @@ -70,17 +70,17 @@ public static function getDefaultMetadata() $metadata['global'] = array( 'adminTabMenuItems' => array( array( - 'label' => 'Groups', + 'label' => "eval:Zurmo::t('ZurmoModule', 'Groups')", 'url' => array('/zurmo/group'), 'right' => self::RIGHT_ACCESS_GROUPS, 'items' => array( array( - 'label' => 'Create Group', + 'label' => "eval:Zurmo::t('ZurmoModule', 'Create Group')", 'url' => array('/zurmo/group/create'), 'right' => self::RIGHT_CREATE_GROUPS ), array( - 'label' => 'Groups', + 'label' => "eval:Zurmo::t('ZurmoModule', 'Groups')", 'url' => array('/zurmo/group'), 'right' => self::RIGHT_ACCESS_GROUPS ), @@ -90,8 +90,8 @@ public static function getDefaultMetadata() 'configureMenuItems' => array( array( 'category' => ZurmoModule::ADMINISTRATION_CATEGORY_GENERAL, - 'titleLabel' => 'Groups', - 'descriptionLabel' => 'Manage Groups', + 'titleLabel' => "eval:Zurmo::t('ZurmoModule', 'Groups')", + 'descriptionLabel' => "eval:Zurmo::t('ZurmoModule', 'Manage Groups')", 'route' => '/zurmo/group', 'right' => self::RIGHT_ACCESS_GROUPS, ), diff --git a/app/protected/modules/zurmo/modules/RolesModule.php b/app/protected/modules/zurmo/modules/RolesModule.php index 0ce7ffb75..baa95a75c 100644 --- a/app/protected/modules/zurmo/modules/RolesModule.php +++ b/app/protected/modules/zurmo/modules/RolesModule.php @@ -70,17 +70,17 @@ public static function getDefaultMetadata() $metadata['global'] = array( 'adminTabMenuItems' => array( array( - 'label' => 'Roles', + 'label' => "eval:Zurmo::t('ZurmoModule', 'Roles')", 'url' => array('/zurmo/role'), 'right' => self::RIGHT_ACCESS_ROLES, 'items' => array( array( - 'label' => 'Create Role', + 'label' => "eval:Zurmo::t('ZurmoModule', 'Create Role')", 'url' => array('/zurmo/role/create'), 'right' => self::RIGHT_CREATE_ROLES ), array( - 'label' => 'Roles', + 'label' => "eval:Zurmo::t('ZurmoModule', 'Roles')", 'url' => array('/zurmo/role'), 'right' => self::RIGHT_ACCESS_ROLES ), @@ -90,8 +90,8 @@ public static function getDefaultMetadata() 'configureMenuItems' => array( array( 'category' => ZurmoModule::ADMINISTRATION_CATEGORY_GENERAL, - 'titleLabel' => 'Roles', - 'descriptionLabel' => 'Manage Roles', + 'titleLabel' => "eval:Zurmo::t('ZurmoModule', 'Roles')", + 'descriptionLabel' => "eval:Zurmo::t('ZurmoModule', 'Manage Roles')", 'route' => '/zurmo/role', 'right' => self::RIGHT_ACCESS_ROLES, ), diff --git a/app/protected/modules/zurmo/tests/unit/ZurmoCopyModelUtilTest.php b/app/protected/modules/zurmo/tests/unit/ZurmoCopyModelUtilTest.php new file mode 100644 index 000000000..095470581 --- /dev/null +++ b/app/protected/modules/zurmo/tests/unit/ZurmoCopyModelUtilTest.php @@ -0,0 +1,233 @@ +code = 'EUR'; + $currency->rateToBase = 2; + $saved = $currency->save(); + assert('$saved'); // Not Coding Standard + self::$sally = UserTestHelper::createBasicUser('sally'); + $multiSelectValues = array( + 'Multi 1', + 'Multi 2', + 'Multi 3', + ); + $customFieldData = CustomFieldData::getByName('TestMultiDropDown'); + $customFieldData->serializedData = serialize($multiSelectValues); + $saved = $customFieldData->save(); + assert('$saved'); // Not Coding Standard + + $tagCloudValues = array( + 'Cloud 1', + 'Cloud 2', + 'Cloud 3', + ); + $customFieldData = CustomFieldData::getByName('TestTagCloud'); + $customFieldData->serializedData = serialize($tagCloudValues); + $saved = $customFieldData->save(); + assert('$saved'); // Not Coding Standard + $values = array( + 'Test1', + 'Test2', + 'Test3', + 'Sample', + 'Demo', + ); + $customFieldData = CustomFieldData::getByName('TestDropDown'); + $customFieldData->serializedData = serialize($values); + $saved = $customFieldData->save(); + assert('$saved'); // Not Coding Standard + $a = new Group(); + $a->name = 'AAA'; + $saved = $a->save(); + assert('$saved'); // Not Coding Standard + self::$groupA = $a; + } + + public function setUp() + { + parent::setUp(); + $freeze = false; + if (RedBeanDatabase::isFrozen()) + { + RedBeanDatabase::unfreeze(); + $freeze = true; + } + $this->freeze = $freeze; + Yii::app()->user->userModel = User::getByUsername('super'); + } + + public function teardown() + { + if ($this->freeze) + { + RedBeanDatabase::freeze(); + } + parent::teardown(); + } + + public function testCopy() + { + Yii::app()->user->userModel = User::getByUsername('sally'); + $currencyValue = new CurrencyValue(); + $currencyValue->value = 100; + $currencyValue->currency = Currency::getByCode('EUR'); + $testItem = new ModelToArrayAdapterTestItem(); + $testItem->firstName = 'Bob'; + $testItem->lastName = 'Bobson'; + $testItem->boolean = true; + $testItem->date = '2002-04-03'; + $testItem->dateTime = '2002-04-03 02:00:43'; + $testItem->float = 54.22; + $testItem->integer = 10; + $testItem->phone = '21313213'; + $testItem->string = 'aString'; + $testItem->textArea = 'Some Text Area'; + $testItem->url = 'http://www.asite.com'; + $testItem->primaryEmail->emailAddress = 'bob.bobson@something.com'; + $testItem->primaryAddress->street1 = 'some street'; + + + $testItem->owner = Yii::app()->user->userModel; + $testItem->currencyValue = $currencyValue; + + $customFieldValue = new CustomFieldValue(); + $customFieldValue->value = 'Multi 1'; + $testItem->multiDropDown->values->add($customFieldValue); + + $customFieldValue = new CustomFieldValue(); + $customFieldValue->value = 'Multi 3'; + $testItem->multiDropDown->values->add($customFieldValue); + + $customFieldValue = new CustomFieldValue(); + $customFieldValue->value = 'Cloud 2'; + $testItem->tagCloud->values->add($customFieldValue); + + $customFieldValue = new CustomFieldValue(); + $customFieldValue->value = 'Cloud 3'; + $testItem->tagCloud->values->add($customFieldValue); + + $testItem->dropDown->value = 'Sample'; + + $testItem2 = new ModelToArrayAdapterTestItem2(); + $testItem2->name = 'John'; + $this->assertTrue($testItem2->save()); + + $testItem4 = new ModelToArrayAdapterTestItem4(); + $testItem4->name = 'John'; + $this->assertTrue($testItem4->save()); + + //HAS_MANY and MANY_MANY relationships should be ignored. + $testItem3_1 = new ModelToArrayAdapterTestItem3(); + $testItem3_1->name = 'Kevin'; + $this->assertTrue($testItem3_1->save()); + + $testItem3_2 = new ModelToArrayAdapterTestItem3(); + $testItem3_2->name = 'Jim'; + $this->assertTrue($testItem3_2->save()); + $testItem->hasOne = $testItem2; + $testItem->hasMany->add($testItem3_1); + $testItem->hasMany->add($testItem3_2); + $testItem->hasOneAlso = $testItem4; + + + $this->assertTrue($testItem->save()); + $testItem->addPermissions(self::$groupA, Permission::READ_WRITE_CHANGE_PERMISSIONS_CHANGE_OWNER); + $this->assertTrue($testItem->save()); + $id = $testItem->id; + $testItem->forget(); + unset($testItem); + + //Switch to super and copy the model + Yii::app()->user->userModel = User::getByUsername('super'); + $testItem = ModelToArrayAdapterTestItem::getById($id); + + $copyToItem = new ModelToArrayAdapterTestItem(); + ZurmoCopyModelUtil::copy($testItem, $copyToItem); + + $this->assertEquals('Bob', $copyToItem->firstName); + $this->assertEquals('Bobson', $copyToItem->lastName); + $this->assertEquals(true, $copyToItem->boolean); + $this->assertEquals('2002-04-03', $copyToItem->date); + $this->assertEquals('2002-04-03 02:00:43', $copyToItem->dateTime); + $this->assertEquals(54.22, $copyToItem->float); + $this->assertEquals(10, $copyToItem->integer); + $this->assertEquals('21313213', $copyToItem->phone); + $this->assertEquals('aString', $copyToItem->string); + $this->assertEquals('Some Text Area', $copyToItem->textArea); + $this->assertEquals('http://www.asite.com', $copyToItem->url); + $this->assertEquals('bob.bobson@something.com', $copyToItem->primaryEmail->emailAddress); + $this->assertEquals('some street', $copyToItem->primaryAddress->street1); + $this->assertEquals('Sample', $copyToItem->dropDown->value); + $this->assertEquals(2, $copyToItem->multiDropDown->values->count()); + $this->assertTrue($copyToItem->multiDropDown->values[0] == 'Multi 1' || + $copyToItem->multiDropDown->values[0] == 'Multi 3'); + $this->assertEquals(2, $copyToItem->tagCloud->values->count()); + $this->assertTrue($copyToItem->tagCloud->values[0] == 'Cloud 2' || + $copyToItem->tagCloud->values[0] == 'Cloud 3'); + $this->assertEquals(100, $copyToItem->currencyValue->value); + $this->assertEquals(2, $copyToItem->currencyValue->rateToBase); + $this->assertEquals('EUR', $copyToItem->currencyValue->currency->code); + $this->assertTrue($copyToItem->owner->isSame(self::$sally)); + $this->assertTrue($copyToItem->createdByUser->id < 0); + $this->assertEquals(Yii::app()->user->userModel->id, $copyToItem->modifiedByUser->id); + $this->assertEquals(0, $copyToItem->hasMany->count()); + $this->assertTrue($copyToItem->hasOne->isSame($testItem2)); + $this->assertTrue($copyToItem->hasOneAlso->isSame($testItem4)); + + $explicitReadWriteModelPermissions = ExplicitReadWriteModelPermissionsUtil::makeBySecurableItem($copyToItem); + $permitables = $explicitReadWriteModelPermissions->getReadWritePermitables(); + $this->assertEquals(1, count($permitables)); + $this->assertEquals('AAA', $permitables[self::$groupA->id]->name); + } + } +?> \ No newline at end of file diff --git a/app/protected/modules/zurmo/utils/ExplicitReadWriteModelPermissionsUtil.php b/app/protected/modules/zurmo/utils/ExplicitReadWriteModelPermissionsUtil.php index e1afe4d8b..3101bb86d 100644 --- a/app/protected/modules/zurmo/utils/ExplicitReadWriteModelPermissionsUtil.php +++ b/app/protected/modules/zurmo/utils/ExplicitReadWriteModelPermissionsUtil.php @@ -225,6 +225,8 @@ public static function removeIfExistsFromPostData($postData) * based on what the provided ExplicitReadWriteModelPermissions indicates should be done. * @param SecurableItem $securableItem * @param ExplicitReadWriteModelPermissions $explicitReadWriteModelPermissions + * @return boolean + * @throws NotSupportedException() */ public static function resolveExplicitReadWriteModelPermissions(SecurableItem $securableItem, ExplicitReadWriteModelPermissions $explicitReadWriteModelPermissions) @@ -327,6 +329,35 @@ public static function resolveExplicitReadWriteModelPermissions(SecurableItem $s return true; } + /** + * Given a SecurableItem, add and remove permissions just on the securableItem. Since this method + * is called when the SecurableItem is not being saved and just for display purposes in the user interface. + * @param SecurableItem $securableItem + * @param ExplicitReadWriteModelPermissions $explicitReadWriteModelPermissions + * @return boolean + * @throws NotSupportedException() + */ + public static function resolveExplicitReadWriteModelPermissionsForDisplay(SecurableItem $securableItem, + ExplicitReadWriteModelPermissions $explicitReadWriteModelPermissions) + { + assert('$securableItem->id < 0'); + if ($explicitReadWriteModelPermissions->getReadOnlyPermitablesCount() > 0) + { + foreach ($explicitReadWriteModelPermissions->getReadOnlyPermitables() as $permitable) + { + $securableItem->addPermissions($permitable, Permission::READ); + } + } + if ($explicitReadWriteModelPermissions->getReadWritePermitablesCount() > 0) + { + foreach ($explicitReadWriteModelPermissions->getReadWritePermitables() as $permitable) + { + $securableItem->addPermissions($permitable, Permission::READ_WRITE_CHANGE_PERMISSIONS_CHANGE_OWNER); + } + } + return true; + } + /** * Make an ExplicitReadWriteModelPermissions by SecurableItem. * @param SecurableItem $securableItem diff --git a/app/protected/modules/zurmo/utils/ReadOptimizationModelWhereAndJoinBuilder.php b/app/protected/modules/zurmo/utils/ReadOptimizationModelWhereAndJoinBuilder.php index 38d696690..1b6d6f971 100644 --- a/app/protected/modules/zurmo/utils/ReadOptimizationModelWhereAndJoinBuilder.php +++ b/app/protected/modules/zurmo/utils/ReadOptimizationModelWhereAndJoinBuilder.php @@ -48,7 +48,7 @@ public function __construct(ReadOptimizationDerivedAttributeToDataProviderAdapte } public function resolveJoinsAndBuildWhere($operatorType, $value, & $clausePosition, & $where, - $onTableAliasName = null) + $onTableAliasName = null, $resolveAsSubquery = false) { assert('$operatorType == null'); assert('$value == null'); diff --git a/app/protected/modules/zurmo/utils/ZurmoCopyModelUtil.php b/app/protected/modules/zurmo/utils/ZurmoCopyModelUtil.php new file mode 100644 index 000000000..d8101a5b1 --- /dev/null +++ b/app/protected/modules/zurmo/utils/ZurmoCopyModelUtil.php @@ -0,0 +1,141 @@ +setIsCopied(); + foreach ($model->attributeNames() as $attributeName) + { + $isReadOnly = $model->isAttributeReadOnly($attributeName); + if (!$model->isRelation($attributeName) && !$isReadOnly) + { + static::copyNonRelation($model, $attributeName, $copyToModel); + } + elseif($model->isRelation($attributeName) && !$isReadOnly && + $model->isRelationTypeAHasOneVariant($attributeName)) + { + static::copyRelation($model, $attributeName, $copyToModel); + } + } + static::resolveExplicitPermissions($model, $copyToModel); + } + + protected static function copyNonRelation(RedBeanModel $model, $attributeName, RedBeanModel $copyToModel) + { + $copyToModel->{$attributeName} = $model->{$attributeName}; + } + + protected static function copyRelation(RedBeanModel $model, $attributeName, RedBeanModel $copyToModel) + { + if($model->{$attributeName} instanceof CurrencyValue) + { + $currencyValue = new CurrencyValue(); + $currencyValue->value = $model->{$attributeName}->value; + $currencyValue->rateToBase = $model->{$attributeName}->rateToBase; + $currencyValue->currency = $model->{$attributeName}->currency; + $copyToModel->{$attributeName} = $currencyValue; + } + elseif($model->{$attributeName} instanceof OwnedModel) + { + static::copyOwnedModelRelation($model, $attributeName, $copyToModel); + } + elseif($model->{$attributeName} instanceof CustomField) + { + static::copyNonRelation($model->{$attributeName}, 'value', $copyToModel->{$attributeName}); + } + elseif($model->{$attributeName} instanceof MultipleValuesCustomField) + { + static::copyMultipleValuesCustomFieldRelation($model, $attributeName, $copyToModel); + } + elseif(!$model->isOwnedRelation($attributeName)) + { + static::copyNonRelation($model, $attributeName, $copyToModel); + } + else + { + //Not supported for copy + } + } + + protected static function copyOwnedModelRelation(RedBeanModel $model, $attributeName, RedBeanModel $copyToModel) + { + $relatedModelClassName = get_class($model->{$attributeName}); + $relatedModel = new $relatedModelClassName(); + foreach($relatedModel->getAttributeNames() as $relatedAttributeName) + { + if(!$relatedModel->isRelation($relatedAttributeName) && !$relatedModel->isAttributeReadOnly($relatedAttributeName)) + { + static::copyNonRelation($model->{$attributeName}, $relatedAttributeName, $relatedModel); + } + } + $copyToModel->{$attributeName} = $relatedModel; + } + + protected static function copyMultipleValuesCustomFieldRelation(RedBeanModel $model, $attributeName, RedBeanModel $copyToModel) + { + foreach($model->{$attributeName}->values as $customFieldValue) + { + $newCustomFieldValue = new CustomFieldValue(); + $newCustomFieldValue->value = $customFieldValue->value; + $copyToModel->{$attributeName}->values->add($newCustomFieldValue); + } + } + + protected static function resolveExplicitPermissions(RedBeanModel $model, RedBeanModel $copyToModel) + { + if($model instanceof SecurableItem) + { + $explicitReadWriteModelPermissions = ExplicitReadWriteModelPermissionsUtil::makeBySecurableItem($model); + ExplicitReadWriteModelPermissionsUtil:: + resolveExplicitReadWriteModelPermissionsForDisplay($copyToModel, $explicitReadWriteModelPermissions); + } + } + } +?> \ No newline at end of file diff --git a/app/protected/modules/zurmo/views/ComponentForWizardModelView.php b/app/protected/modules/zurmo/views/ComponentForWizardModelView.php index c736f6eb7..cf0ec6917 100644 --- a/app/protected/modules/zurmo/views/ComponentForWizardModelView.php +++ b/app/protected/modules/zurmo/views/ComponentForWizardModelView.php @@ -131,8 +131,8 @@ public function isUniqueToAPage() */ protected function renderContent() { - $content = $this->renderTitleContent(); - $content .= $this->renderFormContent(); + $content = $this->renderTitleContent(); + $content .= $this->renderFormContent(); $actionElementContent = $this->renderActionElementBar(true); if ($actionElementContent != null) { diff --git a/app/protected/modules/zurmo/views/HeaderView.php b/app/protected/modules/zurmo/views/HeaderView.php index 17c080f1e..0ab7313ab 100644 --- a/app/protected/modules/zurmo/views/HeaderView.php +++ b/app/protected/modules/zurmo/views/HeaderView.php @@ -78,12 +78,18 @@ protected function renderLoginRequiredAjaxResponse() { if (Yii::app()->user->loginRequiredAjaxResponse) { + Yii::app()->clientScript->registerCoreScript('cookie'); Yii::app()->clientScript->registerScript('ajaxLoginRequired', ' jQuery("body").ajaxComplete( function(event, request, options) { if (request.responseText == "' . Yii::app()->user->loginRequiredAjaxResponse . '") { + $.cookie("' . Yii::app()->user->loginRequiredAjaxResponse . 'Cookie", 1, + { + expires : 1, + path: "/" + }); window.location.reload(true); } } diff --git a/app/protected/modules/zurmo/views/LoginPageView.php b/app/protected/modules/zurmo/views/LoginPageView.php index 0915ce0c4..06bf6f1f1 100644 --- a/app/protected/modules/zurmo/views/LoginPageView.php +++ b/app/protected/modules/zurmo/views/LoginPageView.php @@ -42,9 +42,12 @@ public function __construct(CController $controller, CFormModel $formModel, $ext $loginview = new LoginView($controller, $formModel, $extraHeaderContent); $loginview->setCssClasses(array('clearfix', 'background-' . mt_rand(1, 6))); - $gridView = new GridView(2, 1); - $gridView->setView($loginview, 0, 0); - $gridView->setView(new FooterView(), 1, 0); + $flashMessageView = new FlashMessageView($controller); + $gridView = new GridView(3, 1); + $gridView->setView($flashMessageView, 0, 0); + $gridView->setView($loginview, 1, 0); + $gridView->setView(new FooterView(), 2, 0); + $this->registerScripts(); parent::__construct($gridView); } @@ -52,5 +55,50 @@ protected function getSubtitle() { return Zurmo::t('ZurmoModule', 'Sign in'); } + + protected function registerScripts() + { + $this->registerUpdateFlashBarScript(); + $this->registerSessionTimeoutFlashBarScript(); + } + + protected function registerUpdateFlashBarScript() + { + Yii::app()->clientScript->registerScript('handleUpdateFlashBar', ' + function updateFlashBar(data, flashBarId) + { + $("#" + flashBarId).jnotifyAddMessage( + { + text: data.message, + permanent: false, + showIcon: true, + type: data.type + }); + } + '); + } + + protected function registerSessionTimeoutFlashBarScript() + { + Yii::app()->clientScript->registerCoreScript('cookie'); + Yii::app()->clientScript->registerScript('handleSessionTimeoutFlashBar', ' + var notificationBarId = "FlashMessageBar"; + var sessionTimeoutCookieName = "' . Yii::app()->user->loginRequiredAjaxResponse . 'Cookie"; + var sessionTimeoutCookieValue = $.cookie(sessionTimeoutCookieName); + if (sessionTimeoutCookieValue == 1) + { + $.cookie(sessionTimeoutCookieName, null, + { + expires : -1, + path: "/" + }); + var data = {' . // Not Coding Standard + ' "message" : "' . Zurmo::t('ZurmoModule', 'You have been logged out due to inactivity.'). '", + "type" : "error" + }; + updateFlashBar(data, notificationBarId); + } + '); + } } ?> diff --git a/app/themes/default/css/mobile.css b/app/themes/default/css/mobile.css index b34a35476..2fa2d0f58 100644 --- a/app/themes/default/css/mobile.css +++ b/app/themes/default/css/mobile.css @@ -957,20 +957,22 @@ body > div { position: relative; top: 6px; } -.right-side-edit-view-panel { - float: none; - width: 100%; - position: relative; - right: 0; - top: 0; -} -.right-side-edit-view-panel .buffer { - padding-left: 0; -} -.right-side-edit-view-panel .buffer > div { - padding: 0; - background: none; -} +/* + .right-side-edit-view-panel{ + float:none; + width:100%; + position:relative; + right:0; + top:0; + .buffer{ + padding-left:0; + > div{ + padding:0; + background: none; + } + } + } + */ .hasParallelFields > div { width: 100% !important; display: block; @@ -984,8 +986,11 @@ body > div { float: none; padding: 0 10px; } -#ConversationDetailsView .right-side-edit-view-panel { - display: none; +#ConversationDetailsView { + /*.right-side-edit-view-panel{ + display:none; + }*/ + } .model-details-summary { padding-left: 65px; diff --git a/app/themes/default/css/newui.css b/app/themes/default/css/newui.css index f55d0636c..63d9e7763 100644 --- a/app/themes/default/css/newui.css +++ b/app/themes/default/css/newui.css @@ -61,13 +61,23 @@ a.z-button, .default-btn .white-button, .default-btn, .z-label, +.float-bar, .hasDetailsFlyout ul, .stacked-list td div.checkbox-column ~ div, .search-form-tools input[type="submit"], a.search-form-tools input[type="submit"], .default-btn .search-form-tools input[type="submit"], .default-btn a.search-form-tools input[type="submit"], +.left-column, +.right-column, +#modal-edit-form, +#edit-form, +#delete-form, +.right-side-edit-view-panel, .after-form-details-content, +.pager, +.pager ul, +.pager li, .LatestActivitiesListView .activity-item, .LatestActivitiesView .activity-item, #progressBar-links a, @@ -95,6 +105,7 @@ atable.configuration-list td:last-child a, a.multiselect-holder input[type="button"], .default-btn .multiselect-holder input[type="button"], .default-btn a.multiselect-holder input[type="button"], +.has-lang-label input + span, .EmailTestingButton, a.EmailTestingButton, .default-btn .EmailTestingButton, @@ -293,14 +304,29 @@ a.ModalGameNotification a, .workflow-order-module-selector-container { zoom: 1; } -.clearfix { +.clearfix, +#modal-edit-form, +#edit-form, +#delete-form, +.right-side-edit-view-panel, +.pager ul { zoom: 1; } -.clearfix:before { +.clearfix:before, +#modal-edit-form:before, +#edit-form:before, +#delete-form:before, +.right-side-edit-view-panel:before, +.pager ul:before { content: ""; display: table; } -.clearfix:after { +.clearfix:after, +#modal-edit-form:after, +#edit-form:after, +#delete-form:after, +.right-side-edit-view-panel:after, +.pager ul:after { content: ""; display: table; clear: both; @@ -4844,9 +4870,11 @@ section { width: 50%; float: right; } -#LoginView .form form { - padding-top: 0 !important; - padding-bottom: 0 !important; +#LoginView .error { + margin-bottom: 40px !important; +} +#login-form { + padding: 5px 0 5px 15px; background: none !important; border-top: none !important; border-right: none !important; @@ -4858,34 +4886,34 @@ section { box-shadow: none !important; filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); } -#LoginView .form form > div { +#login-form > div { margin-bottom: 15px; } -#LoginView .form form > div.clearfix { +#login-form > div:last-child { + margin-bottom: 0; +} +#login-form > div.clearfix { margin-bottom: 0; } -#LoginView .form form label { +#login-form label { display: inline-block; margin-bottom: 5px; } -#LoginView .form form input[type="password"], -#LoginView .form form input[type="text"] { +#login-form input[type="password"], +#login-form input[type="text"] { background: #fff !important; margin: 0 !important; } -#LoginView .form form input[type="checkbox"] { +#login-form input[type="checkbox"] { float: left; margin-right: 10px !important; margin-top: 1px !important; clear: both; } -#LoginView .form form .errorMessage { +#login-form .errorMessage { font-size: 11px; padding-top: 4px; } -#LoginView .error { - margin-bottom: 40px !important; -} #Login { margin-left: 0; } @@ -6101,6 +6129,8 @@ body > .ui-autocomplete { height: 40px; display: block; z-index: 10; + padding: 0 15px 0 15px; + margin-bottom: 15px; } .float-bar .view-toolbar-container { z-index: 222222; @@ -7246,7 +7276,6 @@ td.empty { padding-left: 15px; } .form form { - padding: 0 15px 15px 15px; border: 1px solid #CCC; -webkit-box-shadow: 0 0 20px 5px rgba(153, 153, 153, 0.12); -moz-box-shadow: 0 0 20px 5px rgba(153, 153, 153, 0.12); @@ -7892,6 +7921,7 @@ div.wide.form label.hasCheckBox { width: 100%; } #search-form { + padding: 0 10px 15px 10px; border: 1px solid #dfdfdf; border-bottom: none; position: relative; @@ -8035,16 +8065,6 @@ div.wide.form label.hasCheckBox { -o-box-shadow: none; -ms-box-shadow: none; box-shadow: none; - zoom: 1; -} -.juiportlet-widget-content .cgrid-view:before { - content: ""; - display: table; -} -.juiportlet-widget-content .cgrid-view:after { - content: ""; - display: table; - clear: both; } .search-view-0 { margin: 15px 0 0 0; @@ -8423,28 +8443,20 @@ div.wide.form label.hasCheckBox { display: block; } /*=Edit + Add Account View*/ -.buffer { - zoom: 1; - padding-left: 30px; -} -.buffer:before { - content: ""; - display: table; -} -.buffer:after { - content: ""; - display: table; - clear: both; -} -.buffer > div { - float: left; - padding: 8px 10px; - background: #F4F4F4; - width: 100%; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; +/* +.buffer{ + //.clearfix(); + //padding-left:30px; + + > div{ + float:left; + padding:8px 10px; + background:#F4F4F4; + width:100%; + .box-sizing(); + } } +*/ .double-column .panel { float: left; width: 100% !important; @@ -8487,46 +8499,27 @@ div.wide.form label.hasCheckBox { display: table; clear: both; } -#modal-edit-form, -#edit-form, -#delete-form { - zoom: 1; - position: relative; - padding-top: 15px; -} -#modal-edit-form:before, -#edit-form:before, -#delete-form:before { - content: ""; - display: table; -} -#modal-edit-form:after, -#edit-form:after, -#delete-form:after { - content: ""; - display: table; - clear: both; -} -#modal-edit-form .panel, -#edit-form .panel, -#delete-form .panel { +.left-column { + padding: 15px 15px 15px 15px; float: left; width: 70%; - display: block; - zoom: 1; } -#modal-edit-form .panel:before, -#edit-form .panel:before, -#delete-form .panel:before { - content: ""; - display: table; +.left-column.full-width { + width: 100%; + float: none; } -#modal-edit-form .panel:after, -#edit-form .panel:after, -#delete-form .panel:after { - content: ""; - display: table; - clear: both; +.left-column.full-width + .right-column { + display: none; +} +.right-column { + float: right; + width: 30%; + padding: 15px 15px 15px 15px; +} +#modal-edit-form, +#edit-form, +#delete-form { + position: relative; } #modal-edit-form .panel table, #edit-form .panel table, @@ -8536,7 +8529,7 @@ div.wide.form label.hasCheckBox { #modal-edit-form h3, #edit-form h3, #delete-form h3 { - margin-bottom: 8px; + margin: 15px 0 0 15px; } #modal-edit-form table, #edit-form table, @@ -8587,8 +8580,8 @@ div.wide.form label.hasCheckBox { #delete-form .hasCheckBox input[type="checkbox"] { margin-bottom: 0 !important; } -#modal-edit-form .panel { - width: 100%; +#modal-edit-form { + padding: 15px 15px 12px 15px; } .more-panels-link { font-size: 11px; @@ -8625,14 +8618,15 @@ div.wide.form label.hasCheckBox { margin-left: 10px; } .right-side-edit-view-panel { - width: 30%; - float: right; + padding: 8px 10px; + background: #F4F4F4; + width: 100%; } .right-side-edit-view-panel p { line-height: 140%; } .right-side-edit-view-panel h3 { - margin-bottom: 8px; + margin: 0 0 10px 0 !important; } .right-side-edit-view-panel label { width: 100%; @@ -8758,6 +8752,7 @@ div.wide.form label.hasCheckBox { border: none; padding: 0; cursor: pointer; + z-index: 10005; } .has-date-select button:hover:before { color: #525252 !important; @@ -9520,15 +9515,6 @@ div.radio-input .hasDropDown { -ms-text-shadow: none; text-shadow: none; } -/* -.back-to-inbox-link{ - .smaller(); - .opacity(50); - &:hover{ - .opacity(100); - } -} -*/ /*=Madlib*/ .mad-lib input { width: auto !important; @@ -9721,9 +9707,6 @@ div.hasHalfs .twoThirds { } /*Upcoming Meeting Pager*/ .pager { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; width: 100%; text-align: center; background: #ffffff url(../images/view-toolbar-gradient.png) left bottom repeat-x; @@ -9732,25 +9715,14 @@ div.hasHalfs .twoThirds { -o-box-shadow: inset 0 1px 0 #dfdfdf; -ms-box-shadow: inset 0 1px 0 #dfdfdf; box-shadow: inset 0 1px 0 #dfdfdf; + overflow: hidden; } .pager ul { + display: block; width: 50%; margin: 0 auto; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; list-style: none; border-left: 1px solid #DFDFDF; - zoom: 1; -} -.pager ul:before { - content: ""; - display: table; -} -.pager ul:after { - content: ""; - display: table; - clear: both; } .pager .endless-list-pager { width: 100%; @@ -9774,9 +9746,6 @@ div.hasHalfs .twoThirds { display: none; } .pager li { - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; float: left; width: 30%; padding: 0; @@ -9930,18 +9899,6 @@ div.hasHalfs .twoThirds { .LatestActivitiesListView form, .LatestActivitiesView form { position: relative; - zoom: 1; -} -.LatestActivitiesListView form:before, -.LatestActivitiesView form:before { - content: ""; - display: table; -} -.LatestActivitiesListView form:after, -.LatestActivitiesView form:after { - content: ""; - display: table; - clear: both; } .LatestActivitiesListView .latest-activity-toolbar, .LatestActivitiesView .latest-activity-toolbar { @@ -11403,12 +11360,6 @@ table.configuration-list td:last-child a .z-label:before { .AdministrativeArea .view-toolbar { margin-top: 0; } -.AdministrativeArea .panel { - width: 100% !important; -} -#EmailTemplateEditAndDetailsView .panel { - width: 70% !important; -} #ModulePermissionsEditAndDetailsView table tr:first-child th { padding-left: 15px; padding-bottom: 10px; @@ -11552,154 +11503,82 @@ table.configuration-list td:last-child a .z-label:before { #JobsCollectionView td.level-1, .SecurityTreeListView td.level-1 { padding-left: 45px !important; -} -#LanguagesCollectionView td.level-1:before, -#CurrenciesCollectionView td.level-1:before, -#JobsCollectionView td.level-1:before, -.SecurityTreeListView td.level-1:before { - content: "∟"; - font-size: 30px; - position: relative; - top: -3px; - font-weight: 100 !important; - line-height: 100% !important; + background: url(../images/elbow.gif) 20px 10px no-repeat; } #LanguagesCollectionView td.level-2, #CurrenciesCollectionView td.level-2, #JobsCollectionView td.level-2, .SecurityTreeListView td.level-2 { padding-left: 75px !important; -} -#LanguagesCollectionView td.level-2:before, -#CurrenciesCollectionView td.level-2:before, -#JobsCollectionView td.level-2:before, -.SecurityTreeListView td.level-2:before { - content: "∟"; - font-size: 30px; - position: relative; - top: -3px; + background: url(../images/elbow.gif) 50px 10px no-repeat; } #LanguagesCollectionView td.level-3, #CurrenciesCollectionView td.level-3, #JobsCollectionView td.level-3, .SecurityTreeListView td.level-3 { padding-left: 105px !important; -} -#LanguagesCollectionView td.level-3:before, -#CurrenciesCollectionView td.level-3:before, -#JobsCollectionView td.level-3:before, -.SecurityTreeListView td.level-3:before { - content: "∟"; - font-size: 30px; - position: relative; - top: -3px; + background: url(../images/elbow.gif) 80px 10px no-repeat; } #LanguagesCollectionView td.level-4, #CurrenciesCollectionView td.level-4, #JobsCollectionView td.level-4, .SecurityTreeListView td.level-4 { padding-left: 135px !important; -} -#LanguagesCollectionView td.level-4:before, -#CurrenciesCollectionView td.level-4:before, -#JobsCollectionView td.level-4:before, -.SecurityTreeListView td.level-4:before { - content: "∟"; - font-size: 30px; - position: relative; - top: -3px; + background: url(../images/elbow.gif) 110px 10px no-repeat; } #LanguagesCollectionView td.level-5, #CurrenciesCollectionView td.level-5, #JobsCollectionView td.level-5, .SecurityTreeListView td.level-5 { padding-left: 165px !important; -} -#LanguagesCollectionView td.level-5:before, -#CurrenciesCollectionView td.level-5:before, -#JobsCollectionView td.level-5:before, -.SecurityTreeListView td.level-5:before { - content: "∟"; - font-size: 30px; - position: relative; - top: -3px; + background: url(../images/elbow.gif) 140px 10px no-repeat; } #LanguagesCollectionView td.level-6, #CurrenciesCollectionView td.level-6, #JobsCollectionView td.level-6, .SecurityTreeListView td.level-6 { padding-left: 195px !important; -} -#LanguagesCollectionView td.level-6:before, -#CurrenciesCollectionView td.level-6:before, -#JobsCollectionView td.level-6:before, -.SecurityTreeListView td.level-6:before { - content: "∟"; - font-size: 30px; - position: absolute; - left: 165px; - top: -1px; + background: url(../images/elbow.gif) 170px 10px no-repeat; } #LanguagesCollectionView td.level-7, #CurrenciesCollectionView td.level-7, #JobsCollectionView td.level-7, .SecurityTreeListView td.level-7 { padding-left: 225px !important; -} -#LanguagesCollectionView td.level-7:before, -#CurrenciesCollectionView td.level-7:before, -#JobsCollectionView td.level-7:before, -.SecurityTreeListView td.level-7:before { - content: "∟"; - font-size: 30px; - position: relative; - top: -3px; + background: url(../images/elbow.gif) 200px 10px no-repeat; } #LanguagesCollectionView td.level-8, #CurrenciesCollectionView td.level-8, #JobsCollectionView td.level-8, .SecurityTreeListView td.level-8 { padding-left: 255px !important; -} -#LanguagesCollectionView td.level-8:before, -#CurrenciesCollectionView td.level-8:before, -#JobsCollectionView td.level-8:before, -.SecurityTreeListView td.level-8:before { - content: "∟"; - font-size: 30px; - position: absolute; - left: 225px; - top: -1px; + background: url(../images/elbow.gif) 230px 10px no-repeat; } #LanguagesCollectionView td.level-9, #CurrenciesCollectionView td.level-9, #JobsCollectionView td.level-9, .SecurityTreeListView td.level-9 { padding-left: 285px !important; -} -#LanguagesCollectionView td.level-9:before, -#CurrenciesCollectionView td.level-9:before, -#JobsCollectionView td.level-9:before, -.SecurityTreeListView td.level-9:before { - content: "∟"; - font-size: 30px; - position: relative; - top: -3px; + background: url(../images/elbow.gif) 260px 10px no-repeat; } #LanguagesCollectionView td.level-10, #CurrenciesCollectionView td.level-10, #JobsCollectionView td.level-10, .SecurityTreeListView td.level-10 { padding-left: 315px !important; -} -#LanguagesCollectionView td.level-10:before, -#CurrenciesCollectionView td.level-10:before, -#JobsCollectionView td.level-10:before, -.SecurityTreeListView td.level-10:before { - content: "∟"; - font-size: 30px; - position: relative; - top: -3px; + background: url(../images/elbow.gif) 290px 10px no-repeat; +} +#ModalView .SecurityTreeListView td.level-1, +#ModalView .SecurityTreeListView td.level-2, +#ModalView .SecurityTreeListView td.level-3, +#ModalView .SecurityTreeListView td.level-4, +#ModalView .SecurityTreeListView td.level-5, +#ModalView .SecurityTreeListView td.level-6, +#ModalView .SecurityTreeListView td.level-7, +#ModalView .SecurityTreeListView td.level-8, +#ModalView .SecurityTreeListView td.level-9, +#ModalView .SecurityTreeListView td.level-10 { + background-position-y: 3px; } /*Roles*/ #RolesTreeListView .z-action-link { @@ -11908,8 +11787,8 @@ table.configuration-list td:last-child a .z-label:before { left: 1px; line-height: 24px; top: 1px; - width: 80px; - text-align: center; + min-width: 80px; + text-align: left; border-right: 1px solid #cccccc; -webkit-text-shadow: rgba(255, 255, 255, 0.8) 0px 1px; -moz-text-shadow: rgba(255, 255, 255, 0.8) 0px 1px; @@ -11922,6 +11801,7 @@ table.configuration-list td:last-child a .z-label:before { -ms-border-radius: 1px 0 0 1px; -o-border-radius: 1px 0 0 1px; border-radius: 1px 0 0 1px; + padding: 0 10px; } .has-lang-label .errorMessage { margin-bottom: 15px; @@ -11934,7 +11814,6 @@ table.configuration-list td:last-child a .z-label:before { margin-bottom: 20px; } #UsersPageView .panel { - width: 100% !important; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; @@ -12062,18 +11941,19 @@ table.configuration-list td:last-child a .z-label:before { float: right; } /*Import window*/ +.AppContent.ImportWizardView #edit-form h3 { + margin-top: 0; + margin-left: 0; +} .AppContent.ImportWizardView #edit-form table { width: 100%; } .AppContent.ImportWizardView #edit-form table td { padding-left: 0; } -.AppContent.ImportWizardView h3 { - margin-bottom: 15px; -} .AppContent.ImportWizardView .right-side-edit-view-panel { - width: 60% !important; - float: none !important; + background: none; + padding: 0; } .AppContent.ImportWizardView #addExtraColumnButton { -moz-box-sizing: border-box; @@ -12139,11 +12019,6 @@ table.configuration-list td:last-child a .z-label:before { margin: 5px 0 0 10px !important; } /*= Step 3*/ -#ImportWizardSetModelPermissionsView .right-side-edit-view-panel { - position: relative !important; - top: 0 !important; - right: 0 !important; -} /*=Step 4,Mapping view*/ #ImportWizardMappingView > .wrapper { padding-bottom: 10px; @@ -12157,6 +12032,10 @@ table.configuration-list td:last-child a .z-label:before { #ImportWizardMappingView .required-fields { margin: 5px 0 0 15px; } +#ImportWizardMappingView table { + border-left: 1px solid #DFDFDF; + border-right: 1px solid #DFDFDF; +} #ImportWizardMappingView table tr:first-child th { color: #545454; text-align: left; @@ -12181,12 +12060,8 @@ table.configuration-list td:last-child a .z-label:before { #ImportWizardMappingView tr td:last-child { padding-right: 15px; } -#ImportWizardMappingView table tr:last-child td { - border-bottom: none; - padding-bottom: 0; -} -#ImportWizardMappingView .view-toolbar-container { - padding-bottom: 15px; +#ImportWizardMappingView .mapping-rules table { + border: none; } #ImportWizardMappingView .mapping-rules table, #ImportWizardMappingView .mapping-rules td, @@ -12251,13 +12126,17 @@ table.configuration-list td:last-child a .z-label:before { .process-container-view { padding: 15px 15px 0 15px; } +#sequenceProcess { + padding: 15px 0 0 0; +} +.process-message { + margin-left: 15px; +} #ImportSequentialProcessContainerView > div { float: left; width: 100%; - padding-bottom: 15px; } #ImportSequentialProcessContainerView #edit-form { - padding: 0 0 15px 0 !important; border: 0 !important; background: none !important; -webkit-box-shadow: none; @@ -12269,8 +12148,11 @@ table.configuration-list td:last-child a .z-label:before { #ImportSequentialProcessContainerView #edit-form table { width: 100%; } -#ImportSequentialProcessContainerView #edit-form table td { - padding-left: 0; +#ImportSequentialProcessContainerView td { + padding: 0; +} +#ImportSequentialProcessContainerView td h3 { + margin: 0 !important; } #ImportSequentialProcessContainerView h3, #ImportSequentialProcessContainerView h3 + span { @@ -12322,6 +12204,9 @@ table.configuration-list td:last-child a .z-label:before { color: #666; font-weight: 400 !important; } +#ImportWizardCreateUpdateModelsCompleteView h3 { + margin: 0 0 10px 0 !important; +} .import-summary { margin: 0 0 15px 15px; line-height: 150%; @@ -12555,7 +12440,7 @@ div.form select.error { } div.form .errorSummary { position: relative; - margin: 15px; + margin: 0 0 15px 0; padding: 10px; border-radius: 5px !important; border: 1px solid #cc0000; @@ -12956,14 +12841,14 @@ div.wide.form .errorMessage { -webkit-box-sizing: border-box; box-sizing: border-box; cursor: pointer; + position: relative; } .ui-datepicker .ui-datepicker-next span { visibility: hidden; } -.ui-datepicker .ui-datepicker-next:after { +.ui-datepicker .ui-datepicker-next:before { content: "▶"; - position: relative; - right: 10px; + margin-left: 10px; } .ui-datepicker .ui-datepicker-next :hover { cursor: pointer !important; @@ -15280,6 +15165,7 @@ a.close-ModalGameNotification.simple-link { -ms-box-shadow: none; box-shadow: none; float: none; + margin-bottom: 0; } #UserDetailsView .details-table { zoom: 1; @@ -15322,6 +15208,9 @@ a.close-ModalGameNotification.simple-link { .gravatar-container + .panel { float: left; } +.gravatar-container + .panel + .panel { + clear: right; +} #UserChangeAvatarView { zoom: 1; } @@ -15570,11 +15459,6 @@ a.dashboard-link .z-label { #ConversationDetailsAndRelationsView .panel > table { border-bottom: none; } -.single-coloumn-details-view .right-side-edit-view-panel, -#ConversationDetailsView .right-side-edit-view-panel, -#ConversationDetailsAndRelationsView .right-side-edit-view-panel { - margin-right: 15px; -} .single-coloumn-details-view .details-table, #ConversationDetailsView .details-table, #ConversationDetailsAndRelationsView .details-table { @@ -15594,22 +15478,22 @@ a.dashboard-link .z-label { clear: both; } /*Sidebar*/ -.thred-details { - margin: 0 0 0 0 !important; +.thread-details { + margin: 0 0 10px 0 !important; width: 100%; } -.thred-details td + th { +.thread-details td + th { padding-left: 0 !important; } -.thred-details th, -.thred-details td { +.thread-details th, +.thread-details td { text-align: left; padding: 5px 0; } -.thred-details th { +.thread-details th { color: #545454; } -.thred-details .attachments { +.thread-details .attachments { margin: 0; font-weight: normal; } @@ -15662,7 +15546,7 @@ a.dashboard-link .z-label { left: 15px; } .conversationStatusChangeArea { - margin: 15px 0; + margin: 0 0 15px 0; padding: 0; } .conversationStatusChangeArea > span { @@ -15809,7 +15693,7 @@ a.dashboard-link .z-label { } #CommentList, .CommentList { - margin-left: 130px; + margin-left: 115px; } #CommentList .comment, .CommentList .comment { @@ -15856,8 +15740,7 @@ a.dashboard-link .z-label { } .model-details-summary { font-size: 12px !important; - padding-left: 130px; - padding-top: 15px; + padding-left: 115px; } .model-details-summary .gravatar { margin-left: -115px; @@ -15883,8 +15766,6 @@ a.dashboard-link .z-label { #ModelDetailsSummaryView, #CommentInlineEditForModelView, #CommentsForRelatedModelView { - width: 70%; - float: left; max-width: 600px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; @@ -15911,13 +15792,13 @@ a.dashboard-link .z-label { } #CommentInlineEditForModelView { margin-top: 0; - padding-left: 120px; + padding-left: 115px; } #CommentInlineEditForModelView td { - padding: 0 0 0 10px !important; + padding: 0 0 0 0 !important; } #CommentInlineEditForModelView h2 { - margin: 0 0 13px 10px; + margin: 0 0 0 0; } #CommentInlineEditForModelView .wide.form { padding: 0; @@ -16098,9 +15979,17 @@ a.user-link { #AllSocialItemsForPortletView .comment-content { padding-right: 15px; } +#ConversationsPageView #comment-inline-edit-form .left-column, +#ConversationsPageView #social-item-inline-edit-form .left-column { + padding: 0; +} +#ConversationsPageView #comment-inline-edit-form .form-toolbar, +#ConversationsPageView #social-item-inline-edit-form .form-toolbar { + padding: 0; +} #comment-inline-edit-form, #social-item-inline-edit-form { - padding-top: 15px; + padding-bottom: 15px; border: none; border-bottom: 1px solid #ccc; background: none !important; @@ -16125,8 +16014,8 @@ a.user-link { #social-item-inline-edit-form .form-toolbar { text-align: right; border-top: none; - padding-top: 0; - margin-top: 2px; + padding: 0 15px; + margin-top: 0; } #comment-inline-edit-form .form-toolbar a, #social-item-inline-edit-form .form-toolbar a { @@ -16494,17 +16383,21 @@ a.user-link { #ModuleForReportWizardView table td { padding-left: 0; } -#GeneralDataForReportWizardView .panel { - width: 70%; - float: left; -} -#GeneralDataForReportWizardView .right-side-edit-view-panel { - width: 30%; - float: right; - position: relative; - top: -2px; - right: 0; +/* +#GeneralDataForReportWizardView{ + .panel{ + width: 70%; + float: left; + } + .right-side-edit-view-panel{ + width: 30%; + float: right; + position: relative; + top:-2px; + right:0; + } } +*/ .hasTree { width: 25%; float: left; @@ -17519,8 +17412,8 @@ a.user-link { position: relative; top: 0; } -.details-table .email-template-combined-content { - margin: 15px; +.email-template-combined-content { + padding: 0 15px; } .tabs-nav { border-bottom: 1px solid #dfdfdf; @@ -17830,4 +17723,13 @@ a.user-link { .juiportlet-widget { margin-right: 0 !important; } + .right-column, + .left-column { + width: 100%; + } + .right-side-edit-view-panel { + padding: 0; + padding: 0 0 0 0; + background: none; + } } diff --git a/app/themes/default/images/elbow.gif b/app/themes/default/images/elbow.gif new file mode 100644 index 000000000..2360ad22d Binary files /dev/null and b/app/themes/default/images/elbow.gif differ diff --git a/app/themes/default/less/configuration.less b/app/themes/default/less/configuration.less index 976a57f32..a385db57d 100644 --- a/app/themes/default/less/configuration.less +++ b/app/themes/default/less/configuration.less @@ -240,15 +240,6 @@ table.configuration-list{ .view-toolbar{ margin-top:0; } - .panel{ - width:100% !important; - } -} - -#EmailTemplateEditAndDetailsView{ - .panel{ - width: 70% !important; - } } #ModulePermissionsEditAndDetailsView{ @@ -342,100 +333,54 @@ table.configuration-list{ td.level-0{ padding-left:10px !important;} td.level-1{ padding-left:45px !important; - &:before{ - content: "∟"; - font-size: 30px; - position: relative; - top:-3px; - font-weight:100 !important; - line-height:100% !important; - } + background: url(../images/elbow.gif) 20px 10px no-repeat; } td.level-2{ padding-left:75px !important; - &:before{ - content: "∟"; - font-size: 30px; - position: relative; - top:-3px; - } + background: url(../images/elbow.gif) 50px 10px no-repeat; } td.level-3{ padding-left:105px !important; - &:before{ - content: "∟"; - font-size: 30px; - position: relative; - top:-3px; - } + background: url(../images/elbow.gif) 80px 10px no-repeat; } td.level-4{ padding-left:135px !important; - &:before{ - content: "∟"; - font-size: 30px; - position: relative; - top:-3px; - } + background: url(../images/elbow.gif) 110px 10px no-repeat; } td.level-5{ padding-left:165px !important; - &:before{ - content: "∟"; - font-size: 30px; - position: relative; - top:-3px; - } + background: url(../images/elbow.gif) 140px 10px no-repeat; } td.level-6{ padding-left:195px !important; - &:before{ - content: "∟"; - font-size: 30px; - position: absolute; - left: 165px; - top:-1px; - } + background: url(../images/elbow.gif) 170px 10px no-repeat; } td.level-7{ padding-left:225px !important; - &:before{ - content: "∟"; - font-size: 30px; - position: relative; - top:-3px; - } + background: url(../images/elbow.gif) 200px 10px no-repeat; } td.level-8{ padding-left:255px !important; - &:before{ - content: "∟"; - font-size: 30px; - position: absolute; - left: 225px; - top:-1px; - } + background: url(../images/elbow.gif) 230px 10px no-repeat; } td.level-9{ padding-left:285px !important; - &:before{ - content: "∟"; - font-size: 30px; - position: relative; - top:-3px; - } + background: url(../images/elbow.gif) 260px 10px no-repeat; } td.level-10{ padding-left:315px !important; - &:before{ - content: "∟"; - font-size: 30px; - position: relative; - top:-3px; - } + background: url(../images/elbow.gif) 290px 10px no-repeat; } } +#ModalView{ + .SecurityTreeListView{ + td.level-1, td.level-2, td.level-3, td.level-4, td.level-5, td.level-6, + td.level-7, td.level-8, td.level-9, td.level-10{ + background-position-y:3px; + } + } +} /*Roles*/ #RolesTreeListView{ .z-action-link{ @@ -656,12 +601,14 @@ table.configuration-list{ left:1px; line-height:24px; top:1px; - width:80px; - text-align:center; + min-width:80px; + text-align:left; border-right:1px solid #cccccc; .t-shadow( rgba(255, 255, 255, 0.8) 0px 1px); .smaller(); .radius(1px 0 0 1px); + padding: 0 10px; + ++.border-box; } .errorMessage{ margin-bottom: 15px; @@ -681,17 +628,14 @@ table.configuration-list{ //padding-right:0; } .panel{ - width:100% !important; .box-sizing(); table{ margin-right:15px; .box-sizing(); } } - #edit-form{ - //padding-right:30px; - } } + #UserCreateView{ .panel{ width:70% !important; @@ -824,6 +768,11 @@ table.configuration-list{ .AppContent.ImportWizardView{ //padding-right:0; #edit-form{ + h3{ + margin-top: 0; + margin-left: 0; + //margin-bottom:15px; + } table{ width:100%; td{ @@ -831,13 +780,11 @@ table.configuration-list{ } } } - h3{ - margin-bottom:15px; - } - .right-side-edit-view-panel { - width: 60% !important; - float: none !important; - } + .right-side-edit-view-panel{ + background: none; + padding: 0; + } + #addExtraColumnButton{ .zButton; margin:0; @@ -864,13 +811,7 @@ table.configuration-list{ } /*= Step 3*/ -#ImportWizardSetModelPermissionsView{ - .right-side-edit-view-panel{ - position:relative !important; - top:0 !important; - right:0 !important; - } -} + /*=Step 4,Mapping view*/ #ImportWizardMappingView{ @@ -886,17 +827,21 @@ table.configuration-list{ .required-fields{ margin:5px 0 0 15px; } - table tr:first-child{ - th{ - color:#545454; - text-align:left; - font-weight: bold !important; - height: 35px; - line-height: 35px; - background: url(../images/table-items-header.png) left top repeat-x; - padding: 0 0 0 15px !important; - border-top:1px solid #DFDFDF; - border-bottom:1px solid #DFDFDF; + table{ + border-left:1px solid #DFDFDF; + border-right:1px solid #DFDFDF; + tr:first-child{ + th{ + color:#545454; + text-align:left; + font-weight: bold !important; + height: 35px; + line-height: 35px; + background: url(../images/table-items-header.png) left top repeat-x; + padding: 0 0 0 15px !important; + border-top:1px solid #DFDFDF; + border-bottom:1px solid #DFDFDF; + } } } td{ @@ -914,14 +859,17 @@ table.configuration-list{ } table tr:last-child{ td{ - border-bottom: none; - padding-bottom:0; + //border-bottom: none; + //padding-bottom:0; } } .view-toolbar-container{ - padding-bottom:15px; + //padding-bottom:15px; } .mapping-rules{ + table{ + border: none; + } table, td, th, input, label{ margin:0 !important; } @@ -999,25 +947,33 @@ table.configuration-list{ padding:15px 15px 0 15px; } +#sequenceProcess{ + padding:15px 0 0 0; +} + +.process-message{ + margin-left: 15px; +} + #ImportSequentialProcessContainerView{ - //padding-right:0; > div{ float: left; width: 100%; - padding-bottom: 15px; } #edit-form{ - padding:0 0 15px 0 !important; border:0 !important; background:none !important; .b-shadow(none); table{ width:100%; - td{ - padding-left:0; - } } } + td{ + padding: 0; + h3{ + margin: 0 !important; + } + } h3, h3 + span{ margin-bottom:15px; display:block; @@ -1059,6 +1015,9 @@ table.configuration-list{ color: #666; font-weight: 400 !important; } + h3{ + margin: 0 0 10px 0 !important; + } } .import-summary{ diff --git a/app/themes/default/less/datepicker.less b/app/themes/default/less/datepicker.less index 4cea29f78..c161bc124 100644 --- a/app/themes/default/less/datepicker.less +++ b/app/themes/default/less/datepicker.less @@ -69,13 +69,13 @@ text-align:right; .box-sizing(); cursor:pointer; + position: relative; span{ visibility:hidden; } - &:after{ + &:before{ content:"▶"; - position:relative; - right:10px; + margin-left: 10px; } :hover{ cursor:pointer !important; diff --git a/app/themes/default/less/email-templates.less b/app/themes/default/less/email-templates.less index 833435053..b6a842c84 100644 --- a/app/themes/default/less/email-templates.less +++ b/app/themes/default/less/email-templates.less @@ -70,12 +70,11 @@ } } -.details-table .email-template-combined-content{ - margin: 15px; +.email-template-combined-content{ + padding: 0 15px; } .tabs-nav{ - //margin-bottom: 10px; border-bottom: 1px solid #dfdfdf; a{ display: inline-block; diff --git a/app/themes/default/less/form.less b/app/themes/default/less/form.less index b1a41f461..99a1562b8 100644 --- a/app/themes/default/less/form.less +++ b/app/themes/default/less/form.less @@ -87,7 +87,7 @@ div.form select.success { div.form .errorSummary { position: relative; - margin:15px; + margin:0 0 15px 0; padding:10px; border-radius:5px !important; border:1px solid #cc0000; diff --git a/app/themes/default/less/gamification.less b/app/themes/default/less/gamification.less index f7c308382..c83cae274 100644 --- a/app/themes/default/less/gamification.less +++ b/app/themes/default/less/gamification.less @@ -654,6 +654,7 @@ a.close-ModalGameNotification.simple-link{ border-bottom: 1px solid #fff; .b-shadow(none); float: none; + margin-bottom: 0; } } @@ -690,6 +691,9 @@ a.close-ModalGameNotification.simple-link{ } + .panel{ float: left; + + .panel{ + clear: right; + } } } diff --git a/app/themes/default/less/media-queries.less b/app/themes/default/less/media-queries.less index f1afb2e45..7b43fb202 100644 --- a/app/themes/default/less/media-queries.less +++ b/app/themes/default/less/media-queries.less @@ -97,4 +97,19 @@ .juiportlet-widget{ margin-right:0 !important; } + + //edit view + .right-column, + .left-column{ + //float: none; + width: 100%; + //padding-left: 0; + } + + .right-side-edit-view-panel{ + padding: 0; + padding: 0 0 0 0; + background: none; + } + } \ No newline at end of file diff --git a/app/themes/default/less/mobile.less b/app/themes/default/less/mobile.less index fd2f3155d..a73fecd50 100644 --- a/app/themes/default/less/mobile.less +++ b/app/themes/default/less/mobile.less @@ -634,6 +634,7 @@ } } + /* .right-side-edit-view-panel{ float:none; width:100%; @@ -648,6 +649,7 @@ } } } + */ .hasParallelFields > div{ width: 100% !important; @@ -666,9 +668,9 @@ } #ConversationDetailsView{ - .right-side-edit-view-panel{ + /*.right-side-edit-view-panel{ display:none; - } + }*/ } .model-details-summary { diff --git a/app/themes/default/less/newui.less b/app/themes/default/less/newui.less index 90496942f..6ca73b17a 100644 --- a/app/themes/default/less/newui.less +++ b/app/themes/default/less/newui.less @@ -142,46 +142,49 @@ footer, header, hgroup, menu, nav, section { .form{ width:50%; float:right; - form{ - padding-top:0 !important; - padding-bottom:0 !important; - background:none !important; - border-top:none !important; - border-right:none !important; - border-bottom:none !important; - .b-shadow(~"none !important"); - .reset-filter(); - > div{ - margin-bottom:15px; - } - > div.clearfix{ - margin-bottom:0; - } - label{ - display:inline-block; - margin-bottom:5px; - } - input[type="password"], input[type="text"]{ - background:#fff !important; - margin:0 !important; - } - input[type="checkbox"]{ - float:left; - margin-right:10px !important; - margin-top:1px !important; - clear:both; - } - .errorMessage{ - font-size:11px; - padding-top:4px - } - } } .error{ margin-bottom: 40px !important; } } +#login-form{ + padding:5px 0 5px 15px; + background:none !important; + border-top:none !important; + border-right:none !important; + border-bottom:none !important; + .b-shadow(~"none !important"); + .reset-filter(); + > div{ + margin-bottom:15px; + } + > div:last-child{ + margin-bottom: 0; + } + > div.clearfix{ + margin-bottom:0; + } + label{ + display:inline-block; + margin-bottom:5px; + } + input[type="password"], input[type="text"]{ + background:#fff !important; + margin:0 !important; + } + input[type="checkbox"]{ + float:left; + margin-right:10px !important; + margin-top:1px !important; + clear:both; + } + .errorMessage{ + font-size:11px; + padding-top:4px + } +} + #Login{ margin-left:0; } @@ -1260,6 +1263,9 @@ body > .ui-autocomplete{ height: 40px; display: block; z-index: 10; + ++.border-box; + padding: 0 15px 0 15px; + margin-bottom: 15px; .view-toolbar-container{ z-index:222222; position:fixed !important; @@ -2019,7 +2025,7 @@ td.empty{ } } form{ - padding:0 15px 15px 15px; + //padding:0 15px 15px 15px; border:1px solid #CCC; .b-shadow(0 0 20px 5px rgba(153, 153, 153, 0.12)); /*999*/ background: #ffffff; @@ -2548,6 +2554,7 @@ div.wide.form{ } #search-form{ + padding:0 10px 15px 10px; border:1px solid #dfdfdf; border-bottom: none; position: relative; @@ -2602,7 +2609,7 @@ div.wide.form{ .juiportlet-widget-content .cgrid-view{ width: 100%; .b-shadow(none); - .clearfix(); + //.clearfix(); } .search-view-0{ @@ -2654,8 +2661,6 @@ div.wide.form{ } } - - .search-form-tools{ position: absolute; z-index:100; @@ -2972,9 +2977,10 @@ div.wide.form{ } /*=Edit + Add Account View*/ +/* .buffer{ - .clearfix(); - padding-left:30px; + //.clearfix(); + //padding-left:30px; > div{ float:left; @@ -2984,7 +2990,7 @@ div.wide.form{ .box-sizing(); } } - +*/ .double-column{ .panel{ float:left; @@ -3023,23 +3029,39 @@ div.wide.form{ .clearfix(); } +.left-column{ + padding: 15px 15px 15px 15px; + float: left; + width: 70%; + ++.border-box; + &.full-width{ + width: 100%; + float:none; + +.right-column{ + display: none; + } + } +} +.right-column{ + float: right; + width: 30%; + padding:15px 15px 15px 15px; + ++.border-box; +} + #modal-edit-form, #edit-form, #delete-form{ - .clearfix(); + ++.clearfix; + ++.border-box; position: relative; - padding-top:15px; .panel{ - float:left; - width:70%; - display:block; - .clearfix(); table{ width:100% !important; } } h3{ - margin-bottom:8px; + margin:15px 0 0 15px; } table{ border-bottom:none; @@ -3074,12 +3096,12 @@ div.wide.form{ } } -#modal-edit-form .panel{ - width: 100%; +#modal-edit-form{ + padding: 15px 15px 12px 15px; } .more-panels-link{ - font-size:11px; + .smaller(); } .ui-overlay-block{ @@ -3119,18 +3141,16 @@ div.wide.form{ } .right-side-edit-view-panel{ - width:30%; - float:right; - //position:absolute; - //right:15px; - //top:15px; + padding: 8px 10px; + background: #F4F4F4; + width: 100%; + ++.border-box; + ++.clearfix; p{ line-height: 140%; } h3{ - margin-bottom:8px; - } - .buffer > div{ + margin:0 0 10px 0 !important; } label{ width: 100%; @@ -3256,6 +3276,7 @@ div.wide.form{ border:none; padding:0; cursor:pointer; + z-index: 10005; &:hover{ &:before{ color:#525252 !important; @@ -3368,17 +3389,11 @@ div.wide.form{ } p{ width:100%; - a{ - //++.themeColor-important; - } } .panelTitle{ padding-top:0; padding-left:10px; } - a{ - //++.themeColor; - } .map-link{ display: inline-block; margin-left:4px; @@ -3849,10 +3864,8 @@ div.radio-input{ margin-left: 10px; width:13px; padding: 1px; - //height: 13px; text-align: center; line-height: 1; - //vertical-align: middle; color: #666; border:1px solid #fff; .b-shadow(inset 0 0 0 1px #ddd); @@ -3891,16 +3904,6 @@ div.radio-input{ } } -/* -.back-to-inbox-link{ - .smaller(); - .opacity(50); - &:hover{ - .opacity(100); - } -} -*/ - /*=Madlib*/ .mad-lib{ input{ @@ -4052,18 +4055,20 @@ div.hasHalfs{ /*Upcoming Meeting Pager*/ .pager{ - .box-sizing(); + ++.border-box; width:100%; text-align:center; background: #fff url(../images/view-toolbar-gradient.png) left bottom repeat-x; .b-shadow(inset 0 1px 0 #DFDFDF ); + overflow: hidden; ul{ + display: block; width:50%; margin:0 auto; - .box-sizing(); + ++.border-box; list-style: none; border-left: 1px solid #DFDFDF; - .clearfix(); + ++.clearfix; } .endless-list-pager{ width:100%; @@ -4084,7 +4089,7 @@ div.hasHalfs{ } } li{ - .box-sizing(); + ++.border-box; float:left; width:30%; padding:0; @@ -4102,9 +4107,6 @@ div.hasHalfs{ .b-shadow(~"inset 0 5px 10px 0px rgba(153, 153, 153, 0.45)"); } } - > a:hover{ - ++.themeColor2-important; - } } .refresh{ width:0; @@ -4230,7 +4232,6 @@ div.hasHalfs{ .LatestActivitiesView{ form{ position: relative; - .clearfix(); } .latest-activity-toolbar{ border-bottom:1px solid #DFDFDF; diff --git a/app/themes/default/less/reports.less b/app/themes/default/less/reports.less index 1017ea715..20a62574a 100644 --- a/app/themes/default/less/reports.less +++ b/app/themes/default/less/reports.less @@ -31,6 +31,10 @@ // feasible for technical reasons, the Appropriate Legal Notices must display the words // "Copyright Zurmo Inc. 2013. All rights reserved". +.ComponentForWizardModelView{ + //padding: 15px; +} + #ReportsSearchView{ .search-view-1{ table{ @@ -105,7 +109,7 @@ } } } - +/* #GeneralDataForReportWizardView{ .panel{ width: 70%; @@ -119,6 +123,7 @@ right:0; } } +*/ .hasTree{ width:25%; diff --git a/app/themes/default/less/thread-view.less b/app/themes/default/less/thread-view.less index 45fac2e89..481086ef5 100644 --- a/app/themes/default/less/thread-view.less +++ b/app/themes/default/less/thread-view.less @@ -50,6 +50,10 @@ textarea{ line-height: 130%; } + .right-side-edit-view-panel{ + //display: inline-block; + //float: none; + } } .single-coloumn-details-view, @@ -76,7 +80,7 @@ } } .right-side-edit-view-panel{ - margin-right:15px; + //margin-right:15px; } .details-table{ .clearfix(); @@ -84,51 +88,51 @@ } /*Sidebar*/ -.thred-info{ +.thread-info{ h3{ //border-top:1px solid #fff; //padding-top:10px; } } -.thred-details{ - margin:0 0 0 0 !important; +.thread-details{ + margin:0 0 10px 0 !important; width: 100%; td + th{ - padding-left:0 !important; + padding-left:0 !important; } th, td{ - text-align: left; - padding:5px 0; + text-align: left; + padding:5px 0; } th{ - color: #545454; + color: #545454; } td{ } .attachments{ - margin: 0; - font-weight: normal; + margin: 0; + font-weight: normal; } } .conversation-related-Account{ .t-shadow(0 1px #fff); > div{ - position: relative; - &:before{ - .symbly(20px); - content:"P"; - font-weight: normal !important; - position: absolute; - top:-3px; - line-height: 1; - } + position: relative; + &:before{ + .symbly(20px); + content:"P"; + font-weight: normal !important; + position: absolute; + top:-3px; + line-height: 1; + } } a{ - position: relative; - left: 15px; + position: relative; + left: 15px; } } @@ -136,38 +140,38 @@ .conversation-related-Opportunity{ .t-shadow(0 1px #fff); > div{ - position: relative; - &:before{ - .symbly(21px); - content:"9"; - font-weight: normal !important; - position: absolute; - top:-2px; - line-height: 1; - } + position: relative; + &:before{ + .symbly(21px); + content:"9"; + font-weight: normal !important; + position: absolute; + top:-2px; + line-height: 1; + } } a{ - position: relative; - left: 15px; + position: relative; + left: 15px; } } .conversationStatusChangeArea{ - margin: 15px 0; + margin:0 0 15px 0; padding:0; > span{ - float: left; - line-height: 1; - margin:10px 10px 0 0; - padding: 0 0; - font-weight: bold; + float: left; + line-height: 1; + margin:10px 10px 0 0; + padding: 0 0; + font-weight: bold; } label{ - display: inline !important; - margin-right: 10px; - input{ - margin-right: 5px; - } + display: inline !important; + margin-right: 10px; + input{ + margin-right: 5px; + } } } @@ -222,24 +226,24 @@ .opacity(100); } &:first-child input:checked + label{ - @topColor: #97c43d; + @topColor: #97c43d; @bottomColor: #6fa82d; - #gradient > .vertical(@topColor, @bottomColor ) !important; //green - border:1px solid @topColor; + #gradient > .vertical(@topColor, @bottomColor ) !important; //green + border:1px solid @topColor; } &:last-child input:checked + label{ - @topColor: #c43d53; + @topColor: #c43d53; @bottomColor: #a82d31; - #gradient > .vertical(@topColor, @bottomColor ) !important; //red - border:1px solid @topColor; + #gradient > .vertical(@topColor, @bottomColor ) !important; //red + border:1px solid @topColor; } &:first-child input:checked:after{ - border:2px solid #6fa82d; - box-shadow:0 0 10px #6fa82d; + border:2px solid #6fa82d; + box-shadow:0 0 10px #6fa82d; } &:last-child input:checked:after{ - border:2px solid #a82d31; - box-shadow:0 0 10px #a82d31; + border:2px solid #a82d31; + box-shadow:0 0 10px #a82d31; } } @@ -268,7 +272,7 @@ #CommentList, .CommentList{ - margin-left: 130px; + margin-left: 115px; .comment{ margin-top:15px; } @@ -306,8 +310,7 @@ .model-details-summary{ font-size: 12px !important; - padding-left: 130px; - padding-top:15px; + padding-left: 115px; .gravatar{ margin-left: -115px; } @@ -339,8 +342,6 @@ #ModelDetailsSummaryView, #CommentInlineEditForModelView, #CommentsForRelatedModelView{ - width:70%; - float:left; max-width: 600px; .box-sizing(); .wide.form{ @@ -353,12 +354,12 @@ #CommentInlineEditForModelView{ margin-top: 0; - padding-left: 120px; + padding-left: 115px; td{ - padding:0 0 0 10px !important; + padding:0 0 0 0 !important; } h2{ - margin:0 0 13px 10px; + margin:0 0 0 0; } .wide.form{ padding:0; @@ -386,7 +387,7 @@ line-height: 140%; li{ margin-bottom:2px; - padding-left:15px; + padding-left:15px; } } @@ -538,14 +539,29 @@ a.user-link{ } } +#ConversationsPageView{ + #comment-inline-edit-form, + #social-item-inline-edit-form{ + .left-column{ + padding: 0; + } + .form-toolbar{ + padding: 0; + } + } +} + #comment-inline-edit-form, #social-item-inline-edit-form{ - padding-top:15px; + padding-bottom:15px; border:none; border-bottom: 1px solid #ccc; background: none !important; .b-shadow(none); .reset-filter(); + .left-column{ + //padding: 0; + } td:first-child{ padding-left: 0; } @@ -557,8 +573,8 @@ a.user-link{ .form-toolbar{ text-align: right; border-top:none; - padding-top: 0; - margin-top: 2px; + padding: 0 15px; + margin-top: 0; a{ color:#fff; margin-right:0; diff --git a/app/version.php b/app/version.php index b87db678c..4fd437a81 100755 --- a/app/version.php +++ b/app/version.php @@ -35,8 +35,8 @@ ********************************************************************************/ define('MAJOR_VERSION', 1); // Update for marketing purposes. - define('MINOR_VERSION', 5); // Update when functionality changes. - define('PATCH_VERSION', 15); // Update when fixes are made that does not change functionality. + define('MINOR_VERSION', 6); // Update when functionality changes. + define('PATCH_VERSION', 00); // Update when fixes are made that does not change functionality. define('REPO_ID', '$Revision$'); // Updated by Mercurial. Numbers like 3650 have no meaning across // clones. This tells us the actual changeset that is universally // meaningful.