diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index 5a6a705..b6f7a93 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -28,33 +28,20 @@ App::uses('Validator', 'Vendor/cakephp/Validation'); App::uses('CoGrouperLite', 'GrouperLite.Model/'); -/** - * Class GrouperGroupsController - * Main Class for Grouper Lite functionality - * - */ + class GrouperGroupsController extends GrouperLiteAppController { - public $helpers = array('Html', 'Form', 'Flash'); public $components = array('Flash'); public $name = 'GrouperGroups'; - /** - * Overrides parent beforeFilter to verify that Session contains the correct API settings. - * - * @return CakeResponse|void|null - * - */ - public function beforeFilter() - { + public function beforeFilter() { parent::beforeFilter(); //Need to find which plugin instance choosing, if more than one from cm_co_grouper_lites // table being used in COmanage. $grouperConnData = $this->Session->read('Plugin.Grouper.Api'); - if ($this->Session->check('Plugin.Grouper.Api.id') && count($grouperConnData) == 5) { if (isset($this->passedArgs['glid'])) { if ($this->Session->read('Plugin.Grouper.Api.id') !== $this->passedArgs['glid']) { @@ -69,15 +56,12 @@ public function beforeFilter() } $this->setConnection(); } - } /** * Adding Grouper Conn info to SESSION for use in Lib/GrouperApiAccess.php - * */ - private function setConnection() - { + private function setConnection() { $this->Session->write('Plugin.Grouper.Api.id', $this->passedArgs['glid']); //Now get the setup Dasboard instance from db for connection info. @@ -143,102 +127,72 @@ public function groupOwner() } } else { - try { - $this->set('groupergroupsowner', $this->GrouperGroup->ownerGroups($this->userId)); - } catch (Exception $e) { - CakeLog::write('error', - 'GrouperLite Controller - groupOwner: ' . var_export($e->getMessage(), true)); - $this->set('groupergroupsowner', array()); - $this->Flash->set(_txt('pl.grouperlite.message.flash.owner-group-failed'), array('key' => 'error')); - } - + $this->set('groupergroupsowner', $this->GrouperGroup->ownerGroups($this->userId)); } - $this->set('isuserowner', $this->GrouperGroup->isUserOwner($this->userId)); } /** - * Listing of all Grouper Groups that the User is a member of Or search those Grouper Groups - * This includes self-joined Optin Groups, as well as non-Optin Groups User cannot leave + * Returns all Groups that the User is a member of in Grouper + * This includes self-joined Optin Groups, as well as required Groups User cannot leave * */ - public function groupMember() - { + public function groupMember() { $this->set('title', _txt('pl.grouperlite.title.groupmember')); - - if (isset($this->request->data['search'])) { - $searchCriteria = urldecode($this->request->data['search']); - $this->set('searchcriteria', $searchCriteria); - - try { - $this->set('groupergroupmemberships', - $this->GrouperGroup->getSearchedGroups($this->userId, $searchCriteria, 'groupMember')); - } catch (Exception $e) { - CakeLog::write('error', - 'GrouperLite Controller - groupMember Search: ' . var_export($e->getMessage(), true)); - $this->set('groupergroupmemberships', array()); - $this->Flash->set(_txt('pl.grouperlite.message.flash.member-group-failed'), array('key' => 'error')); - } - - } else { - try { + try { + if (isset($this->request->data['search'])){ + $searchCriteria = urldecode($this->request->data['search']); + $this->set('groupergroupmemberships', $this->GrouperGroup->getSearchedGroups($this->userId, $searchCriteria, 'groupMember')); + $this->set('searchcriteria', $searchCriteria); + } else { $this->set('groupergroupmemberships', $this->GrouperGroup->filteredMemberOfGroups($this->userId)); - } catch (Exception $e) { - CakeLog::write('error', - 'GrouperLite Controller - groupMember: ' . var_export($e->getMessage(), true)); - $this->set('groupergroupmemberships', array()); - $this->Flash->set(_txt('pl.grouperlite.message.flash.member-group-failed'), array('key' => 'error')); } - + } catch (Exception $e) { + CakeLog::write('error', + 'GrouperLite Controller - groupMember: ' . var_export($e->getMessage(), true)); + $this->Flash->set("Your Membership Groups cannot be found currently, please try again later.", array('key' => 'error')); + $this->set('groupergroupmemberships', array()); } - $this->set('isuserowner', $this->GrouperGroup->isUserOwner($this->userId)); + } /** - * Display all Grouper Groups that are Optin and a User can join Or search those Grouper Groups + * Display all Groups a User can Join */ - public function groupOptin() - { + public function groupOptin() { $this->set('title', _txt('pl.grouperlite.title.groupoptin')); - if (isset($this->request->data['search'])) { + if (isset($this->request->data['search'])){ $searchCriteria = urldecode($this->request->data['search']); + $this->set('groupergroupoptin', $this->GrouperGroup->getSearchedGroups($this->userId, $searchCriteria, 'groupOptin')); $this->set('searchcriteria', $searchCriteria); - - try { - $this->set('groupergroupoptin', $this->GrouperGroup->getSearchedGroups($this->userId, $searchCriteria, 'groupOptin')); - } catch (Exception $e) { - CakeLog::write('error', - 'GrouperLite Controller - groupOptin Search: ' . var_export($e->getMessage(), true)); - $this->set('groupergroupoptin', array()); - $this->Flash->set(_txt('pl.grouperlite.message.flash.optin-group-failed'), array('key' => 'error')); - } - } else { try { - $this->set('groupergroupoptin', $this->GrouperGroup->optinGroups($this->userId)); + $optin = $this->GrouperGroup->optinGroups($this->userId); + if (isset($optin['errorMessage'])){ + $this->Flash->set('Some error', array('key' => 'error')); + $this->set('groupergroupoptin', array()); + } else { + $this->set('groupergroupoptin', $optin); + } + } catch (Exception $e) { - CakeLog::write('error', - 'GrouperLite Controller - groupOptin: ' . var_export($e->getMessage(), true)); - $this->Flash->set(_txt('pl.grouperlite.message.flash.optin-group-failed'), array('key' => 'error')); + CakeLog::write('error', 'GrouperLite Controller: Seeing is believing'); + $this->Flash->set($e->getMessage(), array('key' => 'error')); $this->set('groupergroupoptin', array()); } - } - $this->set('isuserowner', $this->GrouperGroup->isUserOwner($this->userId)); } //TODO - Need to combine this form with code below for groupCreate - public function groupCreateForm() - { + public function groupCreateForm() { $this->set('title', _txt('pl.grouperlite.title.groupcreate')); $this->set('grouperstems', $this->GrouperGroup->getOwnerStems($this->userId)); } - public function groupCreate() - { + public function groupCreate() { $name = urldecode($this->request->data['name']); $set = urldecode($this->request->data['set']); $descr = urldecode($this->request->data['description']); @@ -251,25 +205,18 @@ public function groupCreate() * * @return CakeResponse Redirect back to "Optin" page */ - public function joinGroup() - { + public function joinGroup() { if ($this->request->is('post')) { $name = $this->request->data['GroupName']; - try { - if ($this->GrouperGroup->joinGroup($this->userId, $name)) { - $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-success'), array('key' => 'success')); - } else { - $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-failed'), array('key' => 'error')); - } - } catch (Exception $e) { - CakeLog::write('error', - 'GrouperLite Controller - joinGroup: ' . var_export($e->getMessage(), true)); - $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-error'), array('key' => 'error')); + if($this->GrouperGroup->joinGroup($this->userId, $name)) { + $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-success'), array('key' => 'success')); + } else { + $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-failed'), array('key' => 'error')); } } else { - $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-error'), array('key' => 'error')); + $this->Flash->set(_txt('pl.grouperlite.message.flash.join-group-error')); } return $this->redirect(array('action' => 'groupoptin')); @@ -280,23 +227,15 @@ public function joinGroup() * * @return CakeResponse Redirect back to "Member Of" page */ - public function leaveGroup() - { + public function leaveGroup() { if ($this->request->is('post')) { $name = $this->request->data['GroupName']; - try { - if ($this->GrouperGroup->leaveGroup($this->userId, $name)) { - $this->Flash->set(_txt('pl.grouperlite.message.flash.leave-group-success'), array('key' => 'success')); - } else { - $this->Flash->set(_txt('pl.grouperlite.message.flash.leave-group-failed'), array('key' => 'error')); - } - } catch (Exception $e) { - CakeLog::write('error', - 'GrouperLite Controller - leaveGroup: ' . var_export($e->getMessage(), true)); - $this->Flash->set(_txt('pl.grouperlite.message.flash.leave-group-error'), array('key' => 'error')); + if($this->GrouperGroup->leaveGroup($this->userId, $name)) { + $this->Flash->set(_txt('pl.grouperlite.message.flash.leave-group-success'), array('key' => 'success')); + } else { + $this->Flash->set(_txt('pl.grouperlite.message.flash.leave-group-failed'), array('key' => 'error')); } - } else { $this->Flash->set(_txt('pl.grouperlite.message.flash.leave-group-error'), array('key' => 'error')); } @@ -312,15 +251,14 @@ public function leaveGroup() * - precondition: Session.Auth holds data used for authz decisions * - postcondition: $permissions set with calculated permissions * - * @return Array Permissions * @since COmanage Registry v3.2.0 + * @return Array Permissions */ - function isAuthorized() - { + function isAuthorized() { $roles = $this->Role->calculateCMRoles(); //Need to pull in UserID for access to Grouper - if ($this->Session->check('Auth.User.username')) { + if($this->Session->check('Auth.User.username')) { $this->userId = $this->Session->read('Auth.User.username'); } @@ -348,8 +286,7 @@ function isAuthorized() return ($p[$this->action]); } - public function emailListsOptin() - { + public function emailListsOptin() { $this->set('title', _txt('pl.grouperlite.title.emaillists')); // mock data $this->set('group', array( @@ -360,8 +297,7 @@ public function emailListsOptin() )); } - public function emailListsManaged() - { + public function emailListsManaged() { $this->set('title', _txt('pl.grouperlite.title.emaillistsmanaged')); // mock data $this->set('group', array( @@ -372,8 +308,7 @@ public function emailListsManaged() )); } - public function emailListInfo() - { + public function emailListInfo() { $this->set('title', _txt('pl.grouperlite.title.emaillistsinfo')); // mock data $this->set('groupergroupsdetail', array( diff --git a/View/Elements/Components/navigation.ctp b/View/Elements/Components/navigation.ctp index a0e2c68..4385907 100644 --- a/View/Elements/Components/navigation.ctp +++ b/View/Elements/Components/navigation.ctp @@ -63,17 +63,19 @@ */ ?> -
- Html->url( - array( - 'controller' => 'groupergroups', - 'action' => 'groupcreateform' - ) - ); - ?> - -   - -
+ +
+ Html->url( + array( + 'controller' => 'groupergroups', + 'action' => 'groupcreateform' + ) + ); + ?> + +   + +
+ \ No newline at end of file diff --git a/View/Elements/Components/subscriberList.ctp b/View/Elements/Components/subscriberList.ctp index bf4330e..378dc0e 100644 --- a/View/Elements/Components/subscriberList.ctp +++ b/View/Elements/Components/subscriberList.ctp @@ -1,5 +1,11 @@ - \ No newline at end of file + + + + + + + + + + +
\ No newline at end of file diff --git a/View/Elements/pagination.php b/View/Elements/pagination.php new file mode 100644 index 0000000..2bb25ec --- /dev/null +++ b/View/Elements/pagination.php @@ -0,0 +1,110 @@ + + + \ No newline at end of file diff --git a/View/GrouperGroups/groupinfo.ctp b/View/GrouperGroups/groupinfo.ctp index 2350cb0..c74a6b6 100644 --- a/View/GrouperGroups/groupinfo.ctp +++ b/View/GrouperGroups/groupinfo.ctp @@ -7,16 +7,17 @@ $groupOperation = '?operation=UiV2Group.viewGroup&groupId='; $groupUrlBase = $baseUrl . $path . $groupOperation; $attrOperation = '?operation=UiV2AttributeDefName.viewAttributeDefName&attributeDefNameId='; $attrUrlBase = $baseUrl . $path . $attrOperation; + +$isuserowner = 'T'; ?>

Group:

-

Group Properties

+
+

Group Properties

+ + + +
+ + element('Components/groupproperties', array( 'group' => $groupergroupsdetail )); ?> +
@@ -39,23 +51,630 @@ $attrUrlBase = $baseUrl . $path . $attrOperation; )); ?>
-
-

Subscribers

-
- element('Components/subscriberList', array('subscribers' => array( - array( - "name" => "Galena Munoz", - "email" => "ipsum.cursus.vestibulum@urnaconvalliserat.net", - "cou" => "Active, Member", - "org" => "Eu Corporation" - ), - array( - "name" => "Doris Santos", - "email" => "vitae@non.org", - "cou" => "Active, Filesource, Member", - "org" => "Aliquam LLC" - ) - ))); ?> +
+
+ + \ No newline at end of file diff --git a/View/GrouperGroups/groupmember.ctp b/View/GrouperGroups/groupmember.ctp index e9f704d..48b0f3a 100644 --- a/View/GrouperGroups/groupmember.ctp +++ b/View/GrouperGroups/groupmember.ctp @@ -14,24 +14,26 @@ - Html->link( + + Html->link( isset($group['friendlyName']) ? $group['friendlyName'] : "No Name", array( 'controller' => 'groupergroups', 'action' => 'groupinfo', '?' => array('groupname' => urlencode($group['name'])) ) - ) ?> + ) ?> + element('GrouperLite.Components/optAction', array( - 'member' => $group['optedin'], - 'action' => 'leavegroup', - 'group' => $group['name'] + 'member' => $group['optedin'], + 'action' => 'leavegroup', + 'group' => $group['name'] )) : ''; ?> -
\ No newline at end of file +
diff --git a/View/GrouperGroups/users.json b/View/GrouperGroups/users.json new file mode 100644 index 0000000..6e08fee --- /dev/null +++ b/View/GrouperGroups/users.json @@ -0,0 +1,344 @@ +[ + { + "name": "Galena Munoz", + "email": "ipsum.cursus.vestibulum@urnaconvalliserat.net", + "cou": "Active, Member", + "org": "Eu Corporation" + }, + { + "name": "Doris Santos", + "email": "vitae@non.org", + "cou": "Active, Filesource, Member", + "org": "Aliquam LLC" + }, + { + "name": "Alma English", + "email": "pede.Cum.sociis@telluseu.net", + "cou": "Member, Active, Writer, Filesource", + "org": "Consectetuer Corp." + }, + { + "name": "Halee Finley", + "email": "in.consectetuer.ipsum@parturientmontes.co.uk", + "cou": "Member", + "org": "Felis Ltd" + }, + { + "name": "Austin Hardy", + "email": "iaculis@Donecegestas.co.uk", + "cou": "Writer", + "org": "Nonummy LLP" + }, + { + "name": "Victor Powell", + "email": "nisi@eget.ca", + "cou": "Member, Active", + "org": "Praesent Interdum Ligula PC" + }, + { + "name": "Baxter Estrada", + "email": "in.consequat.enim@vestibulum.co.uk", + "cou": "", + "org": "In Molestie Tortor Corporation" + }, + { + "name": "Carlos Rose", + "email": "elit.elit@non.co.uk", + "cou": "Member, Writer, Filesource, Active", + "org": "Risus Nulla Eget LLP" + }, + { + "name": "Ishmael Patton", + "email": "leo.Morbi@mollisnoncursus.co.uk", + "cou": "Writer, Filesource", + "org": "A Enim Suspendisse Consulting" + }, + { + "name": "Ryder Tanner", + "email": "varius@rutrum.org", + "cou": "Writer, Filesource", + "org": "Ornare Elit Elit Consulting" + }, + { + "name": "Dane Rollins", + "email": "Curabitur.consequat.lectus@Naminterdum.ca", + "cou": "Member", + "org": "Ut Pellentesque Consulting" + }, + { + "name": "Brian Kaufman", + "email": "aliquet.vel@orciluctuset.edu", + "cou": "Filesource, Active", + "org": "Justo Eu Arcu Inc." + }, + { + "name": "Lester Price", + "email": "Integer@idlibero.edu", + "cou": "Writer, Member, Active, Filesource", + "org": "Dapibus Rutrum Justo Incorporated" + }, + { + "name": "Helen Cardenas", + "email": "Curabitur.egestas.nunc@quisdiam.org", + "cou": "Member, Active, Filesource", + "org": "Faucibus Morbi Vehicula Associates" + }, + { + "name": "Hop Holloway", + "email": "non.arcu.Vivamus@nibhvulputate.org", + "cou": "Filesource, Active, Member", + "org": "Nunc Sed Pede Ltd" + }, + { + "name": "Madeson Hendrix", + "email": "viverra@purus.com", + "cou": "", + "org": "Neque Venenatis Consulting" + }, + { + "name": "Amity Navarro", + "email": "tincidunt.Donec@inconsequat.com", + "cou": "Writer", + "org": "Pretium Aliquet Consulting" + }, + { + "name": "Cameron Booth", + "email": "nulla.magna@Quisqueporttitor.net", + "cou": "", + "org": "Fusce Associates" + }, + { + "name": "Sybil Burgess", + "email": "Fusce.feugiat@sem.org", + "cou": "Writer, Member, Filesource, Active", + "org": "Curabitur Corporation" + }, + { + "name": "Otto Cantrell", + "email": "Ut@nonarcu.org", + "cou": "", + "org": "Cursus PC" + }, + { + "name": "Mannix Obrien", + "email": "eu.neque@egestasDuisac.ca", + "cou": "", + "org": "Amet Faucibus Corp." + }, + { + "name": "Marcia Gill", + "email": "molestie.in.tempus@posuere.edu", + "cou": "", + "org": "Et Corp." + }, + { + "name": "Tanek Figueroa", + "email": "diam@arcuSed.org", + "cou": "Active", + "org": "Bibendum Donec Ltd" + }, + { + "name": "Ira Lynn", + "email": "aliquet@consequatpurusMaecenas.edu", + "cou": "Filesource", + "org": "Massa Suspendisse Eleifend Corporation" + }, + { + "name": "Lesley Pittman", + "email": "iaculis.odio@Phasellus.edu", + "cou": "Member, Writer", + "org": "Urna Et Arcu PC" + }, + { + "name": "Len Ryan", + "email": "ut.mi.Duis@sitamet.org", + "cou": "Writer, Filesource, Active", + "org": "Vestibulum Accumsan PC" + }, + { + "name": "Sarah Morton", + "email": "dis.parturient@rhoncusProin.org", + "cou": "Active", + "org": "Amet Consectetuer PC" + }, + { + "name": "Marny Hewitt", + "email": "dapibus@orciquis.ca", + "cou": "Active, Writer", + "org": "Ultricies Consulting" + }, + { + "name": "Abel Lyons", + "email": "Proin.eget.odio@enim.org", + "cou": "Writer", + "org": "Amet Lorem Corporation" + }, + { + "name": "Slade Schneider", + "email": "ante.dictum.cursus@turpisAliquamadipiscing.co.uk", + "cou": "", + "org": "Lacinia Company" + }, + { + "name": "Ashton Arnold", + "email": "velit.justo@velitin.edu", + "cou": "", + "org": "Diam Ltd" + }, + { + "name": "Phelan Goff", + "email": "ullamcorper.viverra.Maecenas@Donecporttitortellus.ca", + "cou": "", + "org": "Faucibus Id Libero Institute" + }, + { + "name": "Graham Underwood", + "email": "Nulla.dignissim.Maecenas@Donecsollicitudin.ca", + "cou": "Filesource, Member", + "org": "Duis Gravida Praesent Ltd" + }, + { + "name": "Alisa Scott", + "email": "ipsum.primis.in@erat.co.uk", + "cou": "Writer, Active", + "org": "Vivamus Non Lorem Inc." + }, + { + "name": "Asher Mccray", + "email": "semper.auctor@nibhAliquamornare.edu", + "cou": "Writer, Member", + "org": "Orci Corporation" + }, + { + "name": "Hanna Salas", + "email": "feugiat@purusactellus.net", + "cou": "", + "org": "Lectus Convallis Industries" + }, + { + "name": "Jeremy Riley", + "email": "Ut.sagittis@necante.ca", + "cou": "Writer", + "org": "Luctus Curabitur LLP" + }, + { + "name": "Violet Trevino", + "email": "vestibulum@nec.edu", + "cou": "", + "org": "Ligula Aenean Gravida Consulting" + }, + { + "name": "Carissa Myers", + "email": "non@rhoncusDonec.co.uk", + "cou": "Member, Filesource", + "org": "Tempor Corporation" + }, + { + "name": "Kadeem Osborn", + "email": "nulla.In@aliquameros.ca", + "cou": "Filesource, Active, Member, Writer", + "org": "Tempus Risus Donec PC" + }, + { + "name": "Kiayada England", + "email": "ultrices.posuere@lectus.net", + "cou": "", + "org": "Orci Institute" + }, + { + "name": "Connor Gardner", + "email": "diam.eu@tortorIntegeraliquam.org", + "cou": "Member, Active, Writer", + "org": "Vulputate Nisi Sem LLP" + }, + { + "name": "Alfonso Casey", + "email": "montes.nascetur.ridiculus@risus.net", + "cou": "Member", + "org": "Sed Eu Nibh Consulting" + }, + { + "name": "Avye Raymond", + "email": "mauris.sapien@tempusrisusDonec.co.uk", + "cou": "Active, Writer, Filesource, Member", + "org": "Amet Ante Incorporated" + }, + { + "name": "Quamar Cross", + "email": "elit.pretium@Sedid.org", + "cou": "", + "org": "Dapibus PC" + }, + { + "name": "Justine Kemp", + "email": "diam@ornare.org", + "cou": "Writer, Filesource", + "org": "Libero At Auctor Associates" + }, + { + "name": "Blair Rush", + "email": "at.velit.Cras@pulvinar.ca", + "cou": "", + "org": "Nulla Tempor Associates" + }, + { + "name": "Jael Travis", + "email": "ut.dolor.dapibus@vestibulumneceuismod.ca", + "cou": "", + "org": "Facilisis Lorem LLC" + }, + { + "name": "Donovan Patel", + "email": "bibendum.ullamcorper@Sedeu.co.uk", + "cou": "Member, Filesource, Writer, Active", + "org": "Ipsum Sodales Incorporated" + }, + { + "name": "Sylvester Brady", + "email": "amet@consequatauctornunc.net", + "cou": "", + "org": "Semper Nam Limited" + }, + { + "name": "Yuri Eaton", + "email": "Nullam.lobortis.quam@Etiamligulatortor.com", + "cou": "", + "org": "Eu Elit Nulla LLP" + }, + { + "name": "Bree Harmon", + "email": "libero.Integer@maurisaliquam.ca", + "cou": "Filesource, Active, Member, Writer", + "org": "Dui In Sodales PC" + }, + { + "name": "Tanek Tucker", + "email": "arcu@Craslorem.org", + "cou": "Active, Member, Filesource", + "org": "Nisl Arcu Company" + }, + { + "name": "Jermaine Stevens", + "email": "luctus@Donec.org", + "cou": "Active, Writer", + "org": "Pellentesque Sed Dictum Corp." + }, + { + "name": "Ira Robinson", + "email": "malesuada.vel@lobortisClass.ca", + "cou": "Active, Member", + "org": "Ac Sem Ut Consulting" + }, + { + "name": "Jocelyn Fulton", + "email": "tristique.senectus.et@faucibusorci.co.uk", + "cou": "Active, Member, Filesource, Writer", + "org": "Ante Ipsum Institute" + }, + { + "name": "Tatyana Kelly", + "email": "a.facilisis.non@tortorat.ca", + "cou": "", + "org": "Donec Feugiat Limited" + } +] \ No newline at end of file diff --git a/webroot/css/co-grouper-plugin.css b/webroot/css/co-grouper-plugin.css index 38484bc..ec6461f 100644 --- a/webroot/css/co-grouper-plugin.css +++ b/webroot/css/co-grouper-plugin.css @@ -22,6 +22,13 @@ margin: 0; } +.btn-sm { + padding: 0.6rem 1rem; + font-size: 1rem; + line-height: 1; + border-radius: .2rem; +} + a { color: var(--primary); } @@ -192,4 +199,17 @@ a.list-group-item-action:hover { a.list-group-item-action:hover .fa { text-decoration: none; +} + +.modal.modal-primary .modal-header { + background: var(--primary); + color: white; +} + +.modal.modal-primary .modal-title, .modal.modal-primary .modal-header, .modal.modal-primary .close { + color: white; +} + +.modal.modal-primary .close { + opacity: 1; } \ No newline at end of file