From 3c6ecf227df612325e1bec1c8b7b758fd0f1d78d Mon Sep 17 00:00:00 2001 From: Ryan Mathis Date: Mon, 15 May 2023 09:26:09 -0700 Subject: [PATCH] Implemented vue.js payout --- Controller/GrouperGroupsController.php | 24 ++- View/Elements/Components/vue-table.ctp | 17 ++ View/GrouperGroups/groupmember.ctp | 2 - View/GrouperGroups/index.ctp | 149 ++++++++++++++ webroot/css/co-grouper-plugin.css | 43 ++-- webroot/css/empty | 0 webroot/files/groupmember.json | 207 +++++++++++++++++++ webroot/files/groupoptin.json | 17 ++ webroot/files/groupowner.json | 29 +++ webroot/js/grouper-groups-view.js | 270 +++++++++++++++---------- webroot/js/pagecount.js | 23 +++ webroot/js/pagination.js | 60 ++++++ webroot/js/search-groups.js | 38 ++++ webroot/js/search.js | 17 -- 14 files changed, 747 insertions(+), 149 deletions(-) create mode 100644 View/GrouperGroups/index.ctp delete mode 100644 webroot/css/empty create mode 100644 webroot/files/groupmember.json create mode 100644 webroot/files/groupoptin.json create mode 100644 webroot/files/groupowner.json create mode 100644 webroot/js/pagecount.js create mode 100644 webroot/js/pagination.js create mode 100644 webroot/js/search-groups.js delete mode 100644 webroot/js/search.js diff --git a/Controller/GrouperGroupsController.php b/Controller/GrouperGroupsController.php index b024ef6..301b045 100644 --- a/Controller/GrouperGroupsController.php +++ b/Controller/GrouperGroupsController.php @@ -120,9 +120,19 @@ private function setConnection() */ public function index() { - return $this->redirect( - array('controller' => 'grouper_groups', 'action' => 'groupmember') - ); + $this->set('title', _txt('pl.grouperlite.title.groupmember')); + + $config = [ + "grouperbaseurl" => $this->Session->read('Plugin.Grouper.Api.grouperUrl'), + "isuserowner" => $this->GrouperGroup->isUserOwner($this->userId), + "isTemplateUser" => $this->GrouperGroup->isTemplateUser($this->userId), + "isGrouperVisible" => $this->GrouperGroup->isGrouperVisible($this->userId), + "defaultCollapse" => CakeSession::read('Plugin.Grouper.Api.defaultCollapse'), + "adHocHeading" => CakeSession::read('Plugin.Grouper.Api.adHocHeading'), + "wgHeading" => CakeSession::read('Plugin.Grouper.Api.wgHeading'), + 'co' => CakeSession::read('Plugin.Grouper.Api.co') + ]; + $this->set('config', $config); } @@ -471,12 +481,12 @@ public function groupOwner() $this->set('config', $config); } - /** * 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() { $this->set('title', _txt('pl.grouperlite.title.groupmember')); @@ -789,18 +799,16 @@ function isAuthorized() //TODO - This is needed for my dev enviro since I do not log in via I2 IdP // BEGIN =============================================== - /* if ($this->Session->check('Auth.User.username')) { $this->userId = $this->Session->read('Auth.User.username'); } - */ // END =============================================== //TODO - Need to make the following code configurable in getting the user ID. In this case the code is // specific to the needs of I2. // BEGIN =============================================== - + /* $uid=$this->Session->read('Auth.User.co_person_id'); $username=$this->Session->read('Auth.User.username'); error_log("HUBING ================ " . $username); @@ -841,7 +849,7 @@ function isAuthorized() $this->Session->write('Plugin.Grouper.UserId', $this->userId); } // END =============================================== - + */ // Determine what operations this user can perform // Construct the permission set for this user, which will also be passed to the view. diff --git a/View/Elements/Components/vue-table.ctp b/View/Elements/Components/vue-table.ctp index 957ae03..af8e203 100644 --- a/View/Elements/Components/vue-table.ctp +++ b/View/Elements/Components/vue-table.ctp @@ -51,6 +51,23 @@ add: "webroot ?>grouper_lite/grouper_groups/addSubscriber", group: "webroot ?>grouper_lite/grouper_groups/groupSubscribers", }, + tabs: [ + { + order: 1, + label: "", + id: 'memberships' + }, + { + order: 2, + label: "", + id: 'join' + }, + { + order: 3, + label: "", + id: 'manage' + }, + ] }, mounted() { if (!this.owner) { diff --git a/View/GrouperGroups/groupmember.ctp b/View/GrouperGroups/groupmember.ctp index b12cdd4..7bbee89 100644 --- a/View/GrouperGroups/groupmember.ctp +++ b/View/GrouperGroups/groupmember.ctp @@ -1,8 +1,6 @@ extend('/GrouperGroups/base'); ?> Html->addCrumb(_txt('pl.grouperlite.nav.memberships')); ?> -element('GrouperLite.Components/navigation-groups', array('active' => 'groupmember')); ?> -element('GrouperLite.Components/search', array('active' => 'groupmember')); ?> element('GrouperLite.Components/vue-table', array( 'groupData' => json_encode(array( diff --git a/View/GrouperGroups/index.ctp b/View/GrouperGroups/index.ctp new file mode 100644 index 0000000..f521323 --- /dev/null +++ b/View/GrouperGroups/index.ctp @@ -0,0 +1,149 @@ + +extend('/GrouperGroups/base'); ?> +Html->addCrumb(_txt('pl.grouperlite.nav.memberships')); ?> + + + + + + +
+
+ + + +
+
diff --git a/webroot/css/co-grouper-plugin.css b/webroot/css/co-grouper-plugin.css index b69165b..5a2586c 100644 --- a/webroot/css/co-grouper-plugin.css +++ b/webroot/css/co-grouper-plugin.css @@ -31,23 +31,23 @@ a { margin-right: 2px; } -#grouper-plugin .nav.nav-tabs .nav-item a.nav-link { +#grouper-plugin .nav.nav-tabs .nav-item .nav-link { padding: 0.75rem 2rem; transition: background-color .2s cubic-bezier(.4, 0, .2, 1), color .2s cubic-bezier(.4, 0, .2, 1); border-radius: 0; } -#grouper-plugin .nav.nav-tabs .nav-item a.nav-link:not(.active) { +#grouper-plugin .nav.nav-tabs .nav-item .nav-link:not(.active) { color: white; background: var(--primary); } -#grouper-plugin .nav.nav-tabs .nav-item a.nav-link:not(.active):hover { +#grouper-plugin .nav.nav-tabs .nav-item .nav-link:not(.active):hover { border-color: black; background: black; } -#grouper-plugin .nav.nav-tabs .nav-item a.nav-link:not(.active):focus { +#grouper-plugin .nav.nav-tabs .nav-item .nav-link:not(.active):focus { border-color: transparent; } @@ -225,6 +225,7 @@ a.list-group-item-action:hover .fa { background-color: var(--primary); color: white; padding: 2px; + border-radius: 0; } .grouper .counter { @@ -232,25 +233,36 @@ a.list-group-item-action:hover .fa { font-size: 0.9rem; } -.grouper .pagination a { - color: white; +.grouper .pagination .pagination-item:not(:last-child) { + border-right: 1px solid rgba(255, 255, 255, 0.5); } .grouper .pagination .pagination-element:not(.pagination-numbers):not(.pagination-limit) { - padding: 0.5rem; margin-right: 0.5rem; } -.grouper .pagination .pagination-element.pagination-limit { - padding: 0 1rem; +.grouper .pagination .pagination-item-list { + display: flex; } -.grouper .pagination .pagination-element.pagination-numbers { - margin-right: 1rem; +.grouper .pagination .pagination-item .pagination-item-btn { + padding: 0.5rem 1rem; + color: white; + border: none; + background: none; } -.grouper .pagination .pagination-element.pagination-numbers-link:not(:first-child) { - border-left: 1px solid rgba(255, 255, 255, 0.5); +.grouper .pagination .pagination-item .pagination-item-btn:hover { + background: rgba(255, 255, 255, 0.1); +} + +.grouper .pagination .pagination-item.pagination-item-list .pagination-item-btn.current { + background: white; + color: var(--primary); +} + +.grouper .pagination .pagination-element.pagination-numbers { + margin-right: 1rem; } .grouper .pagination .pagination-element.pagination-numbers .pagination-numbers-list>span { @@ -263,11 +275,6 @@ a.list-group-item-action:hover .fa { padding: 0.5rem 1rem; } -.grouper .pagination .pagination-element.pagination-numbers .pagination-numbers-list .current.pagination-numbers-item { - background: white; - color: var(--primary); -} - .grouper .pagination .pagination-element.pagination-form * { margin: 0 0.5rem 0 0; } diff --git a/webroot/css/empty b/webroot/css/empty deleted file mode 100644 index e69de29..0000000 diff --git a/webroot/files/groupmember.json b/webroot/files/groupmember.json new file mode 100644 index 0000000..2d50459 --- /dev/null +++ b/webroot/files/groupmember.json @@ -0,0 +1,207 @@ +{ + "adhoc": [ + { + "extension": "admins", + "displayName": "app:Confluence:UniconTestAxel123:admins", + "description": "Admins of confluence space for working group. UniconTestAxel123", + "uuid": "1a0cc0cde33b4556b0565aa1f9c11f7a", + "enabled": "T", + "displayExtension": "admins", + "name": "app:Confluence:UniconTestAxel123:admins", + "typeOfGroup": "group", + "idIndex": "19473", + "optOut": false, + "friendlyName": "admins" + }, + { + "extension": "subscribers", + "displayName": "app:sympa:incommon:AdminTestWG:AdminTest WG subscribers", + "description": "Subscribers list receives working group emails. Test Create of a WG by an Admin", + "uuid": "2e421ab17fc94537a6efcdc38580a093", + "enabled": "T", + "displayExtension": "AdminTest WG subscribers", + "name": "app:sympa:incommon:AdminTestWG:subscribers", + "typeOfGroup": "group", + "idIndex": "19403", + "optOut": false, + "friendlyName": "AdminTest WG subscribers" + }, + { + "extension": "subscribers", + "displayName": "app:sympa:incommon:Bills Group:subscribers", + "description": "Subscribers list receives working group emails. Bills Working Group for testing and splunking", + "uuid": "a564f37496524696b486cffbddabd09d", + "enabled": "T", + "displayExtension": "subscribers", + "name": "app:sympa:incommon:BillsGroup:subscribers", + "typeOfGroup": "group", + "idIndex": "19123", + "optOut": false, + "friendlyName": "subscribers" + }, + { + "extension": "subscribers", + "displayName": "app:sympa:incommon:incommon-comanage:subscribers", + "uuid": "108785997dd7427ca06d5cdb0991cbad", + "enabled": "T", + "displayExtension": "subscribers", + "name": "app:sympa:incommon:incommon-comanage:subscribers", + "typeOfGroup": "group", + "idIndex": "19995", + "optOut": false, + "friendlyName": "subscribers" + }, + { + "extension": "subscriber", + "displayName": "app:sympa:internet2:d_iam_c:Drew's IAM Committee Subscriber", + "description": "Mailing List: Drew's IAM Committee", + "uuid": "3f4c50ee4ce542a6911dfd7cc4191799", + "enabled": "T", + "displayExtension": "Drew's IAM Committee Subscriber", + "name": "app:sympa:internet2:d_iam_c:subscriber", + "typeOfGroup": "group", + "idIndex": "21843", + "optOut": false, + "friendlyName": "Drew's IAM Committee Subscriber" + }, + { + "extension": "users", + "displayName": "ref:InCommon-collab:AdminTestWG:AdminTestWG users", + "description": "This is the AdminTestWG user group", + "uuid": "f092236c89254dc6b7f180706a5c5ad3", + "enabled": "T", + "displayExtension": "AdminTestWG users", + "name": "ref:incommon-collab:AdminTestWG:users", + "typeOfGroup": "group", + "idIndex": "19400", + "optOut": true, + "friendlyName": "AdminTestWG users" + }, + { + "extension": "users", + "displayName": "ref:InCommon-collab:BillsGroup:BillsGroupUsers", + "description": "Bills Group of Users", + "uuid": "215aead1b2a14464a65ce3723f326414", + "enabled": "T", + "displayExtension": "BillsGroupUsers", + "name": "ref:incommon-collab:BillsGroup:users", + "typeOfGroup": "group", + "idIndex": "20042", + "optOut": true, + "friendlyName": "BillsGroupUsers" + }, + { + "extension": "COmanage-UsersGroup-Members", + "displayName": "ref:InCommon-collab:COmanage:COmanage-UsersGroup-Members", + "description": "COmanage Users Group Members", + "uuid": "3ce99f5fc09c42968fae4afe5e63831d", + "enabled": "T", + "displayExtension": "COmanage-UsersGroup-Members", + "name": "ref:incommon-collab:COmanage:COmanage-UsersGroup-Members", + "typeOfGroup": "group", + "idIndex": "19996", + "optOut": true, + "friendlyName": "COmanage-UsersGroup-Members" + }, + { + "extension": "member", + "displayName": "ref:InCommon-collab:Drew's IAM Committee:Drew's IAM Committee Member", + "description": "Drew's IAM Committee member.", + "uuid": "1eafe705651c41fc8e6c50dc753c0891", + "enabled": "T", + "displayExtension": "Drew's IAM Committee Member", + "name": "ref:incommon-collab:d_iam_c:member", + "typeOfGroup": "group", + "idIndex": "20536", + "optOut": true, + "friendlyName": "Drew's IAM Committee Member" + }, + { + "extension": "users", + "displayName": "ref:InCommon-collab:UniconTestAxel333:UniconTestAxel333 users", + "description": "Users role means members of the working group with access to collaboration tools. UniconTestAxel333", + "uuid": "5b84ccacb8a940409f5e126ecabbb9e2", + "enabled": "T", + "displayExtension": "UniconTestAxel333 users", + "name": "ref:incommon-collab:UniconTestAxel333:users", + "typeOfGroup": "group", + "idIndex": "19481", + "optOut": true, + "friendlyName": "UniconTestAxel333 users" + }, + { + "extension": "subscriber", + "displayName": "sandbox:sympa:service:mailing_list:internet2:IAM Fans:IAM Fans Subscriber", + "description": "Mailing list for people who are Identity and Access Mangement fanatics", + "alternateName": "sandbox:sympa:service:mailing_list:internet2:iam_fans:iam_fans_subscriber", + "uuid": "0b23539aa1954f3e8cdd619d3f9e02b6", + "enabled": "T", + "displayExtension": "IAM Fans Subscriber", + "name": "sandbox:sympa:service:mailing_list:internet2:iam_fans:subscriber", + "typeOfGroup": "group", + "idIndex": "19208", + "optOut": true, + "friendlyName": "IAM Fans Subscriber" + }, + { + "extension": "user", + "displayName": "test:OptInOptOut:OptInOptOut User", + "description": "This group can be used in general to be provided privs for opting in and out just for folks in the group vs every entity", + "alternateName": "test:optinOptout", + "uuid": "13bed1e3e58148ec87400c43c9c3c824", + "enabled": "T", + "displayExtension": "OptInOptOut User", + "name": "test:optinoptout:user", + "typeOfGroup": "group", + "idIndex": "19109", + "optOut": true, + "friendlyName": "OptInOptOut User" + } + ], + "working": [ + { + "WGName": "AdminTestWG", + "WGShowName": "AdminTestWG", + "Groups": [ + { + "extension": "users", + "displayName": "app:Confluence:AdminTestWG:users", + "description": "Users of confluence space for working group. Test Create of a WG by an Admin", + "uuid": "caf29f77fdb948eb90a43756f8b3434a", + "enabled": "T", + "displayExtension": "users", + "name": "app:Confluence:AdminTestWG:users", + "typeOfGroup": "group", + "idIndex": "19405", + "optOut": false, + "WGName": "AdminTestWG", + "WGShowName": "AdminTestWG", + "WGRole": "users", + "WGApp": "Confluence" + } + ] + }, + { + "WGName": "BillsGroup", + "WGShowName": "Bills Group", + "Groups": [ + { + "extension": "users", + "displayName": "app:Confluence:Bills Group:users", + "description": "Users of confluence space for working group. Bills Working Group for testing and splunking", + "uuid": "d991a05d5e85494db17e09cc46af7274", + "enabled": "T", + "displayExtension": "users", + "name": "app:Confluence:BillsGroup:users", + "typeOfGroup": "group", + "idIndex": "19125", + "optOut": false, + "WGName": "BillsGroup", + "WGShowName": "Bills Group", + "WGRole": "users", + "WGApp": "Confluence" + } + ] + } + ] +} \ No newline at end of file diff --git a/webroot/files/groupoptin.json b/webroot/files/groupoptin.json new file mode 100644 index 0000000..de7d1a9 --- /dev/null +++ b/webroot/files/groupoptin.json @@ -0,0 +1,17 @@ +{ + "adhoc": [ + { + "extension": "users", + "displayName": "ref:InCommon-collab:UniconTestAxel123:UniconTestAxel123 users", + "description": "Users role means members of the working group with access to collaboration tools. UniconTestAxel123", + "uuid": "ac1641e827894283a8b7259a6549ce5c", + "enabled": "T", + "displayExtension": "UniconTestAxel123 users", + "name": "ref:incommon-collab:UniconTestAxel123:users", + "typeOfGroup": "group", + "idIndex": "19469", + "friendlyName": "UniconTestAxel123 users" + } + ], + "working": [] +} \ No newline at end of file diff --git a/webroot/files/groupowner.json b/webroot/files/groupowner.json new file mode 100644 index 0000000..7292441 --- /dev/null +++ b/webroot/files/groupowner.json @@ -0,0 +1,29 @@ +{ + "adhoc": [ + { + "extension": "admins", + "displayName": "app:Confluence:UniconTestAxel123:admins", + "description": "Admins of confluence space for working group. UniconTestAxel123", + "uuid": "1a0cc0cde33b4556b0565aa1f9c11f7a", + "enabled": "T", + "displayExtension": "admins", + "name": "app:Confluence:UniconTestAxel123:admins", + "typeOfGroup": "group", + "idIndex": "19473", + "friendlyName": "admins" + }, + { + "extension": "users", + "displayName": "app:Confluence:UniconTestAxel123:users", + "description": "Users of confluence space for working group. UniconTestAxel123", + "uuid": "43b9782ef93f47afa4d75d9911248720", + "enabled": "T", + "displayExtension": "users", + "name": "app:Confluence:UniconTestAxel123:users", + "typeOfGroup": "group", + "idIndex": "19474", + "friendlyName": "users" + } + ], + "working": [] +} \ No newline at end of file diff --git a/webroot/js/grouper-groups-view.js b/webroot/js/grouper-groups-view.js index 15baf5b..d426943 100644 --- a/webroot/js/grouper-groups-view.js +++ b/webroot/js/grouper-groups-view.js @@ -1,28 +1,51 @@ import Collapse from './collapse.js'; import Popover from './popover.js'; import Members from './members.js'; +import Search from './search-groups.js'; +import PageCount from './pagecount.js'; +import Pagination from './pagination.js'; export default { + directives: { + Popover + }, props: { - groups: Object, - columns: Object, config: Object, action: { type: String, - default: 'leave' + default: 'leavegroup' }, url: String, owner: Boolean, grouper: String, }, - inject: ['txt'], + inject: ['txt', 'tabs', 'columns'], + data() { + return { + active: 'memberships', + keyword: '', + loading: false, + error: null, + groups: { + adhoc: [], + working: [] + } + } + }, components: { Collapse, - Members + Members, + Search, + PageCount, + Pagination }, computed: { + cols() { + const ids = (!this.owner) ? this.tab.columns.filter(c => c.value !== 'role') : this.tab.columns; + return this.columns.filter(c => ids.indexOf(c.value) > -1); + }, numColumns() { - return this.columns.length; + return this.cols.length; }, collapsed() { return this.config.collapsed; @@ -32,131 +55,170 @@ export default { }, status() { return this.columns.some(c => c.value === 'status'); + }, + tab() { + return this.tabs.find(t => t.id === this.active); } }, - directives: { - Popover + watch: { + active(newActive) { + const { api } = this.tabs.find(t => t.id === newActive); + this.loadGroups(api); + } }, methods: { + search(query) { + this.keyword = query; + }, showSubscribers(group) { this.$refs.members.show(group); }, showOptAction(group) { - if (this.config.optAction === 'leavegroup'){ + if (this.tab.action === 'leavegroup'){ return group.optOut; } else { - return this.config.hasOwnProperty('optAction') && this.config.optAction !== 'none'; + return this.tab.action && this.tab.action !== 'none'; } + }, + async loadGroups(api, keyword) { + this.loading = true; + this.error = null; + const resp = await fetch(`${api}?keyword=${keyword}`, { + headers: { + "Accept": "application/json", + // 'Content-Type': 'application/x-www-form-urlencoded', + }, + method: "GET" + }); + if (resp.ok) { + this.groups = await resp.json(); + } else { + this.error = resp; + } + this.loading = false; } }, + mounted() { + this.loadGroups(this.tab.api); + }, template: /*html*/` - - + + + + +
- + - - - - - - - - - - - - - - - - -
{{ column.label }}{{ column.label }}
- -
- -
None
+ + ` } \ No newline at end of file diff --git a/webroot/js/pagecount.js b/webroot/js/pagecount.js new file mode 100644 index 0000000..f021ded --- /dev/null +++ b/webroot/js/pagecount.js @@ -0,0 +1,23 @@ +export default { + props: { + first: { + type: Number, + default: 0 + }, + last: { + type: Number, + default: 10 + }, + total: { + type: Number, + default: 100 + } + }, + template: /*html*/` +
+
+ Viewing {{first}}-{{last}} of {{total}} +
+
+ ` +} diff --git a/webroot/js/pagination.js b/webroot/js/pagination.js new file mode 100644 index 0000000..7f80259 --- /dev/null +++ b/webroot/js/pagination.js @@ -0,0 +1,60 @@ +export default { + props: { + current: { + type: Number, + default: 1 + } + }, + inject: ['txt'], + data() { + return { + query: '' + } + }, + methods: { + change() { + + } + }, + computed: { + numbers() { + return 5; + } + }, + mounted() { }, + template: /*html*/` + + ` +} + + diff --git a/webroot/js/search-groups.js b/webroot/js/search-groups.js new file mode 100644 index 0000000..3485bef --- /dev/null +++ b/webroot/js/search-groups.js @@ -0,0 +1,38 @@ +export default { + props: { + + }, + inject: ['txt'], + data() { + return { + query: '' + } + }, + methods: { + search(event, q) { + event.preventDefault(); + this.$emit('search', q); + } + }, + mounted() { }, + template: /*html*/` + + ` +} \ No newline at end of file diff --git a/webroot/js/search.js b/webroot/js/search.js deleted file mode 100644 index c74ddc2..0000000 --- a/webroot/js/search.js +++ /dev/null @@ -1,17 +0,0 @@ -export default { - props: { - - }, - data() { - return {} - }, - methods: { - - }, - mounted() { - - }, - template: /*html*/` - - ` -} \ No newline at end of file