diff --git a/bower.json b/bower.json index 40d25d80..2fee9681 100644 --- a/bower.json +++ b/bower.json @@ -34,7 +34,7 @@ "angular-translate-interpolation-messageformat": "^2.14.0", "angular-sanitize": "^1.6.2", "angular-message-format": "^1.6.2", - "impac-angular": "~1.7.0", + "impac-angular": "~1.8.5", "angular-bootstrap-toggle": "^0.1.2" }, "devDependencies": { diff --git a/src/app/components/mnoe-api/admin/dashboard.svc.coffee b/src/app/components/mnoe-api/admin/dashboard.svc.coffee new file mode 100644 index 00000000..efc6ab2b --- /dev/null +++ b/src/app/components/mnoe-api/admin/dashboard.svc.coffee @@ -0,0 +1,18 @@ +# Service for managing staff dashboards +@App.service 'MnoeDashboards', (MnoeAdminApiSvc, MnoeCurrentUser) -> + _self = @ + + # List the staff dashboard for the current user + @getStaffDashboards = (organizationUid, limit, offset, sort) -> + MnoeAdminApiSvc.all("/impac/dashboards").getList({ + order_by: sort, + limit: limit, + offset: offset, + 'where[data_sources]': [organizationUid] + }) + + # Delete a dashboard + @delete = (dashboardId) -> + MnoeAdminApiSvc.one("/impac/dashboards", dashboardId).remove() + + return @ diff --git a/src/app/components/mnoe-config/mnoe-admin-config.svc.coffee b/src/app/components/mnoe-config/mnoe-admin-config.svc.coffee index 30b87efb..42466f28 100644 --- a/src/app/components/mnoe-config/mnoe-admin-config.svc.coffee +++ b/src/app/components/mnoe-config/mnoe-admin-config.svc.coffee @@ -97,4 +97,7 @@ @dashboardTemplatesDatesFormat = -> ADMIN_PANEL_CONFIG.dashboard_templates? && ADMIN_PANEL_CONFIG.dashboard_templates.dates_format || 'L' + @isStaffDashboardsEnabled = -> + ADMIN_PANEL_CONFIG.staff_dashboards? && ADMIN_PANEL_CONFIG.staff_dashboards.enabled + return @ diff --git a/src/app/components/mnoe-staff-dashboards-list/mnoe-staff-dashboards-list.coffee b/src/app/components/mnoe-staff-dashboards-list/mnoe-staff-dashboards-list.coffee new file mode 100644 index 00000000..d6b80170 --- /dev/null +++ b/src/app/components/mnoe-staff-dashboards-list/mnoe-staff-dashboards-list.coffee @@ -0,0 +1,109 @@ +# +# Mnoe staff dashboards list. +# +@App.component('mnoeStaffDashboardsList', { + templateUrl: 'app/components/mnoe-staff-dashboards-list/mnoe-staff-dashboards-list.html' + bindings: { + organization: '<' + } + + controller: (toastr, MnoConfirm, MnoeDashboards, ImpacDashboardsSvc, ImpacConfigSvc) -> + vm = this + + vm.$onChanges = (changes) -> + if changes.organization && vm.organization + fetchDashboards() + + vm.dashboards = + sort: "created_at" + nbItems: 5 + page: 1 + offset: 0 + nbItemsValues: [5, 10, 20] + pageChangedCb: (nbItems, page) -> + vm.dashboards.nbItems = nbItems + vm.dashboards.page = page + offset = (page - 1) * nbItems + fetchDashboards(nbItems, offset) + + vm.callServer = (tableState) -> + sort = updateSort(tableState.sort) + fetchDashboards(vm.dashboards.nbItems, vm.dashboards.offset, sort) + + # Update sorting parameters + updateSort = (sortState = {}) -> + sort = "name" + if sortState.predicate + sort = sortState.predicate + if sortState.reverse + sort += ".desc" + else + sort += ".asc" + + # Update dashboards sort + vm.dashboards.sort = sort + + #==================================== + # Reconfigure Impac! + #==================================== + ImpacConfigSvc.disableDashboardDesigner() + + #==================================== + # Retrieve Staff Dashboard + #==================================== + fetchDashboards = (limit = vm.dashboards.nbItems, offset = vm.dashboards.offset, sort = vm.dashboards.sort) -> + vm.dashboards.loading = true + return unless vm.organization + return MnoeDashboards.getStaffDashboards(vm.organization.uid, limit, offset, sort).then( + (response) -> + vm.dashboards.totalItems = response.headers('x-total-count') + vm.dashboards.list = response.data + ).finally(-> vm.dashboards.loading = false) + + #==================================== + # Staff dashboard deletion Modal + #==================================== + vm.openDeleteModal = (dashboardId) -> + + modalOptions = + type: 'danger' + closeButtonText: 'mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.cancel' + actionButtonText: 'mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.action' + headerText: 'mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.proceed' + bodyText: 'mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.perform' + MnoConfirm.showModal(modalOptions).then( + -> + MnoeDashboards.delete(dashboardId).then( + (success) -> + toastr.success('mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.toastr.success') + # Reload list if the user deleted a dashboard + fetchDashboards() + (error) -> + toastr.error('mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.toastr.error') + ) + -> + # Cancel + ) + + # ----------------------------------------------------------- + # Advisor Dashboard + # ----------------------------------------------------------- + vm.createDashboard = (dashboard) -> + angular.merge(dashboard, { organization_ids: [vm.organization.id] }) + + # TODO: bug when creating after copying (also present on frontend) + promise = if dashboard.id + ImpacDashboardsSvc.copy(dashboard) + else + ImpacDashboardsSvc.create(dashboard) + + # TODO: toaster + # refresh dashboard list OR redirect to created dashboard + promise.then( + (savedDhb) -> + fetchDashboards() + # $state.go('dashboard.staff-dashboard-show', dashboardId: dashboard.id, orgId: vm.organization.id) + ) + + return +}) diff --git a/src/app/components/mnoe-staff-dashboards-list/mnoe-staff-dashboards-list.html b/src/app/components/mnoe-staff-dashboards-list/mnoe-staff-dashboards-list.html new file mode 100644 index 00000000..1df22124 --- /dev/null +++ b/src/app/components/mnoe-staff-dashboards-list/mnoe-staff-dashboards-list.html @@ -0,0 +1,50 @@ + + +
+ +
+
+ +
+ + + + + + + + + + + + + + + + + +
mnoe_admin_panel.dashboard.staff_dashboards.widget.list.name
+ {{ dashboard.name }} + +
+
+ + + +
+
+
+
+
+ + + + +
diff --git a/src/app/components/mnoe-staff-dashboards-list/mnoe-staff-dashboards-list.less b/src/app/components/mnoe-staff-dashboards-list/mnoe-staff-dashboards-list.less new file mode 100644 index 00000000..6ae1a958 --- /dev/null +++ b/src/app/components/mnoe-staff-dashboards-list/mnoe-staff-dashboards-list.less @@ -0,0 +1,11 @@ +.nested-table-one-header:first-of-type { + font-weight: bold; +} + +.nested-table-one-header > td:first-of-type { + padding-left: 16px !important; +} + +.nested-table-one-body > td:first-of-type { + padding-left: 24px !important; +} diff --git a/src/app/impac.config.coffee b/src/app/impac.config.coffee index 890b9ba2..df9544d9 100644 --- a/src/app/impac.config.coffee +++ b/src/app/impac.config.coffee @@ -9,9 +9,6 @@ angular.module 'frontendAdmin' data = mnoHub: mnoHub impacApi: "#{IMPAC_CONFIG.protocol}://#{IMPAC_CONFIG.host}/api" - dashboards: - index: "#{mnoHub}/admin/impac/dashboard_templates" - show: "#{mnoHub}/admin/impac/dashboard_templates/:id" widgets: update: "#{mnoHub}/admin/impac/widgets/:id" del: "#{mnoHub}/admin/impac/widgets/:id" @@ -30,7 +27,9 @@ angular.module 'frontendAdmin' options = # link to the marketplace dataNotFoundConfig: - mainMessage: 'mnoe_admin_panel.impac.data_not_found_config.custom_message' + content: + mainMessage: 'mnoe_admin_panel.impac.data_not_found_config.custom_message' + linkMessage: null linkUrl: '#!/marketplace' linkTarget: '_self' dhbConfig: @@ -44,8 +43,6 @@ angular.module 'frontendAdmin' # configurations for the dashboard selector feature. dhbSelectorConfig: pdfModeEnabled: false - addDhbEnabled: false - deleteDhbEnabled: false selectorType: 'dropdown' dhbSettings: syncApps: diff --git a/src/app/index.route.coffee b/src/app/index.route.coffee index d4d38a3c..4542fa45 100644 --- a/src/app/index.route.coffee +++ b/src/app/index.route.coffee @@ -157,6 +157,8 @@ if adminConfig.isDashboardTemplatesEnabled $stateProvider.state 'dashboard.dashboard-templates', + data: + dashboardDesigner: true url: '/dashboard-templates' templateUrl: 'app/views/dashboard-templates/dashboard-templates.html' controller: 'DashboardTemplatesController' @@ -164,6 +166,8 @@ ncyBreadcrumb: label: 'mnoe_admin_panel.dashboard.dashboard_templates.title' .state 'dashboard.dashboard-templates-show', + data: + dashboardDesigner: true url: '/dashboard-templates/:dashboardId' templateUrl: 'app/views/impac/impac.html' controller: 'ImpacController' @@ -171,4 +175,15 @@ ncyBreadcrumb: label: 'mnoe_admin_panel.dashboard.impac.title' + if adminConfig.isStaffDashboardsEnabled() + $stateProvider.state 'dashboard.staff-dashboard-show', + data: + dashboardDesigner: false + url: '^/organization/:orgId/staff-dashboard/:dashboardId' + templateUrl: 'app/views/impac/impac.html' + controller: 'ImpacController' + controllerAs: 'vm' + ncyBreadcrumb: + label: 'mnoe_admin_panel.dashboard.staff_dashboards.title' + $urlRouterProvider.otherwise '/home' diff --git a/src/app/services/impac-config/impac-config.coffee b/src/app/services/impac-config/impac-config.coffee index ba26294b..cde52db0 100644 --- a/src/app/services/impac-config/impac-config.coffee +++ b/src/app/services/impac-config/impac-config.coffee @@ -1,19 +1,94 @@ -@App.service 'ImpacConfigSvc' , ($log, $q, MnoeCurrentUser, MnoeOrganizations) -> +@App.service 'ImpacConfigSvc' , ($state, $stateParams, $log, $q, MnoeCurrentUser, MnoeOrganizations, ImpacMainSvc, ImpacRoutes, ImpacTheming, IMPAC_CONFIG) -> _self = @ + # Keep track of dashboard designer mode + _self.dashboardDesigner = null + + # Used to control Impac Angular UI in staff dashboard mode + # We want to remove the create/delete dashboard butttons as this is managed through + # the staff-dashboard-list component. + defaultACL = { + self: {show: true, update: true, destroy: true}, + related: { + impac: {show: true}, + dashboards: {show: true, create: false, update: true, destroy: false}, + widgets: {show: true, create: true, update: true, destroy: true}, + kpis: {show: false, create: false, update: false, destroy: false} + } + } + @getUserData = -> MnoeCurrentUser.getUser() @getOrganizations = -> - userOrgsPromise = MnoeCurrentUser.getUser().then( - (user) -> - userOrgs = user.organizations - if _.isEmpty(userOrgs) - $log.error(err = { message: "Unable to retrieve user organizations" }) - $q.reject(err) - else - firstOrgId = userOrgs[0].id - $q.resolve({ organizations: userOrgs, currentOrgId: firstOrgId }) - ) + if _self.dashboardDesigner + MnoeCurrentUser.getUser().then( + (user) -> + userOrgs = user.organizations + if _.isEmpty(userOrgs) + $log.error(err = { message: "Unable to retrieve user organizations" }) + $q.reject(err) + else + firstOrgId = userOrgs[0].id + $q.resolve({ organizations: userOrgs, currentOrgId: firstOrgId }) + ) + else if $stateParams.orgId + # Staff dashboard mode, returns the current organization + $log.info('getOrganizations', 'Loading customer org') + MnoeOrganizations.get($stateParams.orgId).then( + (response) -> + currentOrganization = response.data.plain() + angular.extend(currentOrganization, {acl: defaultACL}) + $q.resolve( + organizations: [currentOrganization], + currentOrgId: currentOrganization.id + ) + ) + else + $log.warn('ImpacConfigSvc.getOrganizations: Designer disabled and orgId specified') + $log.error(err = { message: "Unable to retrieve user organizations" }) + $q.reject(err) + + @configureDashboardDesigner = (enabled) -> + _self.dashboardDesigner = enabled + + $log.info('Configuring dashboard designer', enabled, _self.dashboardDesigner) + + # Reconfigure Impac routes to use templates or dashboards + mnoHub = IMPAC_CONFIG.paths.mnohub_api + + if _self.dashboardDesigner + data = + dashboards: + index: "#{mnoHub}/admin/impac/dashboard_templates" + show: "#{mnoHub}/admin/impac/dashboard_templates/:id" + else + data = + dashboards: + index: "#{mnoHub}/admin/impac/dashboards" + show: "#{mnoHub}/admin/impac/dashboards/:id" + create: "#{mnoHub}/admin/impac/dashboards" + + ImpacRoutes.configureRoutes(data) + + # Configure Dashboard Designer + options = + dhbConfig: + designerMode: + enabled: enabled + # For now do not allow to create templates from templates + dhbSettings: + createFromTemplateEnabled: !enabled + # Disable PDF mode in designer mode + dhbSelectorConfig: + pdfModeEnabled: !enabled + + ImpacTheming.configure(options) + + @enableDashboardDesigner = -> + _self.configureDashboardDesigner(true) + + @disableDashboardDesigner = -> + _self.configureDashboardDesigner(false) return diff --git a/src/app/views/dashboard-templates/dasboard-templates.controller.coffee b/src/app/views/dashboard-templates/dasboard-templates.controller.coffee index 302b1e2a..b0a4f1b5 100644 --- a/src/app/views/dashboard-templates/dasboard-templates.controller.coffee +++ b/src/app/views/dashboard-templates/dasboard-templates.controller.coffee @@ -1,7 +1,10 @@ -@App.controller 'DashboardTemplatesController', ($state, ImpacDashboardsSvc) -> +@App.controller 'DashboardTemplatesController', ($state, ImpacDashboardsSvc, ImpacConfigSvc) -> 'ngInject' vm = this + # Reconfigure Impac to enable the dashboard designer + ImpacConfigSvc.enableDashboardDesigner() + vm.createDashboard = (dashboard) -> angular.merge(dashboard, { published: false }) ImpacDashboardsSvc.create(dashboard).then( diff --git a/src/app/views/impac/impac.coffee b/src/app/views/impac/impac.coffee index 9164e44d..d65885a6 100644 --- a/src/app/views/impac/impac.coffee +++ b/src/app/views/impac/impac.coffee @@ -1,8 +1,17 @@ -@App.controller 'ImpacController', ($rootScope, $stateParams, MnoeDashboardTemplates, ImpacDashboardsSvc) -> +@App.controller 'ImpacController', ( + $rootScope, $state, $stateParams + MnoeDashboardTemplates, MnoeOrganizations, ImpacConfigSvc, ImpacDashboardsSvc +) -> 'ngInject' vm = this vm.dashboardLoaded = false + vm.designerMode = $state.current.data.dashboardDesigner + vm.orgId = $stateParams.orgId + + if vm.designerMode != ImpacConfigSvc.dashboardDesigner + ImpacConfigSvc.configureDashboardDesigner(vm.designerMode) + $rootScope.$watch( -> vm.dashboardLoaded diff --git a/src/app/views/impac/impac.html b/src/app/views/impac/impac.html index b6079c1a..67b7e1ce 100644 --- a/src/app/views/impac/impac.html +++ b/src/app/views/impac/impac.html @@ -1,9 +1,13 @@
-
- + diff --git a/src/app/views/organization/organization.html b/src/app/views/organization/organization.html index d118dc1c..69647808 100644 --- a/src/app/views/organization/organization.html +++ b/src/app/views/organization/organization.html @@ -109,4 +109,9 @@

mnoe_admin_panel.dashboard.organization.organization_info

+
+
+ +
+
diff --git a/src/locales/en-AU.json b/src/locales/en-AU.json index ef037ba6..53ffefc4 100644 --- a/src/locales/en-AU.json +++ b/src/locales/en-AU.json @@ -91,6 +91,16 @@ "mnoe_admin_panel.dashboard.customers.connect_app.myob.cancel": "Cancel", "mnoe_admin_panel.dashboard.customers.connect_app.myob.close": "Close", "mnoe_admin_panel.dashboard.customers.connect_app.myob.connect": "Connect", + "mnoe_admin_panel.dashboard.staff_dashboards.title": "Staff Dashboard", + "mnoe_admin_panel.dashboard.staff_dashboards.back_link": "Back to organization", + "mnoe_admin_panel.dashboard.staff_dashboards.widget.list.title": "Staff dashboards", + "mnoe_admin_panel.dashboard.staff_dashboards.widget.list.name": "Name", + "mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.cancel": "Cancel", + "mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.action": "Delete", + "mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.proceed": "Delete Staff Dashboard", + "mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.perform": "Are you sure you want to delete this staff dashboard?", + "mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.toastr.success": "Staff dashboard deleted successfully", + "mnoe_admin_panel.dashboard.staff_dashboards.delete_dashboard.toastr.error": "The staff dashboard could not be deleted", "mnoe_admin_panel.dashboard.dashboard_templates.title": "Dashboard Templates", "mnoe_admin_panel.dashboard.dashboard_templates.back_link": "Back to templates list", "mnoe_admin_panel.dashboard.dashboard_templates.published": "Published",