diff --git a/awx/ui_next/src/api/models/WorkflowJobTemplates.js b/awx/ui_next/src/api/models/WorkflowJobTemplates.js index 0725a1a3e4..e369d71cc9 100644 --- a/awx/ui_next/src/api/models/WorkflowJobTemplates.js +++ b/awx/ui_next/src/api/models/WorkflowJobTemplates.js @@ -1,7 +1,8 @@ import Base from '../Base'; import SchedulesMixin from '../mixins/Schedules.mixin'; +import NotificationsMixin from '../mixins/Notifications.mixin'; -class WorkflowJobTemplates extends SchedulesMixin(Base) { +class WorkflowJobTemplates extends SchedulesMixin(NotificationsMixin(Base)) { constructor(http) { super(http); this.baseUrl = '/api/v2/workflow_job_templates/'; @@ -46,6 +47,10 @@ class WorkflowJobTemplates extends SchedulesMixin(Base) { params, }); } + + readAccessList(id, params) { + return this.http.get(`${this.baseUrl}${id}/access_list/`, { params }); + } } export default WorkflowJobTemplates; diff --git a/awx/ui_next/src/screens/Project/Project.jsx b/awx/ui_next/src/screens/Project/Project.jsx index 0016acdc39..1f75a05c79 100644 --- a/awx/ui_next/src/screens/Project/Project.jsx +++ b/awx/ui_next/src/screens/Project/Project.jsx @@ -25,8 +25,6 @@ class Project extends Component { contentError: null, isInitialized: false, isNotifAdmin: false, - isAuditorOfThisOrg: false, - isAdminOfThisOrg: false, }; this.loadProject = this.loadProject.bind(this); this.loadProjectAndRoles = this.loadProjectAndRoles.bind(this); @@ -65,22 +63,10 @@ class Project extends Component { role_level: 'notification_admin_role', }), ]); - const [auditorRes, adminRes] = await Promise.all([ - OrganizationsAPI.read({ - id: data.organization, - role_level: 'auditor_role', - }), - OrganizationsAPI.read({ - id: data.organization, - role_level: 'admin_role', - }), - ]); setBreadcrumb(data); this.setState({ project: data, isNotifAdmin: notifAdminRes.data.results.length > 0, - isAuditorOfThisOrg: auditorRes.data.results.length > 0, - isAdminOfThisOrg: adminRes.data.results.length > 0, }); } catch (err) { this.setState({ contentError: err }); @@ -124,15 +110,9 @@ class Project extends Component { hasContentLoading, isInitialized, isNotifAdmin, - isAuditorOfThisOrg, - isAdminOfThisOrg, } = this.state; - - const canSeeNotificationsTab = - me.is_system_auditor || isNotifAdmin || isAuditorOfThisOrg; - const canToggleNotifications = - isNotifAdmin && - (me.is_system_auditor || isAuditorOfThisOrg || isAdminOfThisOrg); + const canSeeNotificationsTab = me.is_system_auditor || isNotifAdmin; + const canToggleNotifications = isNotifAdmin; const tabsArray = [ { name: i18n._(t`Details`), link: `${match.url}/details` }, diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx index a1a29752b0..d00142066c 100644 --- a/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx @@ -12,7 +12,13 @@ import JobList from '@components/JobList'; import RoutedTabs from '@components/RoutedTabs'; import { Schedules } from '@components/Schedule'; import ContentLoading from '@components/ContentLoading'; -import { WorkflowJobTemplatesAPI, CredentialsAPI } from '@api'; +import { ResourceAccessList } from '@components/ResourceAccessList'; +import NotificationList from '@components/NotificationList'; +import { + WorkflowJobTemplatesAPI, + CredentialsAPI, + OrganizationsAPI, +} from '@api'; import WorkflowJobTemplateDetail from './WorkflowJobTemplateDetail'; import WorkflowJobTemplateEdit from './WorkflowJobTemplateEdit'; import { Visualizer } from './WorkflowJobTemplateVisualizer'; @@ -26,6 +32,7 @@ class WorkflowJobTemplate extends Component { hasContentLoading: true, template: null, webhook_key: null, + isNotifAdmin: false, }; this.loadTemplate = this.loadTemplate.bind(this); this.loadSchedules = this.loadSchedules.bind(this); @@ -68,8 +75,15 @@ class WorkflowJobTemplate extends Component { ); data.summary_fields.webhook_credential.kind = name; } - this.setState({ template: data }); + const notifAdminRes = await OrganizationsAPI.read({ + page_size: 1, + role_level: 'notification_admin_role', + }); setBreadcrumb(data); + this.setState({ + template: data, + isNotifAdmin: notifAdminRes.data.results.length > 0, + }); } catch (err) { this.setState({ contentError: err }); } finally { @@ -88,20 +102,30 @@ class WorkflowJobTemplate extends Component { } render() { - const { i18n, location, match, setBreadcrumb } = this.props; + const { i18n, me, location, match, setBreadcrumb } = this.props; const { contentError, hasContentLoading, template, webhook_key, + isNotifAdmin, } = this.state; + const canSeeNotificationsTab = me.is_system_auditor || isNotifAdmin; + const canToggleNotifications = isNotifAdmin; + const tabsArray = [ { name: i18n._(t`Details`), link: `${match.url}/details` }, - { name: i18n._(t`Visualizer`), link: `${match.url}/visualizer` }, - { name: i18n._(t`Completed Jobs`), link: `${match.url}/completed_jobs` }, + { name: i18n._(t`Access`), link: `${match.url}/access` }, ]; + if (canSeeNotificationsTab) { + tabsArray.push({ + name: i18n._(t`Notifications`), + link: `${match.url}/notifications`, + }); + } + if (template) { tabsArray.push({ name: i18n._(t`Schedules`), @@ -109,6 +133,15 @@ class WorkflowJobTemplate extends Component { }); } + tabsArray.push({ + name: i18n._(t`Visualizer`), + link: `${match.url}/visualizer`, + }); + tabsArray.push({ + name: i18n._(t`Completed Jobs`), + link: `${match.url}/completed_jobs`, + }); + tabsArray.forEach((tab, n) => { tab.id = n; }); @@ -174,6 +207,29 @@ class WorkflowJobTemplate extends Component { )} /> )} + {template && ( + ( + + )} + /> + )} + {canSeeNotificationsTab && ( + ( + + )} + /> + )} {template && (