diff --git a/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js b/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js
index 0a3ddcf57d..5e444a0eed 100644
--- a/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js
+++ b/awx/ui/client/src/organizations/linkout/controllers/organizations-projects.controller.js
@@ -19,6 +19,41 @@ export default ['$scope', '$rootScope', '$log', '$stateParams', 'Rest', 'Alert',
orgBase = GetBasePath('organizations'),
projBase = GetBasePath('projects');
+
+ function updateStatus() {
+ if ($scope.projects) {
+ $scope.projects.forEach(function(project, i) {
+ $scope.projects[i].statusIcon = GetProjectIcon(project.status);
+ $scope.projects[i].statusTip = GetProjectToolTip(project.status);
+ $scope.projects[i].scm_update_tooltip = i18n._("Get latest SCM revision");
+ $scope.projects[i].scm_type_class = "";
+
+ if (project.status === 'failed' && project.summary_fields.last_update && project.summary_fields.last_update.status === 'canceled') {
+ $scope.projects[i].statusTip = i18n._('Canceled. Click for details');
+ }
+
+ if (project.status === 'running' || project.status === 'updating') {
+ $scope.projects[i].scm_update_tooltip = i18n._("SCM update currently running");
+ $scope.projects[i].scm_type_class = "btn-disabled";
+ }
+
+ if ($scope.project_scm_type_options) {
+ $scope.project_scm_type_options.forEach(function(type) {
+ if (type.value === project.scm_type) {
+ $scope.projects[i].scm_type = type.label;
+ if (type.label === 'Manual') {
+ $scope.projects[i].scm_update_tooltip = i18n._('Manual projects do not require an SCM update');
+ $scope.projects[i].scm_type_class = 'btn-disabled';
+ $scope.projects[i].statusTip = 'Not configured for SCM';
+ $scope.projects[i].statusIcon = 'none';
+ }
+ }
+ });
+ }
+ });
+ }
+ }
+
init();
function init() {
@@ -31,35 +66,7 @@ export default ['$scope', '$rootScope', '$log', '$stateParams', 'Rest', 'Alert',
$scope.$on('choicesReadyProjectList', function() {
Wait('stop');
- if ($scope.projects) {
- $scope.projects.forEach(function(project, i) {
- $scope.projects[i].statusIcon = GetProjectIcon(project.status);
- $scope.projects[i].statusTip = GetProjectToolTip(project.status);
- $scope.projects[i].scm_update_tooltip = i18n._("Get latest SCM revision");
- $scope.projects[i].scm_type_class = "";
-
- if (project.status === 'failed' && project.summary_fields.last_update && project.summary_fields.last_update.status === 'canceled') {
- $scope.projects[i].statusTip = i18n._('Canceled. Click for details');
- }
-
- if (project.status === 'running' || project.status === 'updating') {
- $scope.projects[i].scm_update_tooltip = i18n._("SCM update currently running");
- $scope.projects[i].scm_type_class = "btn-disabled";
- }
-
- $scope.project_scm_type_options.forEach(function(type) {
- if (type.value === project.scm_type) {
- $scope.projects[i].scm_type = type.label;
- if (type.label === 'Manual') {
- $scope.projects[i].scm_update_tooltip = i18n._('Manual projects do not require an SCM update');
- $scope.projects[i].scm_type_class = 'btn-disabled';
- $scope.projects[i].statusTip = 'Not configured for SCM';
- $scope.projects[i].statusIcon = 'none';
- }
- }
- });
- });
- }
+ updateStatus();
});
}
@@ -69,9 +76,9 @@ export default ['$scope', '$rootScope', '$log', '$stateParams', 'Rest', 'Alert',
});
$scope.$watchCollection(`${$scope.list.name}`, function() {
- optionsRequestDataProcessing();
- }
- );
+ optionsRequestDataProcessing();
+ updateStatus();
+ });
// iterate over the list and add fields like type label, after the
// OPTIONS request returns, or the list is sorted/paginated/searched
diff --git a/awx/ui/client/src/projects/add/projects-add.controller.js b/awx/ui/client/src/projects/add/projects-add.controller.js
index aaa9fee909..4f2d9a0b5f 100644
--- a/awx/ui/client/src/projects/add/projects-add.controller.js
+++ b/awx/ui/client/src/projects/add/projects-add.controller.js
@@ -7,10 +7,10 @@
export default ['$scope', '$location', '$stateParams', 'GenerateForm',
'ProjectsForm', 'Rest', 'Alert', 'ProcessErrors', 'GetBasePath',
'GetProjectPath', 'GetChoices', 'Wait', '$state', 'CreateSelect2', 'i18n',
- 'CredentialTypes', 'ConfigData',
+ 'CredentialTypes', 'ConfigData', 'resolvedModels',
function($scope, $location, $stateParams, GenerateForm, ProjectsForm, Rest,
Alert, ProcessErrors, GetBasePath, GetProjectPath, GetChoices, Wait, $state,
- CreateSelect2, i18n, CredentialTypes, ConfigData) {
+ CreateSelect2, i18n, CredentialTypes, ConfigData, resolvedModels) {
let form = ProjectsForm(),
base = $location.path().replace(/^\//, '').split('/')[0],
@@ -23,6 +23,9 @@ export default ['$scope', '$location', '$stateParams', 'GenerateForm',
$scope.canEditOrg = true;
const virtualEnvs = ConfigData.custom_virtualenvs || [];
$scope.custom_virtualenvs_options = virtualEnvs;
+
+ const [ProjectModel] = resolvedModels;
+ $scope.canAdd = ProjectModel.options('actions.POST');
Rest.setUrl(GetBasePath('projects'));
Rest.options()
diff --git a/awx/ui/client/src/projects/list/projects-list.controller.js b/awx/ui/client/src/projects/list/projects-list.controller.js
deleted file mode 100644
index 11be31c54c..0000000000
--- a/awx/ui/client/src/projects/list/projects-list.controller.js
+++ /dev/null
@@ -1,342 +0,0 @@
-/*************************************************
- * Copyright (c) 2016 Ansible, Inc.
- *
- * All Rights Reserved
- *************************************************/
-
-export default ['$scope', '$rootScope', '$log', 'Rest', 'Alert',
- 'ProjectList', 'Prompt', 'ProcessErrors', 'GetBasePath', 'ProjectUpdate',
- 'Wait', 'Empty', 'Find', 'GetProjectIcon', 'GetProjectToolTip', '$filter',
- '$state', 'rbacUiControlService', 'Dataset', 'i18n', 'QuerySet', 'ProjectModel',
- 'ProjectsStrings', 'ngToast',
- function($scope, $rootScope, $log, Rest, Alert, ProjectList,
- Prompt, ProcessErrors, GetBasePath, ProjectUpdate, Wait, Empty, Find,
- GetProjectIcon, GetProjectToolTip, $filter, $state, rbacUiControlService,
- Dataset, i18n, qs, Project, ProjectsStrings, ngToast) {
-
- let project = new Project();
-
- var list = ProjectList;
-
- init();
-
- function init() {
- $scope.canAdd = false;
-
- rbacUiControlService.canAdd('projects')
- .then(function(params) {
- $scope.canAdd = params.canAdd;
- });
-
- // search init
- $scope.list = list;
- $scope[`${list.iterator}_dataset`] = Dataset.data;
- $scope[list.name] = $scope[`${list.iterator}_dataset`].results;
-
- _.forEach($scope[list.name], buildTooltips);
- $rootScope.flashMessage = null;
- }
-
- $scope.$on(`${list.iterator}_options`, function(event, data){
- $scope.options = data.data.actions.GET;
- optionsRequestDataProcessing();
- });
-
- $scope.$watchCollection(`${$scope.list.name}`, function() {
- optionsRequestDataProcessing();
- }
- );
-
- // iterate over the list and add fields like type label, after the
- // OPTIONS request returns, or the list is sorted/paginated/searched
- function optionsRequestDataProcessing(){
- if ($scope[list.name] !== undefined) {
- $scope[list.name].forEach(function(item, item_idx) {
- var itm = $scope[list.name][item_idx];
-
- // Set the item type label
- if (list.fields.scm_type && $scope.options &&
- $scope.options.hasOwnProperty('scm_type')) {
- $scope.options.scm_type.choices.forEach(function(choice) {
- if (choice[0] === item.scm_type) {
- itm.type_label = choice[1];
- }
- });
- }
-
- buildTooltips(itm);
-
- });
- }
- }
-
- function buildTooltips(project) {
- project.statusIcon = GetProjectIcon(project.status);
- project.statusTip = GetProjectToolTip(project.status);
- project.scm_update_tooltip = i18n._("Get latest SCM revision");
- project.scm_type_class = "";
-
- if (project.status === 'failed' && project.summary_fields.last_update && project.summary_fields.last_update.status === 'canceled') {
- project.statusTip = i18n._('Canceled. Click for details');
- project.scm_type_class = "btn-disabled";
- }
-
- if (project.status === 'running' || project.status === 'updating') {
- project.scm_update_tooltip = i18n._("SCM update currently running");
- project.scm_type_class = "btn-disabled";
- }
- if (project.scm_type === 'manual') {
- project.scm_update_tooltip = i18n._('Manual projects do not require an SCM update');
- project.scm_type_class = 'btn-disabled';
- project.statusTip = i18n._('Not configured for SCM');
- project.statusIcon = 'none';
- }
- }
-
- $scope.reloadList = function(){
- let path = GetBasePath(list.basePath) || GetBasePath(list.name);
- qs.search(path, $state.params[`${list.iterator}_search`])
- .then(function(searchResponse) {
- $scope[`${list.iterator}_dataset`] = searchResponse.data;
- $scope[list.name] = $scope[`${list.iterator}_dataset`].results;
- });
- };
-
- $scope.$on(`ws-jobs`, function(e, data) {
- var project;
- $log.debug(data);
- if ($scope.projects) {
- // Assuming we have a list of projects available
- project = Find({ list: $scope.projects, key: 'id', val: data.project_id });
- if (project) {
- // And we found the affected project
- $log.debug('Received event for project: ' + project.name);
- $log.debug('Status changed to: ' + data.status);
- if (data.status === 'successful' || data.status === 'failed' || data.status === 'canceled') {
- $scope.reloadList();
- } else {
- project.scm_update_tooltip = i18n._("SCM update currently running");
- project.scm_type_class = "btn-disabled";
- }
- project.status = data.status;
- project.statusIcon = GetProjectIcon(data.status);
- project.statusTip = GetProjectToolTip(data.status);
- }
- }
- });
-
- $scope.addProject = function() {
- $state.go('projects.add');
- };
-
- $scope.editProject = function(id) {
- $state.go('projects.edit', { project_id: id });
- };
-
- if ($scope.removeGoTojobResults) {
- $scope.removeGoTojobResults();
- }
- $scope.removeGoTojobResults = $scope.$on('GoTojobResults', function(e, data) {
- if (data.summary_fields.current_update || data.summary_fields.last_update) {
-
- Wait('start');
-
- // Grab the id from summary_fields
- var id = (data.summary_fields.current_update) ? data.summary_fields.current_update.id : data.summary_fields.last_update.id;
-
- $state.go('output', { id: id, type: 'project'}, { reload: true });
-
- } else {
- Alert(i18n._('No Updates Available'), i18n._('There is no SCM update information available for this project. An update has not yet been ' +
- ' completed. If you have not already done so, start an update for this project.'), 'alert-info');
- }
- });
-
- $scope.copyProject = project => {
- Wait('start');
- new Project('get', project.id)
- .then(model => model.copy())
- .then((copiedProj) => {
- ngToast.success({
- content: `
-
-
-
-
-
- ${ProjectsStrings.get('SUCCESSFUL_CREATION', copiedProj.name)}
-
-
`,
- dismissButton: false,
- dismissOnTimeout: true
- });
- $state.go('.', null, { reload: true });
- })
- .catch(({ data, status }) => {
- const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` };
- ProcessErrors($scope, data, status, null, params);
- })
- .finally(() => Wait('stop'));
- };
-
- $scope.showSCMStatus = function(id) {
- // Refresh the project list
- var project = Find({ list: $scope.projects, key: 'id', val: id });
- if (Empty(project.scm_type) || project.scm_type === 'Manual') {
- Alert(i18n._('No SCM Configuration'), i18n._('The selected project is not configured for SCM. To configure for SCM, edit the project and provide SCM settings, ' +
- 'and then run an update.'), 'alert-info');
- } else {
- // Refresh what we have in memory to insure we're accessing the most recent status record
- Rest.setUrl(project.url);
- Rest.get()
- .then(({data}) => {
- $scope.$emit('GoTojobResults', data);
- })
- .catch(({data, status}) => {
- ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'),
- msg: i18n._('Project lookup failed. GET returned: ') + status });
- });
- }
- };
-
- $scope.deleteProject = function(id, name) {
- var action = function() {
- $('#prompt-modal').modal('hide');
- Wait('start');
- project.request('delete', id)
- .then(() => {
-
- let reloadListStateParams = null;
-
- if($scope.projects.length === 1 && $state.params.project_search && _.has($state, 'params.project_search.page') && $state.params.project_search.page !== '1') {
- reloadListStateParams = _.cloneDeep($state.params);
- reloadListStateParams.project_search.page = (parseInt(reloadListStateParams.project_search.page)-1).toString();
- }
-
- if (parseInt($state.params.project_id) === id) {
- $state.go("^", reloadListStateParams, { reload: true });
- } else {
- $state.go('.', reloadListStateParams, {reload: true});
- }
- })
- .catch(({data, status}) => {
- ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'),
- msg: i18n.sprintf(i18n._('Call to %s failed. DELETE returned status: '), `${project.path}${id}/`) + status });
- })
- .finally(function() {
- Wait('stop');
- });
- };
-
- project.getDependentResourceCounts(id)
- .then((counts) => {
- const invalidateRelatedLines = [];
- let deleteModalBody = `
${ProjectsStrings.get('deleteResource.CONFIRM', 'project')}
`;
-
- counts.forEach(countObj => {
- if(countObj.count && countObj.count > 0) {
- invalidateRelatedLines.push(`
${countObj.label}${countObj.count}
`);
- }
- });
-
- if (invalidateRelatedLines && invalidateRelatedLines.length > 0) {
- deleteModalBody = `
${ProjectsStrings.get('deleteResource.USED_BY', 'project')} ${ProjectsStrings.get('deleteResource.CONFIRM', 'project')}
`;
- invalidateRelatedLines.forEach(invalidateRelatedLine => {
- deleteModalBody += invalidateRelatedLine;
- });
- }
-
- Prompt({
- hdr: i18n._('Delete'),
- resourceName: $filter('sanitize')(name),
- body: deleteModalBody,
- action: action,
- actionText: i18n._('DELETE')
- });
- });
- };
-
- if ($scope.removeCancelUpdate) {
- $scope.removeCancelUpdate();
- }
- $scope.removeCancelUpdate = $scope.$on('Cancel_Update', function(e, url) {
- // Cancel the project update process
- Rest.setUrl(url);
- Rest.post()
- .then(() => {
- Alert(i18n._('SCM Update Cancel'), i18n._('Your request to cancel the update was submitted to the task manager.'), 'alert-info');
- })
- .catch(({data, status}) => {
- ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. POST status: '), url) + status });
- });
- });
-
- if ($scope.removeCheckCancel) {
- $scope.removeCheckCancel();
- }
- $scope.removeCheckCancel = $scope.$on('Check_Cancel', function(e, data) {
- // Check that we 'can' cancel the update
- var url = data.related.cancel;
- Rest.setUrl(url);
- Rest.get()
- .then(({data}) => {
- if (data.can_cancel) {
- $scope.$emit('Cancel_Update', url);
- } else {
- Alert(i18n._('Cancel Not Allowed'), '
' + i18n.sprintf(i18n._('Either you do not have access or the SCM update process completed. ' +
- 'Click the %sRefresh%s button to view the latest status.'), '', '') + '
', 'alert-info', null, null, null, null, true);
- }
- })
- .catch(({data, status}) => {
- ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), msg: i18n.sprintf(i18n._('Call to %s failed. GET status: '), url) + status });
- });
- });
-
- $scope.cancelUpdate = function(project) {
- project.pending_cancellation = true;
- Rest.setUrl(GetBasePath("projects") + project.id);
- Rest.get()
- .then(({data}) => {
- if (data.related.current_update) {
- Rest.setUrl(data.related.current_update);
- Rest.get()
- .then(({data}) => {
- $scope.$emit('Check_Cancel', data);
- })
- .catch(({data, status}) => {
- ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'),
- msg: i18n.sprintf(i18n._('Call to %s failed. GET status: '), data.related.current_update) + status });
- });
- } else {
- Alert(i18n._('Update Not Found'), '
' + i18n.sprintf(i18n._('An SCM update does not appear to be running for project: %s. Click the %sRefresh%s ' +
- 'button to view the latest status.'), $filter('sanitize')(name), '', '') + '
', 'alert-info',undefined,undefined,undefined,undefined,true);
- }
- })
- .catch(({data, status}) => {
- ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'),
- msg: i18n._('Call to get project failed. GET status: ') + status });
- });
- };
-
- $scope.SCMUpdate = function(project_id, event) {
- try {
- $(event.target).tooltip('hide');
- } catch (e) {
- // ignore
- }
- $scope.projects.forEach(function(project) {
- if (project.id === project_id) {
- if (project.scm_type === "Manual" || Empty(project.scm_type)) {
- // Do not respond. Button appears greyed out as if it is disabled. Not disabled though, because we need mouse over event
- // to work. So user can click, but we just won't do anything.
- //Alert('Missing SCM Setup', 'Before running an SCM update, edit the project and provide the SCM access information.', 'alert-info');
- } else if (project.status === 'updating' || project.status === 'running' || project.status === 'pending') {
- // Alert('Update in Progress', 'The SCM update process is running. Use the Refresh button to monitor the status.', 'alert-info');
- } else {
- ProjectUpdate({ scope: $scope, project_id: project.id });
- }
- }
- });
- };
- }
-];
diff --git a/awx/ui/client/src/projects/main.js b/awx/ui/client/src/projects/main.js
index 144fb99b91..ebb3aa7bb9 100644
--- a/awx/ui/client/src/projects/main.js
+++ b/awx/ui/client/src/projects/main.js
@@ -4,12 +4,10 @@
* All Rights Reserved
*************************************************/
-import ProjectsList from './list/projects-list.controller';
import ProjectsAdd from './add/projects-add.controller';
import ProjectsEdit from './edit/projects-edit.controller';
-import ProjectList from './projects.list';
import ProjectsForm from './projects.form';
-import { N_ } from '../i18n';
+import ProjectList from './projects.list';
import GetProjectPath from './factories/get-project-path.factory';
import GetProjectIcon from './factories/get-project-icon.factory';
import GetProjectToolTip from './factories/get-project-tool-tip.factory';
@@ -20,93 +18,60 @@ import {
} from '../scheduler/schedules.route';
import ProjectsTemplatesRoute from '~features/templates/routes/projectsTemplatesList.route';
-import ProjectsStrings from './projects.strings';
+import projectsListRoute from '~features/projects/routes/projectsList.route.js';
export default
angular.module('Projects', [])
- .controller('ProjectsList', ProjectsList)
.controller('ProjectsAdd', ProjectsAdd)
.controller('ProjectsEdit', ProjectsEdit)
.factory('GetProjectPath', GetProjectPath)
.factory('GetProjectIcon', GetProjectIcon)
.factory('GetProjectToolTip', GetProjectToolTip)
- .factory('ProjectList', ProjectList)
.factory('ProjectsForm', ProjectsForm)
- .service('ProjectsStrings', ProjectsStrings)
+ .factory('ProjectList', ProjectList)
.config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider',
function($stateProvider, stateDefinitionsProvider,$stateExtenderProvider) {
let stateDefinitions = stateDefinitionsProvider.$get();
let stateExtender = $stateExtenderProvider.$get();
- var projectResolve = {
- CredentialTypes: ['Rest', '$stateParams', 'GetBasePath', 'ProcessErrors',
- (Rest, $stateParams, GetBasePath, ProcessErrors) => {
- var path = GetBasePath('credential_types');
- Rest.setUrl(path);
- return Rest.get()
- .then(function(data) {
- return (data.data.results);
- }).catch(function(response) {
- ProcessErrors(null, response.data, response.status, null, {
- hdr: 'Error!',
- msg: 'Failed to get credential types. GET returned status: ' +
- response.status
- });
- });
- }
- ],
- ConfigData: ['ConfigService', 'ProcessErrors', (ConfigService, ProcessErrors) => {
- return ConfigService.getConfig()
- .then(response => response)
- .catch(({data, status}) => {
- ProcessErrors(null, data, status, null, {
- hdr: 'Error!',
- msg: 'Failed to get config. GET returned status: ' +
- 'status: ' + status
- });
- });
- }]
- };
function generateStateTree() {
- let projectTree = stateDefinitions.generateTree({
- parent: 'projects', // top-most node in the generated tree (will replace this state definition)
- modes: ['add', 'edit'],
- generateSchedulerView: true,
- list: 'ProjectList',
+ let projectAdd = stateDefinitions.generateTree({
+ name: 'projects.add',
+ url: '/add',
+ modes: ['add'],
form: 'ProjectsForm',
controllers: {
- list: ProjectsList, // DI strings or objects
- add: ProjectsAdd,
- edit: ProjectsEdit
+ add: 'ProjectsAdd',
+ },
+ });
+
+ let projectEdit = stateDefinitions.generateTree({
+ name: 'projects.edit',
+ url: '/:project_id',
+ modes: ['edit'],
+ form: 'ProjectsForm',
+ controllers: {
+ edit: 'ProjectsEdit',
},
data: {
activityStream: true,
activityStreamTarget: 'project',
- socket: {
- "groups": {
- "jobs": ["status_changed"]
- }
- }
+ activityStreamId: 'project_id'
},
- ncyBreadcrumb: {
- label: N_('PROJECTS')
- },
- breadcrumbs: {
+ breadcrumbs: {
edit: '{{breadcrumb.project_name}}'
},
- resolve: {
- add: projectResolve,
- edit: projectResolve
- }
});
return Promise.all([
- projectTree
+ projectAdd,
+ projectEdit,
]).then((generated) => {
return {
states: _.reduce(generated, (result, definition) => {
return result.concat(definition.states);
}, [
+ stateExtender.buildDefinition(projectsListRoute),
stateExtender.buildDefinition(ProjectsTemplatesRoute),
stateExtender.buildDefinition(projectsSchedulesListRoute),
stateExtender.buildDefinition(projectsSchedulesAddRoute),
diff --git a/awx/ui/client/src/projects/projects.list.js b/awx/ui/client/src/projects/projects.list.js
index 64b0ddb4ab..436ee5c3b6 100644
--- a/awx/ui/client/src/projects/projects.list.js
+++ b/awx/ui/client/src/projects/projects.list.js
@@ -5,124 +5,124 @@
*************************************************/
export default ['i18n', function(i18n) {
- return {
+ return {
- name: 'projects',
- iterator: 'project',
- basePath: 'projects',
- selectTitle: i18n._('Add Project'),
- editTitle: i18n._('PROJECTS'),
- listTitle: i18n._('PROJECTS'),
- selectInstructions: '
Select existing projects by clicking each project or checking the related checkbox. When finished, click the blue ' +
- 'Select button, located bottom right.
Create a new project by clicking the button.
',
- index: false,
- hover: true,
- emptyListText: i18n._('No Projects Have Been Created'),
+ name: 'projects',
+ iterator: 'project',
+ basePath: 'projects',
+ selectTitle: i18n._('Add Project'),
+ editTitle: i18n._('PROJECTS'),
+ listTitle: i18n._('PROJECTS'),
+ selectInstructions: '
Select existing projects by clicking each project or checking the related checkbox. When finished, click the blue ' +
+ 'Select button, located bottom right.
Create a new project by clicking the button.
',
+ index: false,
+ hover: true,
+ emptyListText: i18n._('No Projects Have Been Created'),
- fields: {
- status: {
- label: '',
- iconOnly: true,
- ngClick: 'showSCMStatus(project.id)',
- awToolTip: '{{ project.statusTip }}',
- dataTipWatch: 'project.statusTip',
- dataPlacement: 'right',
- icon: "icon-job-{{ project.statusIcon }}",
- columnClass: "List-staticColumn--smallStatus",
- nosort: true,
- excludeModal: true
- },
- name: {
- key: true,
- label: i18n._('Name'),
- columnClass: "col-lg-4 col-md-4 col-sm-4 col-xs-7 List-staticColumnAdjacent",
- modalColumnClass: 'col-md-8',
- awToolTip: '{{project.description | sanitize}}',
- dataPlacement: 'top'
- },
- scm_type: {
- label: i18n._('Type'),
- ngBind: 'project.type_label',
- excludeModal: true,
- columnClass: 'col-lg-2 col-md-2 col-sm-2 hidden-xs'
- },
- scm_revision: {
- label: i18n._('Revision'),
- excludeModal: true,
- columnClass: 'List-tableCell col-lg-2 col-md-2 hidden-sm hidden-xs',
- type: 'revision'
- },
- last_updated: {
- label: i18n._('Last Updated'),
- filter: "longDate",
- columnClass: "col-lg-3 hidden-md hidden-sm hidden-xs",
- excludeModal: true
- }
- },
+ fields: {
+ status: {
+ label: '',
+ iconOnly: true,
+ ngClick: 'showSCMStatus(project.id)',
+ awToolTip: '{{ project.statusTip }}',
+ dataTipWatch: 'project.statusTip',
+ dataPlacement: 'right',
+ icon: "icon-job-{{ project.statusIcon }}",
+ columnClass: "List-staticColumn--smallStatus",
+ nosort: true,
+ excludeModal: true
+ },
+ name: {
+ key: true,
+ label: i18n._('Name'),
+ columnClass: "col-lg-4 col-md-4 col-sm-4 col-xs-7 List-staticColumnAdjacent",
+ modalColumnClass: 'col-md-8',
+ awToolTip: '{{project.description | sanitize}}',
+ dataPlacement: 'top'
+ },
+ scm_type: {
+ label: i18n._('Type'),
+ ngBind: 'project.type_label',
+ excludeModal: true,
+ columnClass: 'col-lg-2 col-md-2 col-sm-2 hidden-xs'
+ },
+ scm_revision: {
+ label: i18n._('Revision'),
+ excludeModal: true,
+ columnClass: 'List-tableCell col-lg-2 col-md-2 hidden-sm hidden-xs',
+ type: 'revision'
+ },
+ last_updated: {
+ label: i18n._('Last Updated'),
+ filter: "longDate",
+ columnClass: "col-lg-3 hidden-md hidden-sm hidden-xs",
+ excludeModal: true
+ }
+ },
- actions: {
- refresh: {
- mode: 'all',
- awToolTip: i18n._("Refresh the page"),
- ngClick: "refresh()",
- ngShow: "socketStatus === 'error'",
- actionClass: 'btn List-buttonDefault',
- buttonContent: i18n._('REFRESH')
- },
- add: {
- mode: 'all', // One of: edit, select, all
- ngClick: 'addProject()',
- awToolTip: i18n._('Create a new project'),
- actionClass: 'at-Button--add',
- actionId: 'button-add',
- ngShow: "canAdd"
- }
- },
+ actions: {
+ refresh: {
+ mode: 'all',
+ awToolTip: i18n._("Refresh the page"),
+ ngClick: "refresh()",
+ ngShow: "socketStatus === 'error'",
+ actionClass: 'btn List-buttonDefault',
+ buttonContent: i18n._('REFRESH')
+ },
+ add: {
+ mode: 'all', // One of: edit, select, all
+ ngClick: 'addProject()',
+ awToolTip: i18n._('Create a new project'),
+ actionClass: 'at-Button--add',
+ actionId: 'button-add',
+ ngShow: "canAdd"
+ }
+ },
- fieldActions: {
+ fieldActions: {
- columnClass: 'col-lg-4 col-md-3 col-sm-4 col-xs-5',
- edit: {
- ngClick: "editProject(project.id)",
- awToolTip: i18n._('Edit the project'),
- dataPlacement: 'top',
- ngShow: "project.summary_fields.user_capabilities.edit"
- },
- scm_update: {
- ngClick: 'SCMUpdate(project.id, $event)',
- awToolTip: "{{ project.scm_update_tooltip }}",
- dataTipWatch: "project.scm_update_tooltip",
- ngClass: "project.scm_type_class",
- dataPlacement: 'top',
- ngShow: "project.summary_fields.user_capabilities.start"
- },
- copy: {
- label: i18n._('Copy'),
- ngClick: 'copyProject(project)',
- "class": 'btn-danger btn-xs',
- awToolTip: i18n._('Copy project'),
- dataPlacement: 'top',
- ngShow: 'project.summary_fields.user_capabilities.copy'
- },
- view: {
- ngClick: "editProject(project.id)",
- awToolTip: i18n._('View the project'),
- dataPlacement: 'top',
- ngShow: "!project.summary_fields.user_capabilities.edit",
- icon: 'fa-eye',
- },
- "delete": {
- ngClick: "deleteProject(project.id, project.name)",
- awToolTip: i18n._('Delete the project'),
- ngShow: "(project.status !== 'updating' && project.status !== 'running' && project.status !== 'pending' && project.status !== 'waiting') && project.summary_fields.user_capabilities.delete",
- dataPlacement: 'top'
- },
- cancel: {
- ngClick: "cancelUpdate(project)",
- awToolTip: i18n._('Cancel the SCM update'),
- ngShow: "(project.status == 'updating' || project.status == 'running' || project.status == 'pending' || project.status == 'waiting') && project.summary_fields.user_capabilities.start",
- dataPlacement: 'top',
- ngDisabled: "project.pending_cancellation || project.status == 'canceled'"
- }
- }
- };}];
+ columnClass: 'col-lg-4 col-md-3 col-sm-4 col-xs-5',
+ edit: {
+ ngClick: "editProject(project.id)",
+ awToolTip: i18n._('Edit the project'),
+ dataPlacement: 'top',
+ ngShow: "project.summary_fields.user_capabilities.edit"
+ },
+ scm_update: {
+ ngClick: 'SCMUpdate(project.id, $event)',
+ awToolTip: "{{ project.scm_update_tooltip }}",
+ dataTipWatch: "project.scm_update_tooltip",
+ ngClass: "project.scm_type_class",
+ dataPlacement: 'top',
+ ngShow: "project.summary_fields.user_capabilities.start"
+ },
+ copy: {
+ label: i18n._('Copy'),
+ ngClick: 'copyProject(project)',
+ "class": 'btn-danger btn-xs',
+ awToolTip: i18n._('Copy project'),
+ dataPlacement: 'top',
+ ngShow: 'project.summary_fields.user_capabilities.copy'
+ },
+ view: {
+ ngClick: "editProject(project.id)",
+ awToolTip: i18n._('View the project'),
+ dataPlacement: 'top',
+ ngShow: "!project.summary_fields.user_capabilities.edit",
+ icon: 'fa-eye',
+ },
+ "delete": {
+ ngClick: "deleteProject(project.id, project.name)",
+ awToolTip: i18n._('Delete the project'),
+ ngShow: "(project.status !== 'updating' && project.status !== 'running' && project.status !== 'pending' && project.status !== 'waiting') && project.summary_fields.user_capabilities.delete",
+ dataPlacement: 'top'
+ },
+ cancel: {
+ ngClick: "cancelUpdate(project)",
+ awToolTip: i18n._('Cancel the SCM update'),
+ ngShow: "(project.status == 'updating' || project.status == 'running' || project.status == 'pending' || project.status == 'waiting') && project.summary_fields.user_capabilities.start",
+ dataPlacement: 'top',
+ ngDisabled: "project.pending_cancellation || project.status == 'canceled'"
+ }
+ }
+ };}];
\ No newline at end of file
diff --git a/awx/ui/client/src/projects/projects.strings.js b/awx/ui/client/src/projects/projects.strings.js
deleted file mode 100644
index 37e4141a7b..0000000000
--- a/awx/ui/client/src/projects/projects.strings.js
+++ /dev/null
@@ -1,7 +0,0 @@
-function ProjectsStrings (BaseString) {
- BaseString.call(this, 'projects');
-}
-
-ProjectsStrings.$inject = ['BaseStringService'];
-
-export default ProjectsStrings;
diff --git a/awx/ui/test/e2e/objects/projects.js b/awx/ui/test/e2e/objects/projects.js
index 85965c4019..345bf1664a 100644
--- a/awx/ui/test/e2e/objects/projects.js
+++ b/awx/ui/test/e2e/objects/projects.js
@@ -56,10 +56,10 @@ module.exports = {
}
},
list: {
- selector: '.Panel',
+ selector: '.at-Panel',
elements: {
- badge: 'span[class~="badge"]',
- title: 'div[class="List-titleText"]',
+ badge: '.at-Panel-headingTitleBadge',
+ title: '.at-Panel-headingTitle',
add: '#button-add'
},
sections: {
diff --git a/awx/ui/test/e2e/objects/sections/search.js b/awx/ui/test/e2e/objects/sections/search.js
index 9feed81554..64fd557da5 100644
--- a/awx/ui/test/e2e/objects/sections/search.js
+++ b/awx/ui/test/e2e/objects/sections/search.js
@@ -2,8 +2,8 @@ const search = {
selector: 'smart-search',
locateStrategy: 'css selector',
elements: {
- clearAll: 'a[class*="clear"]',
- searchButton: 'i[class$="search"]',
+ clearAll: 'a[class*="clearAll"]',
+ searchButton: 'i[class*="fa-search"]',
input: 'input',
tags: '.SmartSearch-tagContainer'
}
diff --git a/awx/ui/test/e2e/tests/test-projects-list-actions.js b/awx/ui/test/e2e/tests/test-projects-list-actions.js
index a252160b85..f01921dad5 100644
--- a/awx/ui/test/e2e/tests/test-projects-list-actions.js
+++ b/awx/ui/test/e2e/tests/test-projects-list-actions.js
@@ -31,7 +31,7 @@ module.exports = {
projects.waitForElementNotVisible('div.spinny');
projects.section.list.expect.element('@badge').text.equal('1');
- projects.expect.element(`#projects_table tr[id="${data.project.id}"]`).visible;
+ projects.expect.element(`#row-${data.project.id}`).visible;
projects.expect.element('i[class*="copy"]').visible;
projects.expect.element('i[class*="copy"]').enabled;
diff --git a/awx/ui/test/e2e/tests/test-xss.js b/awx/ui/test/e2e/tests/test-xss.js
index 6383926709..d33ee0b754 100644
--- a/awx/ui/test/e2e/tests/test-xss.js
+++ b/awx/ui/test/e2e/tests/test-xss.js
@@ -508,36 +508,36 @@ module.exports = {
client.expect.element('#project_form').visible;
},
'check project list for unsanitized content': client => {
- const itemRow = `#projects_table tr[id="${data.project.id}"]`;
- const itemName = `${itemRow} td[class*="name-"] a`;
+ const itemRow = `#row-${data.project.id}`;
+ const itemName = `${itemRow} .at-RowItem-header`;
- client.expect.element('div[class^="Panel"] smart-search').visible;
- client.expect.element('div[class^="Panel"] smart-search input').enabled;
+ client.expect.element('.at-Panel smart-search').visible;
+ client.expect.element('.at-Panel smart-search input').enabled;
- client.sendKeys('div[class^="Panel"] smart-search input', `id:>${data.project.id - 1} id:<${data.project.id + 1}`);
- client.sendKeys('div[class^="Panel"] smart-search input', client.Keys.ENTER);
+ client.sendKeys('.at-Panel smart-search input', `id:>${data.project.id - 1} id:<${data.project.id + 1}`);
+ client.sendKeys('.at-Panel smart-search input', client.Keys.ENTER);
- client.expect.element('div.spinny').visible;
client.expect.element('div.spinny').not.visible;
- client.expect.element('.List-titleBadge').text.equal('1');
+ client.expect.element('.at-Panel-headingTitleBadge').text.equal('1');
client.expect.element(itemName).visible;
- client.moveToElement(itemName, 0, 0, () => {
- client.expect.element(itemName).attribute('aria-describedby');
-
- client.getAttribute(itemName, 'aria-describedby', ({ value }) => {
- const tooltip = `#${value}`;
-
- client.expect.element(tooltip).present;
- client.expect.element(tooltip).visible;
-
- client.expect.element('#xss').not.present;
- client.expect.element('[class=xss]').not.present;
- client.expect.element(tooltip).attribute('innerHTML')
- .contains('<div id="xss" class="xss">test</div>');
- });
- });
+ // TODO: uncomment when tooltips are added
+ // client.moveToElement(itemName, 0, 0, () => {
+ // client.expect.element(itemName).attribute('aria-describedby');
+ //
+ // client.getAttribute(itemName, 'aria-describedby', ({ value }) => {
+ // const tooltip = `#${value}`;
+ //
+ // client.expect.element(tooltip).present;
+ // client.expect.element(tooltip).visible;
+ //
+ // client.expect.element('#xss').not.present;
+ // client.expect.element('[class=xss]').not.present;
+ // client.expect.element(tooltip).attribute('innerHTML')
+ // .contains('<div id="xss" class="xss">test</div>');
+ // });
+ // });
client.click(`${itemRow} i[class*="trash"]`);