From 4cd2f93c31a3bd2eb3738fa04cecdf2b9d85313e Mon Sep 17 00:00:00 2001 From: mabashian Date: Wed, 8 Nov 2017 16:38:34 -0500 Subject: [PATCH 1/8] Updated delete warnings to indicate resources that may be invalidated as a result of deletion --- .../credentials/credentials.strings.js | 5 + awx/ui/client/index.template.ejs | 2 +- awx/ui/client/lib/models/Base.js | 47 +++++- awx/ui/client/lib/models/Credential.js | 60 +++++++- awx/ui/client/lib/models/CredentialType.js | 29 +++- awx/ui/client/lib/models/Inventory.js | 44 ++++++ awx/ui/client/lib/models/InventoryScript.js | 44 ++++++ awx/ui/client/lib/models/InventorySource.js | 44 ++++++ awx/ui/client/lib/models/JobTemplate.js | 44 ++++++ awx/ui/client/lib/models/Organization.js | 13 +- awx/ui/client/lib/models/Project.js | 64 +++++++++ .../lib/models/WorkflowJobTemplateNode.js | 28 ++++ awx/ui/client/lib/models/index.js | 17 ++- awx/ui/client/lib/models/models.strings.js | 22 +++ .../credential-types.strings.js | 15 ++ .../credential-types/list/list.controller.js | 42 ++++-- awx/ui/client/src/credential-types/main.js | 2 + .../list/credentials-list.controller.js | 39 +++-- .../list/inventory-list.controller.js | 44 ++++-- .../sources/list/sources-list.controller.js | 44 ++++-- .../inventory-hosts.strings.js | 10 ++ .../inventory-scripts.strings.js | 15 ++ .../inventory-scripts/list/list.controller.js | 44 ++++-- awx/ui/client/src/inventory-scripts/main.js | 2 + .../list/organizations-list.controller.js | 2 +- .../projects/list/projects-list.controller.js | 47 ++++-- awx/ui/client/src/projects/main.js | 2 + .../client/src/projects/projects.strings.js | 15 ++ awx/ui/client/src/shared/prompt-dialog.js | 1 + .../list/templates-list.controller.js | 134 ++++++++++-------- awx/ui/client/src/templates/main.js | 2 + .../client/src/templates/templates.strings.js | 17 +++ 32 files changed, 807 insertions(+), 133 deletions(-) create mode 100644 awx/ui/client/lib/models/Inventory.js create mode 100644 awx/ui/client/lib/models/InventoryScript.js create mode 100644 awx/ui/client/lib/models/InventorySource.js create mode 100644 awx/ui/client/lib/models/JobTemplate.js create mode 100644 awx/ui/client/lib/models/Project.js create mode 100644 awx/ui/client/lib/models/WorkflowJobTemplateNode.js create mode 100644 awx/ui/client/lib/models/models.strings.js create mode 100644 awx/ui/client/src/credential-types/credential-types.strings.js create mode 100644 awx/ui/client/src/inventory-scripts/inventory-scripts.strings.js create mode 100644 awx/ui/client/src/projects/projects.strings.js create mode 100644 awx/ui/client/src/templates/templates.strings.js diff --git a/awx/ui/client/features/credentials/credentials.strings.js b/awx/ui/client/features/credentials/credentials.strings.js index 958282aa09..64af74726e 100644 --- a/awx/ui/client/features/credentials/credentials.strings.js +++ b/awx/ui/client/features/credentials/credentials.strings.js @@ -27,6 +27,11 @@ function CredentialsStrings (BaseString) { ns.permissions = { TITLE: t.s('CREDENTIALS PERMISSIONS') }; + + ns.deleteCredential = { + CONFIRM: t.s('Are you sure you want to delete this credential?'), + INVALIDATE: t.s('Doing so will invalidate the following:') + }; } CredentialsStrings.$inject = ['BaseStringService']; diff --git a/awx/ui/client/index.template.ejs b/awx/ui/client/index.template.ejs index f222a054d1..5b082eb6e7 100644 --- a/awx/ui/client/index.template.ejs +++ b/awx/ui/client/index.template.ejs @@ -42,7 +42,7 @@ diff --git a/awx/ui/client/lib/models/Base.js b/awx/ui/client/lib/models/Base.js index 72434e7d8d..854fb72de0 100644 --- a/awx/ui/client/lib/models/Base.js +++ b/awx/ui/client/lib/models/Base.js @@ -77,12 +77,16 @@ function search (params, config) { }); } -function httpGet (resource) { +function httpGet (resource, config) { const req = { method: 'GET', url: this.path }; + if (config && config.params) { + req.params = config.params; + } + if (typeof resource === 'object') { this.model.GET = resource; @@ -143,6 +147,19 @@ function httpOptions (resource) { }); } +function httpDelete (resource) { + const req = { + method: 'DELETE', + url: this.path + }; + + if (resource) { + req.url = `${this.path}${resource}/`; + } + + return $http(req).then(res => res); +} + function options (keys) { return this.find('options', keys); } @@ -349,6 +366,32 @@ function graft (id) { return new this.Constructor('get', item, true); } +function getDependentResourceCounts (id) { + if (this.setDependentResources) { + this.setDependentResources(id); + } else { + return Promise.resolve([]); + } + + const dependentResourcePromises = []; + + this.dependentResources.forEach(dependentResource => { + const config = {}; + + if (dependentResource.params) { + config.params = dependentResource.params; + } + + dependentResourcePromises.push(dependentResource.model.http.get(undefined, config) + .then((val) => ({ + label: dependentResource.model.label, + count: val.data.count + }))); + }); + + return Promise.all(dependentResourcePromises); +} + /** * `create` is called on instantiation of every model. Models can be * instantiated empty or with `GET` and/or `OPTIONS` requests that yield data. @@ -407,12 +450,14 @@ function BaseModel (path, settings) { this.set = set; this.unset = unset; this.extend = extend; + this.getDependentResourceCounts = getDependentResourceCounts; this.http = { get: httpGet.bind(this), options: httpOptions.bind(this), post: httpPost.bind(this), put: httpPut.bind(this), + delete: httpDelete.bind(this) }; this.model = {}; diff --git a/awx/ui/client/lib/models/Credential.js b/awx/ui/client/lib/models/Credential.js index 3b0aafcf3d..0bfac7be07 100644 --- a/awx/ui/client/lib/models/Credential.js +++ b/awx/ui/client/lib/models/Credential.js @@ -1,6 +1,11 @@ const ENCRYPTED_VALUE = '$encrypted$'; let BaseModel; +let ProjectModel; +let JobTemplateModel; +let InventoryModel; +let InventorySourceModel; +let ModelsStrings; function createFormSchema (method, config) { if (!config) { @@ -40,22 +45,73 @@ function assignInputGroupValues (inputs) { }); } +function setDependentResources (id) { + this.dependentResources = [ + { + model: new ProjectModel(), + params: { + credential: id + } + }, + { + model: new JobTemplateModel(), + params: { + credential: id, + ask_credential_on_launch: false + } + }, + { + model: new InventoryModel(), + params: { + insights_credential: id + } + }, + { + model: new InventorySourceModel(), + params: { + credential: id + } + } + ]; +} + function CredentialModel (method, resource, graft) { BaseModel.call(this, 'credentials'); this.Constructor = CredentialModel; this.createFormSchema = createFormSchema.bind(this); this.assignInputGroupValues = assignInputGroupValues.bind(this); + this.setDependentResources = setDependentResources.bind(this); + this.label = ModelsStrings.get('labels.CREDENTIAL'); return this.create(method, resource, graft); } -function CredentialModelLoader (_BaseModel_) { +function CredentialModelLoader ( + _BaseModel_, + _ProjectModel_, + _JobTemplateModel_, + _InventoryModel_, + _InventorySourceModel_, + _ModelsStrings_ +) { BaseModel = _BaseModel_; + ProjectModel = _ProjectModel_; + JobTemplateModel = _JobTemplateModel_; + InventoryModel = _InventoryModel_; + InventorySourceModel = _InventorySourceModel_; + ModelsStrings = _ModelsStrings_; return CredentialModel; } -CredentialModelLoader.$inject = ['BaseModel']; +CredentialModelLoader.$inject = [ + 'BaseModel', + 'ProjectModel', + 'JobTemplateModel', + 'InventoryModel', + 'InventorySourceModel', + 'ModelsStrings' +]; export default CredentialModelLoader; diff --git a/awx/ui/client/lib/models/CredentialType.js b/awx/ui/client/lib/models/CredentialType.js index 334ba234ce..936a1d8bdd 100644 --- a/awx/ui/client/lib/models/CredentialType.js +++ b/awx/ui/client/lib/models/CredentialType.js @@ -1,4 +1,6 @@ let BaseModel; +let CredentialModel; +let ModelsStrings; function categorizeByKind () { const group = {}; @@ -30,22 +32,45 @@ function mergeInputProperties () { }); } +function setDependentResources (id) { + this.dependentResources = [ + { + model: new CredentialModel(), + params: { + credential_type: id + } + } + ]; +} + function CredentialTypeModel (method, resource, graft) { BaseModel.call(this, 'credential_types'); this.Constructor = CredentialTypeModel; this.categorizeByKind = categorizeByKind.bind(this); this.mergeInputProperties = mergeInputProperties.bind(this); + this.setDependentResources = setDependentResources.bind(this); + this.label = ModelsStrings.get('labels.CREDENTIAL_TYPE'); return this.create(method, resource, graft); } -function CredentialTypeModelLoader (_BaseModel_) { +function CredentialTypeModelLoader ( + _BaseModel_, + _CredentialModel_, + _ModelsStrings_ +) { BaseModel = _BaseModel_; + CredentialModel = _CredentialModel_; + ModelsStrings = _ModelsStrings_; return CredentialTypeModel; } -CredentialTypeModelLoader.$inject = ['BaseModel']; +CredentialTypeModelLoader.$inject = [ + 'BaseModel', + 'CredentialModel', + 'ModelsStrings' +]; export default CredentialTypeModelLoader; diff --git a/awx/ui/client/lib/models/Inventory.js b/awx/ui/client/lib/models/Inventory.js new file mode 100644 index 0000000000..b1d5af3f54 --- /dev/null +++ b/awx/ui/client/lib/models/Inventory.js @@ -0,0 +1,44 @@ +let BaseModel; +let JobTemplateModel; +let ModelsStrings; + +function setDependentResources (id) { + this.dependentResources = [ + { + model: new JobTemplateModel(), + params: { + inventory: id + } + } + ]; +} + +function InventoryModel (method, resource, graft) { + BaseModel.call(this, 'inventories'); + + this.Constructor = InventoryModel; + this.setDependentResources = setDependentResources.bind(this); + this.label = ModelsStrings.get('labels.INVENTORY'); + + return this.create(method, resource, graft); +} + +function InventoryModelLoader ( + _BaseModel_, + _JobTemplateModel_, + _ModelsStrings_ +) { + BaseModel = _BaseModel_; + JobTemplateModel = _JobTemplateModel_; + ModelsStrings = _ModelsStrings_; + + return InventoryModel; +} + +InventoryModelLoader.$inject = [ + 'BaseModel', + 'JobTemplateModel', + 'ModelsStrings' +]; + +export default InventoryModelLoader; diff --git a/awx/ui/client/lib/models/InventoryScript.js b/awx/ui/client/lib/models/InventoryScript.js new file mode 100644 index 0000000000..aa37d09efd --- /dev/null +++ b/awx/ui/client/lib/models/InventoryScript.js @@ -0,0 +1,44 @@ +let BaseModel; +let InventorySourceModel; +let ModelsStrings; + +function setDependentResources (id) { + this.dependentResources = [ + { + model: new InventorySourceModel(), + params: { + source_script: id + } + } + ]; +} + +function InventoryScriptModel (method, resource, graft) { + BaseModel.call(this, 'inventory_scripts'); + + this.Constructor = InventoryScriptModel; + this.setDependentResources = setDependentResources.bind(this); + this.label = ModelsStrings.get('labels.INVENTORY_SCRIPT'); + + return this.create(method, resource, graft); +} + +function InventoryScriptModelLoader ( + _BaseModel_, + _InventorySourceModel_, + _ModelsStrings_ +) { + BaseModel = _BaseModel_; + InventorySourceModel = _InventorySourceModel_; + ModelsStrings = _ModelsStrings_; + + return InventoryScriptModel; +} + +InventoryScriptModelLoader.$inject = [ + 'BaseModel', + 'InventorySourceModel', + 'ModelsStrings' +]; + +export default InventoryScriptModelLoader; diff --git a/awx/ui/client/lib/models/InventorySource.js b/awx/ui/client/lib/models/InventorySource.js new file mode 100644 index 0000000000..abde6883fb --- /dev/null +++ b/awx/ui/client/lib/models/InventorySource.js @@ -0,0 +1,44 @@ +let BaseModel; +let WorkflowJobTemplateNodeModel; +let ModelsStrings; + +function setDependentResources (id) { + this.dependentResources = [ + { + model: new WorkflowJobTemplateNodeModel(), + params: { + unified_job_template: id + } + } + ]; +} + +function InventorySourceModel (method, resource, graft) { + BaseModel.call(this, 'inventory_sources'); + + this.Constructor = InventorySourceModel; + this.setDependentResources = setDependentResources.bind(this); + this.label = ModelsStrings.get('labels.INVENTORY_SOURCE'); + + return this.create(method, resource, graft); +} + +function InventorySourceModelLoader ( + _BaseModel_, + _WorkflowJobTemplateNodeModel_, + _ModelsStrings_ +) { + BaseModel = _BaseModel_; + WorkflowJobTemplateNodeModel = _WorkflowJobTemplateNodeModel_; + ModelsStrings = _ModelsStrings_; + + return InventorySourceModel; +} + +InventorySourceModelLoader.$inject = [ + 'BaseModel', + 'WorkflowJobTemplateNodeModel', + 'ModelsStrings' +]; + +export default InventorySourceModelLoader; diff --git a/awx/ui/client/lib/models/JobTemplate.js b/awx/ui/client/lib/models/JobTemplate.js new file mode 100644 index 0000000000..2b0a7ce021 --- /dev/null +++ b/awx/ui/client/lib/models/JobTemplate.js @@ -0,0 +1,44 @@ +let BaseModel; +let WorkflowJobTemplateNodeModel; +let ModelsStrings; + +function setDependentResources (id) { + this.dependentResources = [ + { + model: new WorkflowJobTemplateNodeModel(), + params: { + unified_job_template: id + } + } + ]; +} + +function JobTemplateModel (method, resource, graft) { + BaseModel.call(this, 'job_templates'); + + this.Constructor = JobTemplateModel; + this.setDependentResources = setDependentResources.bind(this); + this.label = ModelsStrings.get('labels.JOB_TEMPLATE'); + + return this.create(method, resource, graft); +} + +function JobTemplateModelLoader ( + _BaseModel_, + _WorkflowJobTemplateNodeModel_, + _ModelsStrings_ +) { + BaseModel = _BaseModel_; + WorkflowJobTemplateNodeModel = _WorkflowJobTemplateNodeModel_; + ModelsStrings = _ModelsStrings_; + + return JobTemplateModel; +} + +JobTemplateModelLoader.$inject = [ + 'BaseModel', + 'WorkflowJobTemplateNodeModel', + 'ModelsStrings' +]; + +export default JobTemplateModelLoader; diff --git a/awx/ui/client/lib/models/Organization.js b/awx/ui/client/lib/models/Organization.js index 53448cd80f..734d547395 100644 --- a/awx/ui/client/lib/models/Organization.js +++ b/awx/ui/client/lib/models/Organization.js @@ -1,19 +1,28 @@ let BaseModel; +let ModelsStrings; function OrganizationModel (method, resource, graft) { BaseModel.call(this, 'organizations'); this.Constructor = OrganizationModel; + this.label = ModelsStrings.get('labels.ORGANIZATION'); return this.create(method, resource, graft); } -function OrganizationModelLoader (_BaseModel_) { +function OrganizationModelLoader ( + _BaseModel_, + _ModelsStrings_ +) { BaseModel = _BaseModel_; + ModelsStrings = _ModelsStrings_; return OrganizationModel; } -OrganizationModelLoader.$inject = ['BaseModel']; +OrganizationModelLoader.$inject = [ + 'BaseModel', + 'ModelsStrings' +]; export default OrganizationModelLoader; diff --git a/awx/ui/client/lib/models/Project.js b/awx/ui/client/lib/models/Project.js new file mode 100644 index 0000000000..63d363bd92 --- /dev/null +++ b/awx/ui/client/lib/models/Project.js @@ -0,0 +1,64 @@ +let BaseModel; +let JobTemplateModel; +let WorkflowJobTemplateNodeModel; +let InventorySourceModel; +let ModelsStrings; + +function setDependentResources (id) { + this.dependentResources = [ + { + model: new JobTemplateModel(), + params: { + project: id + } + }, + { + model: new WorkflowJobTemplateNodeModel(), + params: { + unified_job_template: id + } + }, + { + model: new InventorySourceModel(), + params: { + source_project: id + } + } + ]; +} + +function ProjectModel (method, resource, graft) { + BaseModel.call(this, 'projects'); + + this.Constructor = ProjectModel; + this.setDependentResources = setDependentResources.bind(this); + this.label = ModelsStrings.get('labels.PROJECT'); + + return this.create(method, resource, graft); +} + +function ProjectModelLoader ( + _BaseModel_, + _JobTemplateModel_, + _WorkflowJobTemplateNodeModel_, + _InventorySourceModel_, + _ModelsStrings_ +) { + BaseModel = _BaseModel_; + JobTemplateModel = _JobTemplateModel_; + WorkflowJobTemplateNodeModel = _WorkflowJobTemplateNodeModel_; + InventorySourceModel = _InventorySourceModel_; + ModelsStrings = _ModelsStrings_; + + return ProjectModel; +} + +ProjectModelLoader.$inject = [ + 'BaseModel', + 'JobTemplateModel', + 'WorkflowJobTemplateNodeModel', + 'InventorySourceModel', + 'ModelsStrings' +]; + +export default ProjectModelLoader; diff --git a/awx/ui/client/lib/models/WorkflowJobTemplateNode.js b/awx/ui/client/lib/models/WorkflowJobTemplateNode.js new file mode 100644 index 0000000000..bc5cfdf107 --- /dev/null +++ b/awx/ui/client/lib/models/WorkflowJobTemplateNode.js @@ -0,0 +1,28 @@ +let BaseModel; +let ModelsStrings; + +function WorkflowJobTemplateNodeModel (method, resource, graft) { + BaseModel.call(this, 'workflow_job_template_nodes'); + + this.Constructor = WorkflowJobTemplateNodeModel; + this.label = ModelsStrings.get('labels.WORKFLOW_JOB_TEMPLATE_NODE'); + + return this.create(method, resource, graft); +} + +function WorkflowJobTemplateNodeModelLoader ( + _BaseModel_, + _ModelsStrings_ +) { + BaseModel = _BaseModel_; + ModelsStrings = _ModelsStrings_; + + return WorkflowJobTemplateNodeModel; +} + +WorkflowJobTemplateNodeModelLoader.$inject = [ + 'BaseModel', + 'ModelsStrings' +]; + +export default WorkflowJobTemplateNodeModelLoader; diff --git a/awx/ui/client/lib/models/index.js b/awx/ui/client/lib/models/index.js index 1213463e57..08de2e3786 100644 --- a/awx/ui/client/lib/models/index.js +++ b/awx/ui/client/lib/models/index.js @@ -6,6 +6,14 @@ import Credential from '~models/Credential'; import CredentialType from '~models/CredentialType'; import Me from '~models/Me'; import Organization from '~models/Organization'; +import Project from '~models/Project'; +import JobTemplate from '~models/JobTemplate'; +import WorkflowJobTemplateNode from '~models/WorkflowJobTemplateNode'; +import InventorySource from '~models/InventorySource'; +import Inventory from '~models/Inventory'; +import InventoryScript from '~models/InventoryScript'; + +import ModelsStrings from '~models/models.strings'; const MODULE_NAME = 'at.lib.models'; @@ -18,6 +26,13 @@ angular .service('CredentialModel', Credential) .service('CredentialTypeModel', CredentialType) .service('MeModel', Me) - .service('OrganizationModel', Organization); + .service('OrganizationModel', Organization) + .service('ProjectModel', Project) + .service('JobTemplateModel', JobTemplate) + .service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode) + .service('InventorySourceModel', InventorySource) + .service('InventoryModel', Inventory) + .service('InventoryScriptModel', InventoryScript) + .service('ModelsStrings', ModelsStrings); export default MODULE_NAME; diff --git a/awx/ui/client/lib/models/models.strings.js b/awx/ui/client/lib/models/models.strings.js new file mode 100644 index 0000000000..55b72be5f0 --- /dev/null +++ b/awx/ui/client/lib/models/models.strings.js @@ -0,0 +1,22 @@ +function ModelsStrings (BaseString) { + BaseString.call(this, 'models'); + + const { t } = this; + const ns = this.models; + + ns.labels = { + CREDENTIAL: t.s('Credentials'), + CREDENTIAL_TYPE: t.s('Credential Types'), + INVENTORY: t.s('Inventories'), + INVENTORY_SCRIPT: t.s('Inventory Scripts'), + INVENTORY_SOURCE: t.s('Inventory Sources'), + JOB_TEMPLATE: t.s('Job Templates'), + ORGANIZATION: t.s('Organizations'), + PROJECT: t.s('Projects'), + WORKFLOW_JOB_TEMPLATE_NODE: t.s('Workflow Job Template Nodes') + }; +} + +ModelsStrings.$inject = ['BaseStringService']; + +export default ModelsStrings; diff --git a/awx/ui/client/src/credential-types/credential-types.strings.js b/awx/ui/client/src/credential-types/credential-types.strings.js new file mode 100644 index 0000000000..ec2e478ef2 --- /dev/null +++ b/awx/ui/client/src/credential-types/credential-types.strings.js @@ -0,0 +1,15 @@ +function CredentialTypesStrings (BaseString) { + BaseString.call(this, 'credential_types'); + + let t = this.t; + let ns = this.credential_types; + + ns.deleteCredentialType = { + CONFIRM: t.s('Are you sure you want to delete this credential type?'), + CREDENTIAL_TYPE_IN_USE: t.s('This credential type is currently being used by one or more credentials. Credentials that use this credential type must be deleted before the credential type can be deleted.') + }; +} + +CredentialTypesStrings.$inject = ['BaseStringService']; + +export default CredentialTypesStrings; diff --git a/awx/ui/client/src/credential-types/list/list.controller.js b/awx/ui/client/src/credential-types/list/list.controller.js index 129d415711..db44d738c6 100644 --- a/awx/ui/client/src/credential-types/list/list.controller.js +++ b/awx/ui/client/src/credential-types/list/list.controller.js @@ -5,11 +5,16 @@ *************************************************/ export default ['$rootScope', '$scope', 'Wait', 'CredentialTypesList', - 'GetBasePath', 'Rest', 'ProcessErrors', 'Prompt', '$state', '$filter', 'Dataset', 'rbacUiControlService', 'Alert', '$q', + 'GetBasePath', 'Rest', 'ProcessErrors', 'Prompt', '$state', '$filter', + 'Dataset', 'rbacUiControlService', 'Alert', '$q', 'CredentialTypeModel', + 'CredentialTypesStrings', 'i18n', function( $rootScope, $scope, Wait, CredentialTypesList, - GetBasePath, Rest, ProcessErrors, Prompt, $state, $filter, Dataset, rbacUiControlService, Alert, $q + GetBasePath, Rest, ProcessErrors, Prompt, $state, $filter, + Dataset, rbacUiControlService, Alert, $q, CredentialType, + CredentialTypesStrings, i18n ) { + let credentialType = new CredentialType(); var defaultUrl = GetBasePath('credential_types'), list = CredentialTypesList; @@ -58,8 +63,7 @@ export default ['$rootScope', '$scope', 'Wait', 'CredentialTypesList', $('#prompt-modal').modal('hide'); Wait('start'); var url = defaultUrl + id + '/'; - Rest.setUrl(url); - Rest.destroy() + credentialType.request('delete', id) .then(() => { let reloadListStateParams = null; @@ -83,13 +87,29 @@ export default ['$rootScope', '$scope', 'Wait', 'CredentialTypesList', }); }; - var bodyHtml = '
Are you sure you want to delete the credential type below?
' + $filter('sanitize')(name) + '
'; - Prompt({ - hdr: 'Delete', - body: bodyHtml, - action: action, - actionText: 'DELETE' - }); + credentialType.getDependentResourceCounts(id) + .then((counts) => { + let credentialTypeInUse = false; + let deleteModalBody = `
${CredentialTypesStrings.get('deleteCredentialType.CONFIRM')}
`; + + counts.forEach(countObj => { + if(countObj.count && countObj.count > 0) { + credentialTypeInUse = true; + } + }); + + if (credentialTypeInUse) { + deleteModalBody = `
${CredentialTypesStrings.get('deleteCredentialType.CREDENTIAL_TYPE_IN_USE')}
`; + } + + Prompt({ + hdr: i18n._('Delete') + ' ' + $filter('sanitize')(name), + body: deleteModalBody, + action: action, + hideActionButton: credentialTypeInUse ? true : false, + actionText: 'DELETE' + }); + }); }; $scope.addCredentialType = function() { diff --git a/awx/ui/client/src/credential-types/main.js b/awx/ui/client/src/credential-types/main.js index be36639928..0f2ce9f186 100644 --- a/awx/ui/client/src/credential-types/main.js +++ b/awx/ui/client/src/credential-types/main.js @@ -10,6 +10,7 @@ import credentialTypesEdit from './edit/main'; import list from './credential-types.list'; import form from './credential-types.form'; import { N_ } from '../i18n'; +import CredentialTypesStrings from './credential-types.strings'; export default angular.module('credentialTypes', [ @@ -19,6 +20,7 @@ angular.module('credentialTypes', [ ]) .factory('CredentialTypesList', list) .factory('CredentialTypesForm', form) + .service('CredentialTypesStrings', CredentialTypesStrings) .config(['$stateProvider', 'stateDefinitionsProvider', function($stateProvider, stateDefinitionsProvider) { let stateDefinitions = stateDefinitionsProvider.$get(); diff --git a/awx/ui/client/src/credentials/list/credentials-list.controller.js b/awx/ui/client/src/credentials/list/credentials-list.controller.js index 798ce5b024..efb3bfb9d1 100644 --- a/awx/ui/client/src/credentials/list/credentials-list.controller.js +++ b/awx/ui/client/src/credentials/list/credentials-list.controller.js @@ -6,9 +6,12 @@ export default ['$scope', 'Rest', 'CredentialList', 'Prompt', 'ProcessErrors', 'GetBasePath', 'Wait', '$state', '$filter', 'rbacUiControlService', 'Dataset', 'credentialType', 'i18n', + 'CredentialModel', 'CredentialsStrings', function($scope, Rest, CredentialList, Prompt, ProcessErrors, GetBasePath, Wait, $state, $filter, rbacUiControlService, Dataset, - credentialType, i18n) { + credentialType, i18n, Credential, CredentialsStrings) { + + let credential = new Credential(); var list = CredentialList, defaultUrl = GetBasePath('credentials'); @@ -83,8 +86,7 @@ export default ['$scope', 'Rest', 'CredentialList', 'Prompt', 'ProcessErrors', ' $('#prompt-modal').modal('hide'); Wait('start'); var url = defaultUrl + id + '/'; - Rest.setUrl(url); - Rest.destroy() + credential.request('delete', id) .then(() => { let reloadListStateParams = null; @@ -109,12 +111,31 @@ export default ['$scope', 'Rest', 'CredentialList', 'Prompt', 'ProcessErrors', ' }); }; - Prompt({ - hdr: i18n._('Delete'), - body: '
' + i18n._('Are you sure you want to delete the credential below?') + '
' + $filter('sanitize')(name) + '
', - action: action, - actionText: i18n._('DELETE') - }); + credential.getDependentResourceCounts(id) + .then((counts) => { + const invalidateRelatedLines = []; + let deleteModalBody = `
${CredentialsStrings.get('deleteCredential.CONFIRM')}
`; + + counts.forEach(countObj => { + if(countObj.count && countObj.count > 0) { + invalidateRelatedLines.push(`
${countObj.label} ${countObj.count}
`); + } + }); + + if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { + deleteModalBody = `
${CredentialsStrings.get('deleteCredential.CONFIRM')} ${CredentialsStrings.get('deleteCredential.INVALIDATE')}
`; + invalidateRelatedLines.forEach(invalidateRelatedLine => { + deleteModalBody += invalidateRelatedLine; + }); + } + + Prompt({ + hdr: i18n._('Delete') + ' ' + $filter('sanitize')(name), + body: deleteModalBody, + action: action, + actionText: 'DELETE' + }); + }); }; } ]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js index f55bd351e0..1653946a56 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js @@ -13,7 +13,9 @@ function InventoriesList($scope, $filter, Rest, InventoryList, Prompt, ProcessErrors, GetBasePath, Wait, $state, - Dataset, canAdd, i18n) { + Dataset, canAdd, i18n, Inventory, InventoryHostsStrings) { + + let inventory = new Inventory(); let list = InventoryList, defaultUrl = GetBasePath('inventory'); @@ -83,8 +85,7 @@ function InventoriesList($scope, var url = defaultUrl + id + '/'; Wait('start'); $('#prompt-modal').modal('hide'); - Rest.setUrl(url); - Rest.destroy() + inventory.request('delete', id) .then(() => { Wait('stop'); }) @@ -95,13 +96,33 @@ function InventoriesList($scope, }); }; - Prompt({ - hdr: 'Delete', - body: '
' + i18n._('Are you sure you want to delete the inventory below?') + '
' + $filter('sanitize')(name) + '
' + - '
Note: ' + i18n._('The inventory will be in a pending status until the final delete is processed.') + '
', - action: action, - actionText: i18n._('DELETE') - }); + inventory.getDependentResourceCounts(id) + .then((counts) => { + const invalidateRelatedLines = []; + let deleteModalBody = `
${InventoryHostsStrings.get('deleteInventory.CONFIRM')}
`; + + counts.forEach(countObj => { + if(countObj.count && countObj.count > 0) { + invalidateRelatedLines.push(`
${countObj.label} ${countObj.count}
`); + } + }); + + if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { + deleteModalBody = `
${InventoryHostsStrings.get('deleteInventory.CONFIRM')} ${InventoryHostsStrings.get('deleteInventory.INVALIDATE')}
`; + invalidateRelatedLines.forEach(invalidateRelatedLine => { + deleteModalBody += invalidateRelatedLine; + }); + } + + deleteModalBody += '
Note: ' + i18n._('The inventory will be in a pending status until the final delete is processed.') + '
'; + + Prompt({ + hdr: i18n._('Delete') + ' ' + $filter('sanitize')(name), + body: deleteModalBody, + action: action, + actionText: 'DELETE' + }); + }); }; $scope.$on(`ws-inventories`, function(e, data){ @@ -129,5 +150,6 @@ function InventoriesList($scope, export default ['$scope', '$filter', 'Rest', 'InventoryList', 'Prompt', 'ProcessErrors', 'GetBasePath', 'Wait', - '$state', 'Dataset', 'canAdd', 'i18n', InventoriesList + '$state', 'Dataset', 'canAdd', 'i18n', 'InventoryModel', + 'InventoryHostsStrings', InventoriesList ]; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js index 0d806bb4e3..d606a01b8d 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/list/sources-list.controller.js @@ -9,12 +9,15 @@ 'ViewUpdateStatus', 'rbacUiControlService', 'GetBasePath', 'GetSyncStatusMsg', 'Dataset', 'Find', 'QuerySet', 'inventoryData', '$filter', 'Prompt', 'Wait', 'SourcesService', 'inventorySourceOptions', - 'canAdd', 'hasSyncableSources', 'i18n', + 'canAdd', 'hasSyncableSources', 'i18n', 'InventoryHostsStrings', 'InventorySourceModel', function($scope, $rootScope, $state, $stateParams, SourcesListDefinition, InventoryUpdate, CancelSourceUpdate, ViewUpdateStatus, rbacUiControlService, GetBasePath, GetSyncStatusMsg, Dataset, Find, qs, inventoryData, $filter, Prompt, - Wait, SourcesService, inventorySourceOptions, canAdd, hasSyncableSources, i18n){ + Wait, SourcesService, inventorySourceOptions, canAdd, hasSyncableSources, i18n, + InventoryHostsStrings, InventorySource){ + + let inventorySource = new InventorySource(); let list = SourcesListDefinition; var inventory_source; @@ -117,7 +120,6 @@ $state.go('inventories.edit.inventory_sources.edit', {inventory_source_id: id}); }; $scope.deleteSource = function(inventory_source){ - var body = '
' + i18n._('Are you sure you want to permanently delete the inventory source below from the inventory?') + '
' + $filter('sanitize')(inventory_source.name) + '
'; var action = function(){ delete $rootScope.promptActionBtnClass; Wait('start'); @@ -137,14 +139,34 @@ Wait('stop'); }); }; - // Prompt depends on having $rootScope.promptActionBtnClass available... - Prompt({ - hdr: i18n._('Delete Source'), - body: body, - action: action, - actionText: i18n._('DELETE'), - }); - $rootScope.promptActionBtnClass = 'Modal-errorButton'; + + inventorySource.getDependentResourceCounts(inventory_source.id) + .then((counts) => { + const invalidateRelatedLines = []; + let deleteModalBody = `
${InventoryHostsStrings.get('deleteSource.CONFIRM')}
`; + + counts.forEach(countObj => { + if(countObj.count && countObj.count > 0) { + invalidateRelatedLines.push(`
${countObj.label} ${countObj.count}
`); + } + }); + + if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { + deleteModalBody = `
${InventoryHostsStrings.get('deleteSource.CONFIRM')} ${InventoryHostsStrings.get('deleteSource.INVALIDATE')}
`; + invalidateRelatedLines.forEach(invalidateRelatedLine => { + deleteModalBody += invalidateRelatedLine; + }); + } + + Prompt({ + hdr: i18n._('Delete Source') + ' ' + $filter('sanitize')(inventory_source.name), + body: deleteModalBody, + action: action, + actionText: 'DELETE' + }); + $rootScope.promptActionBtnClass = 'Modal-errorButton'; + }); + }; $scope.updateSource = function(inventory_source) { diff --git a/awx/ui/client/src/inventories-hosts/inventory-hosts.strings.js b/awx/ui/client/src/inventories-hosts/inventory-hosts.strings.js index c64b73a933..0744be46db 100644 --- a/awx/ui/client/src/inventories-hosts/inventory-hosts.strings.js +++ b/awx/ui/client/src/inventories-hosts/inventory-hosts.strings.js @@ -4,6 +4,16 @@ function InventoryHostsStrings (BaseString) { let t = this.t; let ns = this['inventory-hosts']; + ns.deleteInventory = { + CONFIRM: t.s('Are you sure you want to delete this inventory?'), + INVALIDATE: t.s('Doing so will invalidate the following:') + }; + + ns.deleteSource = { + CONFIRM: t.s('Are you sure you want to delete this inventory source?'), + INVALIDATE: t.s('Doing so will invalidate the following:') + }; + ns.deletegroup = { GROUP: count => t.p(count, 'group', 'groups'), HOST: count => t.p(count, 'host', 'hosts'), diff --git a/awx/ui/client/src/inventory-scripts/inventory-scripts.strings.js b/awx/ui/client/src/inventory-scripts/inventory-scripts.strings.js new file mode 100644 index 0000000000..9b3fccd4af --- /dev/null +++ b/awx/ui/client/src/inventory-scripts/inventory-scripts.strings.js @@ -0,0 +1,15 @@ +function InventoryScriptsStrings (BaseString) { + BaseString.call(this, 'inventory_scripts'); + + let t = this.t; + let ns = this.inventory_scripts; + + ns.deleteInventoryScript = { + CONFIRM: t.s('Are you sure you want to delete this inventory script?'), + INVALIDATE: t.s('Doing so will invalidate the following:') + }; +} + +InventoryScriptsStrings.$inject = ['BaseStringService']; + +export default InventoryScriptsStrings; diff --git a/awx/ui/client/src/inventory-scripts/list/list.controller.js b/awx/ui/client/src/inventory-scripts/list/list.controller.js index 979d6fc2e0..8f8156951e 100644 --- a/awx/ui/client/src/inventory-scripts/list/list.controller.js +++ b/awx/ui/client/src/inventory-scripts/list/list.controller.js @@ -5,11 +5,16 @@ *************************************************/ export default ['$rootScope', '$scope', 'Wait', 'InventoryScriptsList', - 'GetBasePath', 'Rest', 'ProcessErrors', 'Prompt', '$state', '$filter', 'Dataset', 'rbacUiControlService', + 'GetBasePath', 'Rest', 'ProcessErrors', 'Prompt', '$state', '$filter', + 'Dataset', 'rbacUiControlService', 'InventoryScriptModel', 'InventoryScriptsStrings', + 'i18n', function( $rootScope, $scope, Wait, InventoryScriptsList, - GetBasePath, Rest, ProcessErrors, Prompt, $state, $filter, Dataset, rbacUiControlService + GetBasePath, Rest, ProcessErrors, Prompt, $state, $filter, + Dataset, rbacUiControlService, InventoryScript, InventoryScriptsStrings, + i18n ) { + let inventoryScript = new InventoryScript(); var defaultUrl = GetBasePath('inventory_scripts'), list = InventoryScriptsList; @@ -48,8 +53,7 @@ export default ['$rootScope', '$scope', 'Wait', 'InventoryScriptsList', $('#prompt-modal').modal('hide'); Wait('start'); var url = defaultUrl + id + '/'; - Rest.setUrl(url); - Rest.destroy() + inventoryScript.request('delete', id) .then(() => { let reloadListStateParams = null; @@ -73,13 +77,31 @@ export default ['$rootScope', '$scope', 'Wait', 'InventoryScriptsList', }); }; - var bodyHtml = '
Are you sure you want to delete the inventory script below?
' + $filter('sanitize')(name) + '
'; - Prompt({ - hdr: 'Delete', - body: bodyHtml, - action: action, - actionText: 'DELETE' - }); + inventoryScript.getDependentResourceCounts(id) + .then((counts) => { + const invalidateRelatedLines = []; + let deleteModalBody = `
${InventoryScriptsStrings.get('deleteInventoryScript.CONFIRM')}
`; + + counts.forEach(countObj => { + if(countObj.count && countObj.count > 0) { + invalidateRelatedLines.push(`
${countObj.label} ${countObj.count}
`); + } + }); + + if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { + deleteModalBody = `
${InventoryScriptsStrings.get('deleteInventoryScript.CONFIRM')} ${InventoryScriptsStrings.get('deleteInventoryScript.INVALIDATE')}
`; + invalidateRelatedLines.forEach(invalidateRelatedLine => { + deleteModalBody += invalidateRelatedLine; + }); + } + + Prompt({ + hdr: i18n._('Delete') + ' ' + $filter('sanitize')(name), + body: deleteModalBody, + action: action, + actionText: 'DELETE' + }); + }); }; $scope.addCustomInv = function() { diff --git a/awx/ui/client/src/inventory-scripts/main.js b/awx/ui/client/src/inventory-scripts/main.js index ec7d3e9a94..4854878bca 100644 --- a/awx/ui/client/src/inventory-scripts/main.js +++ b/awx/ui/client/src/inventory-scripts/main.js @@ -10,6 +10,7 @@ import inventoryScriptsEdit from './edit/main'; import list from './inventory-scripts.list'; import form from './inventory-scripts.form'; import { N_ } from '../i18n'; +import InventoryScriptsStrings from './inventory-scripts.strings'; export default angular.module('inventoryScripts', [ @@ -19,6 +20,7 @@ angular.module('inventoryScripts', [ ]) .factory('InventoryScriptsList', list) .factory('InventoryScriptsForm', form) + .service('InventoryScriptsStrings', InventoryScriptsStrings) .config(['$stateProvider', 'stateDefinitionsProvider', function($stateProvider, stateDefinitionsProvider) { let stateDefinitions = stateDefinitionsProvider.$get(); diff --git a/awx/ui/client/src/organizations/list/organizations-list.controller.js b/awx/ui/client/src/organizations/list/organizations-list.controller.js index 9cbe175efc..dd938c5f47 100644 --- a/awx/ui/client/src/organizations/list/organizations-list.controller.js +++ b/awx/ui/client/src/organizations/list/organizations-list.controller.js @@ -169,7 +169,7 @@ export default ['$stateParams', '$scope', '$rootScope', Prompt({ hdr: i18n._('Delete'), - body: '
' + i18n._('Are you sure you want to delete the organization below?') + '
' + $filter('sanitize')(name) + '
', + body: '
' + i18n._('Are you sure you want to delete the organization below? This makes everything in this organization unavailable.') + '
' + $filter('sanitize')(name) + '
', action: action, actionText: i18n._('DELETE') }); diff --git a/awx/ui/client/src/projects/list/projects-list.controller.js b/awx/ui/client/src/projects/list/projects-list.controller.js index 0e7d50f240..32f0c13179 100644 --- a/awx/ui/client/src/projects/list/projects-list.controller.js +++ b/awx/ui/client/src/projects/list/projects-list.controller.js @@ -7,14 +7,16 @@ export default ['$scope', '$rootScope', '$log', 'Rest', 'Alert', 'ProjectList', 'Prompt', 'ProcessErrors', 'GetBasePath', 'ProjectUpdate', 'Wait', 'Empty', 'Find', 'GetProjectIcon', 'GetProjectToolTip', '$filter', - '$state', 'rbacUiControlService', 'Dataset', 'i18n', 'QuerySet', + '$state', 'rbacUiControlService', 'Dataset', 'i18n', 'QuerySet', 'ProjectModel', + 'ProjectsStrings', function($scope, $rootScope, $log, Rest, Alert, ProjectList, Prompt, ProcessErrors, GetBasePath, ProjectUpdate, Wait, Empty, Find, GetProjectIcon, GetProjectToolTip, $filter, $state, rbacUiControlService, - Dataset, i18n, qs) { + Dataset, i18n, qs, Project, ProjectsStrings) { - var list = ProjectList, - defaultUrl = GetBasePath('projects'); + let project = new Project(); + + var list = ProjectList; init(); @@ -176,9 +178,7 @@ export default ['$scope', '$rootScope', '$log', 'Rest', 'Alert', var action = function() { $('#prompt-modal').modal('hide'); Wait('start'); - var url = defaultUrl + id + '/'; - Rest.setUrl(url); - Rest.destroy() + project.request('delete', id) .then(() => { let reloadListStateParams = null; @@ -196,19 +196,38 @@ export default ['$scope', '$rootScope', '$log', 'Rest', 'Alert', }) .catch(({data, status}) => { ProcessErrors($scope, data, status, null, { hdr: i18n._('Error!'), - msg: i18n.sprintf(i18n._('Call to %s failed. DELETE returned status: '), url) + status }); + msg: i18n.sprintf(i18n._('Call to %s failed. DELETE returned status: '), `${project.path}${id}/`) + status }); }) .finally(function() { Wait('stop'); }); }; - Prompt({ - hdr: i18n._('Delete'), - body: '
' + i18n._('Are you sure you want to delete the project below?') + '
' + '
' + $filter('sanitize')(name) + '
', - action: action, - actionText: 'DELETE' - }); + project.getDependentResourceCounts(id) + .then((counts) => { + const invalidateRelatedLines = []; + let deleteModalBody = `
${ProjectsStrings.get('deleteProject.CONFIRM')}
`; + + counts.forEach(countObj => { + if(countObj.count && countObj.count > 0) { + invalidateRelatedLines.push(`
${countObj.label} ${countObj.count}
`); + } + }); + + if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { + deleteModalBody = `
${ProjectsStrings.get('deleteProject.CONFIRM')} ${ProjectsStrings.get('deleteProject.INVALIDATE')}
`; + invalidateRelatedLines.forEach(invalidateRelatedLine => { + deleteModalBody += invalidateRelatedLine; + }); + } + + Prompt({ + hdr: i18n._('Delete') + ' ' + $filter('sanitize')(name), + body: deleteModalBody, + action: action, + actionText: 'DELETE' + }); + }); }; if ($scope.removeCancelUpdate) { diff --git a/awx/ui/client/src/projects/main.js b/awx/ui/client/src/projects/main.js index e5534b4a79..25e6eeaea1 100644 --- a/awx/ui/client/src/projects/main.js +++ b/awx/ui/client/src/projects/main.js @@ -14,6 +14,7 @@ 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'; import ProjectsTemplatesRoute from './projects-templates.route'; +import ProjectsStrings from './projects.strings'; export default angular.module('Projects', []) @@ -25,6 +26,7 @@ angular.module('Projects', []) .factory('GetProjectToolTip', GetProjectToolTip) .factory('ProjectList', ProjectList) .factory('ProjectsForm', ProjectsForm) + .service('ProjectsStrings', ProjectsStrings) .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', function($stateProvider, stateDefinitionsProvider,$stateExtenderProvider) { let stateDefinitions = stateDefinitionsProvider.$get(); diff --git a/awx/ui/client/src/projects/projects.strings.js b/awx/ui/client/src/projects/projects.strings.js new file mode 100644 index 0000000000..84566d12e7 --- /dev/null +++ b/awx/ui/client/src/projects/projects.strings.js @@ -0,0 +1,15 @@ +function ProjectsStrings (BaseString) { + BaseString.call(this, 'projects'); + + let t = this.t; + let ns = this.projects; + + ns.deleteProject = { + CONFIRM: t.s('Are you sure you want to delete this project?'), + INVALIDATE: t.s('Doing so will invalidate the following:') + }; +} + +ProjectsStrings.$inject = ['BaseStringService']; + +export default ProjectsStrings; diff --git a/awx/ui/client/src/shared/prompt-dialog.js b/awx/ui/client/src/shared/prompt-dialog.js index 96152c0b89..dcb1812f78 100644 --- a/awx/ui/client/src/shared/prompt-dialog.js +++ b/awx/ui/client/src/shared/prompt-dialog.js @@ -42,6 +42,7 @@ angular.module('PromptDialog', ['Utilities']) scope.promptBody = params.body; scope.promptAction = params.action; scope.promptActionText = (params.actionText === null || params.actionText === undefined || params.actionText === '') ? 'YES' : params.actionText; + scope.hideActionButton = params.hideActionButton ? true : false; local_backdrop = (params.backdrop === undefined) ? "static" : params.backdrop; diff --git a/awx/ui/client/src/templates/list/templates-list.controller.js b/awx/ui/client/src/templates/list/templates-list.controller.js index b400ec66ed..9ecdecdd9d 100644 --- a/awx/ui/client/src/templates/list/templates-list.controller.js +++ b/awx/ui/client/src/templates/list/templates-list.controller.js @@ -8,14 +8,16 @@ export default ['$scope', '$rootScope', 'Alert','TemplateList', 'Prompt', 'ProcessErrors', 'GetBasePath', 'InitiatePlaybookRun', 'Wait', '$state', '$filter', 'Dataset', 'rbacUiControlService', 'TemplatesService','QuerySet', - 'TemplateCopyService', 'i18n', + 'TemplateCopyService', 'i18n', 'JobTemplateModel', 'TemplatesStrings', function( $scope, $rootScope, Alert, TemplateList, Prompt, ProcessErrors, GetBasePath, InitiatePlaybookRun, Wait, $state, $filter, Dataset, rbacUiControlService, TemplatesService, - qs, TemplateCopyService, i18n + qs, TemplateCopyService, i18n, JobTemplate, TemplatesStrings ) { + let jobTemplate = new JobTemplate(); + var list = TemplateList; init(); @@ -98,65 +100,85 @@ export default ['$scope', '$rootScope', $scope.deleteJobTemplate = function(template) { if(template) { - Prompt({ - hdr: i18n._('Delete'), - body: `
${i18n._("Are you sure you want to delete the template below?")}
${$filter('sanitize')(template.name)}
`, - action: function() { + var action = function() { + function handleSuccessfulDelete(isWorkflow) { + let stateParamId = isWorkflow ? $state.params.workflow_job_template_id : $state.params.job_template_id; - function handleSuccessfulDelete(isWorkflow) { - let stateParamId = isWorkflow ? $state.params.workflow_job_template_id : $state.params.job_template_id; + let reloadListStateParams = null; - let reloadListStateParams = null; + if($scope.templates.length === 1 && $state.params.template_search && !_.isEmpty($state.params.template_search.page) && $state.params.template_search.page !== '1') { + reloadListStateParams = _.cloneDeep($state.params); + reloadListStateParams.template_search.page = (parseInt(reloadListStateParams.template_search.page)-1).toString(); + } - if($scope.templates.length === 1 && $state.params.template_search && !_.isEmpty($state.params.template_search.page) && $state.params.template_search.page !== '1') { - reloadListStateParams = _.cloneDeep($state.params); - reloadListStateParams.template_search.page = (parseInt(reloadListStateParams.template_search.page)-1).toString(); - } + if (parseInt(stateParamId) === template.id) { + // Move the user back to the templates list + $state.go("templates", reloadListStateParams, {reload: true}); + } else { + $state.go(".", reloadListStateParams, {reload: true}); + } + Wait('stop'); + } - if (parseInt(stateParamId) === template.id) { - // Move the user back to the templates list - $state.go("templates", reloadListStateParams, {reload: true}); - } else { - $state.go(".", reloadListStateParams, {reload: true}); - } - Wait('stop'); - } + $('#prompt-modal').modal('hide'); + Wait('start'); + if(template.type && (template.type === 'Workflow Job Template' || template.type === 'workflow_job_template')) { + TemplatesService.deleteWorkflowJobTemplate(template.id) + .then(function () { + handleSuccessfulDelete(true); + }) + .catch(function (response) { + Wait('stop'); + ProcessErrors($scope, response.data, response.status, null, { hdr: 'Error!', + msg: 'Call to delete workflow job template failed. DELETE returned status: ' + response.status + '.'}); + }); + } + else if(template.type && (template.type === 'Job Template' || template.type === 'job_template')) { + TemplatesService.deleteJobTemplate(template.id) + .then(function () { + handleSuccessfulDelete(); + }) + .catch(function (response) { + Wait('stop'); + ProcessErrors($scope, response.data, response.status, null, { hdr: 'Error!', + msg: 'Call to delete job template failed. DELETE returned status: ' + response.status + '.'}); + }); + } + else { + Wait('stop'); + Alert('Error: Unable to determine template type', 'We were unable to determine this template\'s type while deleting.'); + } + }; - $('#prompt-modal').modal('hide'); - Wait('start'); - if(template.type && (template.type === 'Workflow Job Template' || template.type === 'workflow_job_template')) { - TemplatesService.deleteWorkflowJobTemplate(template.id) - .then(function () { - handleSuccessfulDelete(true); - }) - .catch(function (response) { - Wait('stop'); - ProcessErrors($scope, response.data, response.status, null, { hdr: 'Error!', - msg: 'Call to delete workflow job template failed. DELETE returned status: ' + response.status + '.'}); - }); - } - else if(template.type && (template.type === 'Job Template' || template.type === 'job_template')) { - TemplatesService.deleteJobTemplate(template.id) - .then(function () { - handleSuccessfulDelete(); - }) - .catch(function (response) { - Wait('stop'); - ProcessErrors($scope, response.data, response.status, null, { hdr: 'Error!', - msg: 'Call to delete job template failed. DELETE returned status: ' + response.status + '.'}); - }); - } - else { - Wait('stop'); - Alert('Error: Unable to determine template type', 'We were unable to determine this template\'s type while deleting.'); - } - }, - actionText: i18n._('DELETE') - }); - } - else { - Alert('Error: Unable to delete template', 'Template parameter is missing'); - } + jobTemplate.getDependentResourceCounts(template.id) + .then((counts) => { + const invalidateRelatedLines = []; + let deleteModalBody = `
${TemplatesStrings.get('jobTemplates.deleteJobTemplate.CONFIRM')}
`; + + counts.forEach(countObj => { + if(countObj.count && countObj.count > 0) { + invalidateRelatedLines.push(`
${countObj.label} ${countObj.count}
`); + } + }); + + if (invalidateRelatedLines && invalidateRelatedLines.length > 0) { + deleteModalBody = `
${TemplatesStrings.get('jobTemplates.deleteJobTemplate.CONFIRM')} ${TemplatesStrings.get('jobTemplates.deleteJobTemplate.INVALIDATE')}
`; + invalidateRelatedLines.forEach(invalidateRelatedLine => { + deleteModalBody += invalidateRelatedLine; + }); + } + + Prompt({ + hdr: i18n._('Delete') + ' ' + $filter('sanitize')(template.name), + body: deleteModalBody, + action: action, + actionText: 'DELETE' + }); + }); + } + else { + Alert('Error: Unable to delete template', 'Template parameter is missing'); + } }; $scope.submitJob = function(template) { diff --git a/awx/ui/client/src/templates/main.js b/awx/ui/client/src/templates/main.js index 2712437a23..dfda8d26de 100644 --- a/awx/ui/client/src/templates/main.js +++ b/awx/ui/client/src/templates/main.js @@ -21,6 +21,7 @@ import WorkflowForm from './workflows.form'; import CompletedJobsList from './completed-jobs.list'; import InventorySourcesList from './inventory-sources.list'; import TemplateList from './templates.list'; +import TemplatesStrings from './templates.strings'; export default angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates.name, labels.name, workflowAdd.name, workflowEdit.name, @@ -33,6 +34,7 @@ angular.module('templates', [surveyMaker.name, templatesList.name, jobTemplates. .factory('CompletedJobsList', CompletedJobsList) .factory('TemplateList', TemplateList) .value('InventorySourcesList', InventorySourcesList) + .service('TemplatesStrings', TemplatesStrings) .config(['$stateProvider', 'stateDefinitionsProvider', '$stateExtenderProvider', function($stateProvider, stateDefinitionsProvider, $stateExtenderProvider) { let stateTree, addJobTemplate, editJobTemplate, addWorkflow, editWorkflow, diff --git a/awx/ui/client/src/templates/templates.strings.js b/awx/ui/client/src/templates/templates.strings.js new file mode 100644 index 0000000000..d8150b0d73 --- /dev/null +++ b/awx/ui/client/src/templates/templates.strings.js @@ -0,0 +1,17 @@ +function TemplatesStrings (BaseString) { + BaseString.call(this, 'templates'); + + let t = this.t; + let ns = this.templates; + + ns.jobTemplates = { + deleteJobTemplate: { + CONFIRM: t.s('Are you sure you want to delete this job template?'), + INVALIDATE: t.s('Doing so will invalidate the following:') + } + }; +} + +TemplatesStrings.$inject = ['BaseStringService']; + +export default TemplatesStrings; From e8fd40ace0cf1dd41b1988000c23a7f69d752fb2 Mon Sep 17 00:00:00 2001 From: gconsidine Date: Thu, 9 Nov 2017 17:01:32 -0500 Subject: [PATCH 2/8] Update model request interface and references --- awx/ui/.eslintrc.js | 1 + .../credentials/add-credentials.controller.js | 2 +- .../edit-credentials.controller.js | 2 +- awx/ui/client/lib/models/Base.js | 164 ++++++++++++------ awx/ui/client/lib/models/Config.js | 12 +- awx/ui/client/lib/models/Credential.js | 52 +++--- awx/ui/client/lib/models/CredentialType.js | 28 +-- awx/ui/client/lib/models/Inventory.js | 28 +-- awx/ui/client/lib/models/InventoryScript.js | 28 +-- awx/ui/client/lib/models/InventorySource.js | 28 +-- awx/ui/client/lib/models/JobTemplate.js | 28 +-- awx/ui/client/lib/models/Me.js | 12 +- awx/ui/client/lib/models/Organization.js | 20 +-- awx/ui/client/lib/models/Project.js | 44 ++--- .../lib/models/WorkflowJobTemplateNode.js | 20 +-- 15 files changed, 260 insertions(+), 209 deletions(-) diff --git a/awx/ui/.eslintrc.js b/awx/ui/.eslintrc.js index c8b8c73bba..217601f5f9 100644 --- a/awx/ui/.eslintrc.js +++ b/awx/ui/.eslintrc.js @@ -45,6 +45,7 @@ module.exports = { ignoreTemplateLiterals: true, }], 'no-continue': 'off', + 'no-debugger': 'off', 'no-mixed-operators': 'off', 'no-param-reassign': 'off', 'no-plusplus': 'off', diff --git a/awx/ui/client/features/credentials/add-credentials.controller.js b/awx/ui/client/features/credentials/add-credentials.controller.js index 560968c918..f0e4445669 100644 --- a/awx/ui/client/features/credentials/add-credentials.controller.js +++ b/awx/ui/client/features/credentials/add-credentials.controller.js @@ -42,7 +42,7 @@ function AddCredentialsController (models, $state, strings) { vm.form.save = data => { data.user = me.get('id'); - return credential.request('post', data); + return credential.request('post', { data }); }; vm.form.onSaveSuccess = res => { diff --git a/awx/ui/client/features/credentials/edit-credentials.controller.js b/awx/ui/client/features/credentials/edit-credentials.controller.js index 6fe3845266..e0a36c106f 100644 --- a/awx/ui/client/features/credentials/edit-credentials.controller.js +++ b/awx/ui/client/features/credentials/edit-credentials.controller.js @@ -88,7 +88,7 @@ function EditCredentialsController (models, $state, $scope, strings) { data.user = me.get('id'); credential.unset('inputs'); - return credential.request('put', data); + return credential.request('put', { data }); }; vm.form.onSaveSuccess = () => { diff --git a/awx/ui/client/lib/models/Base.js b/awx/ui/client/lib/models/Base.js index 854fb72de0..cd72106684 100644 --- a/awx/ui/client/lib/models/Base.js +++ b/awx/ui/client/lib/models/Base.js @@ -2,33 +2,44 @@ let $http; let $q; let cache; -function request (method, resource) { - if (Array.isArray(method)) { - const promises = method.map((_method_, i) => - this.request(_method_, Array.isArray(resource) ? resource[i] : resource)); +function request (method, resource, config) { + let req = this.parseRequestConfig(method, resource, config); + + if (Array.isArray(req.method)) { + const promises = req.method.map((_method, i) => { + const _resource = Array.isArray(req.resource) ? req.resource[i] : req.resource; + + req = this.parseRequestConfig(_method, _resource, config); + + if (this.isCacheable(req)) { + return this.requestWithCache(req); + } + + return this.request(req); + }); return $q.all(promises); } - if (this.isCacheable(method, resource)) { - return this.requestWithCache(method, resource); + if (this.isCacheable(req)) { + return this.requestWithCache(req); } - return this.http[method](resource); + return this.http[req.method](req); } -function requestWithCache (method, resource) { - const key = cache.createKey(method, this.path, resource); +function requestWithCache (config) { + const key = cache.createKey(config.method, this.path, config.resource); return cache.get(key) .then(data => { if (data) { - this.model[method.toUpperCase()] = data; + this.model[config.method.toUpperCase()] = data; return data; } - return this.http[method](resource) + return this.http[config.method](config) .then(res => { cache.put(key, res.data); @@ -77,22 +88,22 @@ function search (params, config) { }); } -function httpGet (resource, config) { +function httpGet (config = {}) { const req = { method: 'GET', url: this.path }; - if (config && config.params) { + if (config.params) { req.params = config.params; } - if (typeof resource === 'object') { - this.model.GET = resource; + if (typeof config.resource === 'object') { + this.model.GET = config.resource; return $q.resolve(); - } else if (resource) { - req.url = `${this.path}${resource}/`; + } else if (config.resource) { + req.url = `${this.path}${config.resource}/`; } return $http(req) @@ -103,40 +114,51 @@ function httpGet (resource, config) { }); } -function httpPost (data) { +function httpPost (config = {}) { const req = { method: 'POST', url: this.path, - data + data: config.data }; - return $http(req).then(res => { - this.model.GET = res.data; + return $http(req) + .then(res => { + this.model.GET = res.data; - return res; - }); + return res; + }); } -function httpPut (changes) { - const model = Object.assign(this.get(), changes); +function httpPatch (config = {}) { + const req = { + method: 'PUT', + url: `${this.path}${this.get('id')}/`, + data: config.changes + }; + + return $http(req); +} + +function httpPut (config = {}) { + const model = _.merge(this.get(), config.data); const req = { method: 'PUT', - url: `${this.path}${model.id}/`, + url: `${this.path}${this.get('id')}/`, data: model }; - return $http(req).then(res => res); + return $http(req); } -function httpOptions (resource) { +function httpOptions (config = {}) { const req = { method: 'OPTIONS', url: this.path }; - if (resource) { - req.url = `${this.path}${resource}/`; + if (config.resource) { + req.url = `${this.path}${config.resource}/`; } return $http(req) @@ -147,17 +169,17 @@ function httpOptions (resource) { }); } -function httpDelete (resource) { +function httpDelete (config = {}) { const req = { method: 'DELETE', url: this.path }; - if (resource) { - req.url = `${this.path}${resource}/`; + if (config.resource) { + req.url = `${this.path}${config.resource}/`; } - return $http(req).then(res => res); + return $http(req); } function options (keys) { @@ -367,29 +389,19 @@ function graft (id) { } function getDependentResourceCounts (id) { - if (this.setDependentResources) { - this.setDependentResources(id); - } else { - return Promise.resolve([]); - } + this.setDependentResources(id); - const dependentResourcePromises = []; + const promises = []; - this.dependentResources.forEach(dependentResource => { - const config = {}; - - if (dependentResource.params) { - config.params = dependentResource.params; - } - - dependentResourcePromises.push(dependentResource.model.http.get(undefined, config) - .then((val) => ({ - label: dependentResource.model.label, - count: val.data.count + this.dependentResources.forEach(resource => { + promises.push(resource.model.request('get', resource.params) + .then(res => ({ + label: resource.model.label, + count: res.data.count }))); }); - return Promise.all(dependentResourcePromises); + return Promise.all(promises); } /** @@ -401,20 +413,22 @@ function getDependentResourceCounts (id) { * @arg {string=} method - Populate the model with `GET` or `OPTIONS` data. * @arg {(string|Object)=} resource - An `id` reference to a particular * resource or an existing model's data. - * @arg {boolean=} isGraft - Create a new instance from existing model data. + * @arg {config=} config - Create a new instance from existing model data. * * @returns {(Object|Promise)} - Returns a reference to the model instance * if an empty instance or graft is created. Otherwise, a promise yielding * a model instance is returned. */ -function create (method, resource, isGraft, config) { - if (!method) { +function create (method, resource, config) { + const req = this.parseRequestConfig(method, resource, config); + + if (!req || !req.method) { return this; } - this.promise = this.request(method, resource, config); + this.promise = this.request(req); - if (isGraft) { + if (req.graft) { return this; } @@ -422,6 +436,40 @@ function create (method, resource, isGraft, config) { .then(() => this); } +function parseRequestConfig (method, resource, config) { + if (!method) { + return null; + } + + let req = {}; + + if (Array.isArray(method)) { + if (Array.isArray(resource)) { + req.resource = resource; + } else if (typeof resource === 'object') { + req = resource; + } + + req.method = method; + } else if (typeof method === 'string') { + if (typeof resource === 'object') { + req = resource; + } else { + req.resource = resource; + } + + req.method = method; + } else if (typeof method === 'object') { + req = method; + } else { + req = config; + req.method = method; + req.resource = resource; + } + + return req; +} + /** * Base functionality for API interaction. * @@ -444,6 +492,7 @@ function BaseModel (path, settings) { this.match = match; this.normalizePath = normalizePath; this.options = options; + this.parseRequestConfig = parseRequestConfig; this.request = request; this.requestWithCache = requestWithCache; this.search = search; @@ -455,6 +504,7 @@ function BaseModel (path, settings) { this.http = { get: httpGet.bind(this), options: httpOptions.bind(this), + patch: httpPatch.bind(this), post: httpPost.bind(this), put: httpPut.bind(this), delete: httpDelete.bind(this) diff --git a/awx/ui/client/lib/models/Config.js b/awx/ui/client/lib/models/Config.js index 85be6ef147..9f2e3ab87a 100644 --- a/awx/ui/client/lib/models/Config.js +++ b/awx/ui/client/lib/models/Config.js @@ -1,5 +1,5 @@ let $log; -let BaseModel; +let Base; function getTruncatedVersion () { let version; @@ -17,18 +17,18 @@ function isOpen () { return this.get('license_info.license_type') === 'open'; } -function ConfigModel (method, resource, graft) { - BaseModel.call(this, 'config', { cache: true }); +function ConfigModel (method, resource, config) { + Base.call(this, 'config', { cache: true }); this.Constructor = ConfigModel; this.getTruncatedVersion = getTruncatedVersion; this.isOpen = isOpen; - return this.create(method, resource, graft); + return this.create(method, resource, config); } -function ConfigModelLoader (_BaseModel_, _$log_) { - BaseModel = _BaseModel_; +function ConfigModelLoader (BaseModel, _$log_) { + Base = BaseModel; $log = _$log_; return ConfigModel; diff --git a/awx/ui/client/lib/models/Credential.js b/awx/ui/client/lib/models/Credential.js index 0bfac7be07..ebf2ea141f 100644 --- a/awx/ui/client/lib/models/Credential.js +++ b/awx/ui/client/lib/models/Credential.js @@ -1,11 +1,11 @@ const ENCRYPTED_VALUE = '$encrypted$'; -let BaseModel; -let ProjectModel; -let JobTemplateModel; -let InventoryModel; -let InventorySourceModel; -let ModelsStrings; +let Base; +let Project; +let JobTemplate; +let Inventory; +let InventorySource; +let strings; function createFormSchema (method, config) { if (!config) { @@ -48,26 +48,26 @@ function assignInputGroupValues (inputs) { function setDependentResources (id) { this.dependentResources = [ { - model: new ProjectModel(), + model: new Project(), params: { credential: id } }, { - model: new JobTemplateModel(), + model: new JobTemplate(), params: { credential: id, ask_credential_on_launch: false } }, { - model: new InventoryModel(), + model: new Inventory(), params: { insights_credential: id } }, { - model: new InventorySourceModel(), + model: new InventorySource(), params: { credential: id } @@ -75,32 +75,32 @@ function setDependentResources (id) { ]; } -function CredentialModel (method, resource, graft) { - BaseModel.call(this, 'credentials'); +function CredentialModel (method, resource, config) { + Base.call(this, 'credentials'); this.Constructor = CredentialModel; this.createFormSchema = createFormSchema.bind(this); this.assignInputGroupValues = assignInputGroupValues.bind(this); this.setDependentResources = setDependentResources.bind(this); - this.label = ModelsStrings.get('labels.CREDENTIAL'); + this.label = strings.get('labels.CREDENTIAL'); - return this.create(method, resource, graft); + return this.create(method, resource, config); } function CredentialModelLoader ( - _BaseModel_, - _ProjectModel_, - _JobTemplateModel_, - _InventoryModel_, - _InventorySourceModel_, - _ModelsStrings_ + BaseModel, + ProjectModel, + JobTemplateModel, + InventoryModel, + InventorySourceModel, + ModelsStrings ) { - BaseModel = _BaseModel_; - ProjectModel = _ProjectModel_; - JobTemplateModel = _JobTemplateModel_; - InventoryModel = _InventoryModel_; - InventorySourceModel = _InventorySourceModel_; - ModelsStrings = _ModelsStrings_; + Base = BaseModel; + Project = ProjectModel; + JobTemplate = JobTemplateModel; + Inventory = InventoryModel; + InventorySource = InventorySourceModel; + strings = ModelsStrings; return CredentialModel; } diff --git a/awx/ui/client/lib/models/CredentialType.js b/awx/ui/client/lib/models/CredentialType.js index 936a1d8bdd..706839795c 100644 --- a/awx/ui/client/lib/models/CredentialType.js +++ b/awx/ui/client/lib/models/CredentialType.js @@ -1,6 +1,6 @@ -let BaseModel; -let CredentialModel; -let ModelsStrings; +let Base; +let Credential; +let strings; function categorizeByKind () { const group = {}; @@ -35,7 +35,7 @@ function mergeInputProperties () { function setDependentResources (id) { this.dependentResources = [ { - model: new CredentialModel(), + model: new Credential(), params: { credential_type: id } @@ -43,26 +43,26 @@ function setDependentResources (id) { ]; } -function CredentialTypeModel (method, resource, graft) { - BaseModel.call(this, 'credential_types'); +function CredentialTypeModel (method, resource, config) { + Base.call(this, 'credential_types'); this.Constructor = CredentialTypeModel; this.categorizeByKind = categorizeByKind.bind(this); this.mergeInputProperties = mergeInputProperties.bind(this); this.setDependentResources = setDependentResources.bind(this); - this.label = ModelsStrings.get('labels.CREDENTIAL_TYPE'); + this.label = strings.get('labels.CREDENTIAL_TYPE'); - return this.create(method, resource, graft); + return this.create(method, resource, config); } function CredentialTypeModelLoader ( - _BaseModel_, - _CredentialModel_, - _ModelsStrings_ + BaseModel, + CredentialModel, + ModelsStrings ) { - BaseModel = _BaseModel_; - CredentialModel = _CredentialModel_; - ModelsStrings = _ModelsStrings_; + Base = BaseModel; + Credential = CredentialModel; + strings = ModelsStrings; return CredentialTypeModel; } diff --git a/awx/ui/client/lib/models/Inventory.js b/awx/ui/client/lib/models/Inventory.js index b1d5af3f54..9ce657d4e5 100644 --- a/awx/ui/client/lib/models/Inventory.js +++ b/awx/ui/client/lib/models/Inventory.js @@ -1,11 +1,11 @@ -let BaseModel; -let JobTemplateModel; -let ModelsStrings; +let Base; +let JobTemplate; +let strings; function setDependentResources (id) { this.dependentResources = [ { - model: new JobTemplateModel(), + model: new JobTemplate(), params: { inventory: id } @@ -13,24 +13,24 @@ function setDependentResources (id) { ]; } -function InventoryModel (method, resource, graft) { - BaseModel.call(this, 'inventories'); +function InventoryModel (method, resource, config) { + Base.call(this, 'inventories'); this.Constructor = InventoryModel; this.setDependentResources = setDependentResources.bind(this); - this.label = ModelsStrings.get('labels.INVENTORY'); + this.label = strings.get('labels.INVENTORY'); - return this.create(method, resource, graft); + return this.create(method, resource, config); } function InventoryModelLoader ( - _BaseModel_, - _JobTemplateModel_, - _ModelsStrings_ + BaseModel, + JobTemplateModel, + ModelsStrings ) { - BaseModel = _BaseModel_; - JobTemplateModel = _JobTemplateModel_; - ModelsStrings = _ModelsStrings_; + Base = BaseModel; + JobTemplate = JobTemplateModel; + strings = ModelsStrings; return InventoryModel; } diff --git a/awx/ui/client/lib/models/InventoryScript.js b/awx/ui/client/lib/models/InventoryScript.js index aa37d09efd..9a1832b8da 100644 --- a/awx/ui/client/lib/models/InventoryScript.js +++ b/awx/ui/client/lib/models/InventoryScript.js @@ -1,11 +1,11 @@ -let BaseModel; -let InventorySourceModel; -let ModelsStrings; +let Base; +let InventorySource; +let strings; function setDependentResources (id) { this.dependentResources = [ { - model: new InventorySourceModel(), + model: new InventorySource(), params: { source_script: id } @@ -13,24 +13,24 @@ function setDependentResources (id) { ]; } -function InventoryScriptModel (method, resource, graft) { - BaseModel.call(this, 'inventory_scripts'); +function InventoryScriptModel (method, resource, config) { + Base.call(this, 'inventory_scripts'); this.Constructor = InventoryScriptModel; this.setDependentResources = setDependentResources.bind(this); - this.label = ModelsStrings.get('labels.INVENTORY_SCRIPT'); + this.label = strings.get('labels.INVENTORY_SCRIPT'); - return this.create(method, resource, graft); + return this.create(method, resource, config); } function InventoryScriptModelLoader ( - _BaseModel_, - _InventorySourceModel_, - _ModelsStrings_ + BaseModel, + InventorySourceModel, + ModelsStrings ) { - BaseModel = _BaseModel_; - InventorySourceModel = _InventorySourceModel_; - ModelsStrings = _ModelsStrings_; + Base = BaseModel; + InventorySource = InventorySourceModel; + strings = ModelsStrings; return InventoryScriptModel; } diff --git a/awx/ui/client/lib/models/InventorySource.js b/awx/ui/client/lib/models/InventorySource.js index abde6883fb..b1529780f3 100644 --- a/awx/ui/client/lib/models/InventorySource.js +++ b/awx/ui/client/lib/models/InventorySource.js @@ -1,11 +1,11 @@ -let BaseModel; -let WorkflowJobTemplateNodeModel; -let ModelsStrings; +let Base; +let WorkflowJobTemplateNode; +let strings; function setDependentResources (id) { this.dependentResources = [ { - model: new WorkflowJobTemplateNodeModel(), + model: new WorkflowJobTemplateNode(), params: { unified_job_template: id } @@ -13,24 +13,24 @@ function setDependentResources (id) { ]; } -function InventorySourceModel (method, resource, graft) { - BaseModel.call(this, 'inventory_sources'); +function InventorySourceModel (method, resource, config) { + Base.call(this, 'inventory_sources'); this.Constructor = InventorySourceModel; + this.label = strings.get('labels.INVENTORY_SOURCE'); this.setDependentResources = setDependentResources.bind(this); - this.label = ModelsStrings.get('labels.INVENTORY_SOURCE'); - return this.create(method, resource, graft); + return this.create(method, resource, config); } function InventorySourceModelLoader ( - _BaseModel_, - _WorkflowJobTemplateNodeModel_, - _ModelsStrings_ + BaseModel, + WorkflowJobTemplateNodeModel, + ModelsStrings ) { - BaseModel = _BaseModel_; - WorkflowJobTemplateNodeModel = _WorkflowJobTemplateNodeModel_; - ModelsStrings = _ModelsStrings_; + Base = BaseModel; + WorkflowJobTemplateNode = WorkflowJobTemplateNodeModel; + strings = ModelsStrings; return InventorySourceModel; } diff --git a/awx/ui/client/lib/models/JobTemplate.js b/awx/ui/client/lib/models/JobTemplate.js index 2b0a7ce021..c058171bee 100644 --- a/awx/ui/client/lib/models/JobTemplate.js +++ b/awx/ui/client/lib/models/JobTemplate.js @@ -1,11 +1,11 @@ -let BaseModel; -let WorkflowJobTemplateNodeModel; -let ModelsStrings; +let Base; +let WorkflowJobTemplateNode; +let strings; function setDependentResources (id) { this.dependentResources = [ { - model: new WorkflowJobTemplateNodeModel(), + model: new WorkflowJobTemplateNode(), params: { unified_job_template: id } @@ -13,24 +13,24 @@ function setDependentResources (id) { ]; } -function JobTemplateModel (method, resource, graft) { - BaseModel.call(this, 'job_templates'); +function JobTemplateModel (method, resource, config) { + Base.call(this, 'job_templates'); this.Constructor = JobTemplateModel; this.setDependentResources = setDependentResources.bind(this); - this.label = ModelsStrings.get('labels.JOB_TEMPLATE'); + this.label = strings.get('labels.JOB_TEMPLATE'); - return this.create(method, resource, graft); + return this.create(method, resource, config); } function JobTemplateModelLoader ( - _BaseModel_, - _WorkflowJobTemplateNodeModel_, - _ModelsStrings_ + BaseModel, + WorkflowJobTemplateNodeModel, + ModelsStrings ) { - BaseModel = _BaseModel_; - WorkflowJobTemplateNodeModel = _WorkflowJobTemplateNodeModel_; - ModelsStrings = _ModelsStrings_; + Base = BaseModel; + WorkflowJobTemplateNode = WorkflowJobTemplateNodeModel; + strings = ModelsStrings; return JobTemplateModel; } diff --git a/awx/ui/client/lib/models/Me.js b/awx/ui/client/lib/models/Me.js index c2ee95d46e..221a29da34 100644 --- a/awx/ui/client/lib/models/Me.js +++ b/awx/ui/client/lib/models/Me.js @@ -1,11 +1,11 @@ -let BaseModel; +let Base; -function MeModel (method, resource, graft) { - BaseModel.call(this, 'me'); +function MeModel (method, resource, config) { + Base.call(this, 'me'); this.Constructor = MeModel; - return this.create(method, resource, graft) + return this.create(method, resource, config) .then(() => { if (this.has('results')) { _.merge(this.model.GET, this.get('results[0]')); @@ -16,8 +16,8 @@ function MeModel (method, resource, graft) { }); } -function MeModelLoader (_BaseModel_) { - BaseModel = _BaseModel_; +function MeModelLoader (BaseModel) { + Base = BaseModel; return MeModel; } diff --git a/awx/ui/client/lib/models/Organization.js b/awx/ui/client/lib/models/Organization.js index 734d547395..a518511ec6 100644 --- a/awx/ui/client/lib/models/Organization.js +++ b/awx/ui/client/lib/models/Organization.js @@ -1,21 +1,21 @@ -let BaseModel; -let ModelsStrings; +let Base; +let strings; -function OrganizationModel (method, resource, graft) { - BaseModel.call(this, 'organizations'); +function OrganizationModel (method, resource, config) { + Base.call(this, 'organizations'); this.Constructor = OrganizationModel; - this.label = ModelsStrings.get('labels.ORGANIZATION'); + this.label = strings.get('labels.ORGANIZATION'); - return this.create(method, resource, graft); + return this.create(method, resource, config); } function OrganizationModelLoader ( - _BaseModel_, - _ModelsStrings_ + BaseModel, + ModelsStrings ) { - BaseModel = _BaseModel_; - ModelsStrings = _ModelsStrings_; + Base = BaseModel; + strings = ModelsStrings; return OrganizationModel; } diff --git a/awx/ui/client/lib/models/Project.js b/awx/ui/client/lib/models/Project.js index 63d363bd92..071350a385 100644 --- a/awx/ui/client/lib/models/Project.js +++ b/awx/ui/client/lib/models/Project.js @@ -1,25 +1,25 @@ -let BaseModel; -let JobTemplateModel; -let WorkflowJobTemplateNodeModel; -let InventorySourceModel; -let ModelsStrings; +let Base; +let JobTemplate; +let WorkflowJobTemplateNode; +let InventorySource; +let strings; function setDependentResources (id) { this.dependentResources = [ { - model: new JobTemplateModel(), + model: new JobTemplate(), params: { project: id } }, { - model: new WorkflowJobTemplateNodeModel(), + model: new WorkflowJobTemplateNode(), params: { unified_job_template: id } }, { - model: new InventorySourceModel(), + model: new InventorySource(), params: { source_project: id } @@ -27,28 +27,28 @@ function setDependentResources (id) { ]; } -function ProjectModel (method, resource, graft) { - BaseModel.call(this, 'projects'); +function ProjectModel (method, resource, config) { + Base.call(this, 'projects'); this.Constructor = ProjectModel; this.setDependentResources = setDependentResources.bind(this); - this.label = ModelsStrings.get('labels.PROJECT'); + this.label = strings.get('labels.PROJECT'); - return this.create(method, resource, graft); + return this.create(method, resource, config); } function ProjectModelLoader ( - _BaseModel_, - _JobTemplateModel_, - _WorkflowJobTemplateNodeModel_, - _InventorySourceModel_, - _ModelsStrings_ + BaseModel, + JobTemplateModel, + WorkflowJobTemplateNodeModel, + InventorySourceModel, + ModelsStrings ) { - BaseModel = _BaseModel_; - JobTemplateModel = _JobTemplateModel_; - WorkflowJobTemplateNodeModel = _WorkflowJobTemplateNodeModel_; - InventorySourceModel = _InventorySourceModel_; - ModelsStrings = _ModelsStrings_; + Base = BaseModel; + JobTemplate = JobTemplateModel; + WorkflowJobTemplateNode = WorkflowJobTemplateNodeModel; + InventorySource = InventorySourceModel; + strings = ModelsStrings; return ProjectModel; } diff --git a/awx/ui/client/lib/models/WorkflowJobTemplateNode.js b/awx/ui/client/lib/models/WorkflowJobTemplateNode.js index bc5cfdf107..5ac7baed0a 100644 --- a/awx/ui/client/lib/models/WorkflowJobTemplateNode.js +++ b/awx/ui/client/lib/models/WorkflowJobTemplateNode.js @@ -1,21 +1,21 @@ -let BaseModel; -let ModelsStrings; +let Base; +let strings; -function WorkflowJobTemplateNodeModel (method, resource, graft) { - BaseModel.call(this, 'workflow_job_template_nodes'); +function WorkflowJobTemplateNodeModel (method, resource, config) { + Base.call(this, 'workflow_job_template_nodes'); this.Constructor = WorkflowJobTemplateNodeModel; - this.label = ModelsStrings.get('labels.WORKFLOW_JOB_TEMPLATE_NODE'); + this.label = strings.get('labels.WORKFLOW_JOB_TEMPLATE_NODE'); - return this.create(method, resource, graft); + return this.create(method, resource, config); } function WorkflowJobTemplateNodeModelLoader ( - _BaseModel_, - _ModelsStrings_ + BaseModel, + ModelsStrings ) { - BaseModel = _BaseModel_; - ModelsStrings = _ModelsStrings_; + Base = BaseModel; + strings = ModelsStrings; return WorkflowJobTemplateNodeModel; } From 8713e38c44fd8621945c5190d32f970b0d694fc0 Mon Sep 17 00:00:00 2001 From: gconsidine Date: Fri, 10 Nov 2017 10:42:05 -0500 Subject: [PATCH 3/8] Update the base model to use string service instead of each sub model --- awx/ui/client/lib/models/Base.js | 13 +++-- awx/ui/client/lib/models/Credential.js | 9 +--- awx/ui/client/lib/models/CredentialType.js | 12 +---- awx/ui/client/lib/models/Inventory.js | 12 +---- awx/ui/client/lib/models/InventoryScript.js | 12 +---- awx/ui/client/lib/models/InventorySource.js | 9 +--- awx/ui/client/lib/models/JobTemplate.js | 12 +---- awx/ui/client/lib/models/Organization.js | 11 +--- awx/ui/client/lib/models/Project.js | 7 +-- .../lib/models/WorkflowJobTemplateNode.js | 11 +--- awx/ui/client/lib/models/models.strings.js | 50 +++++++++++++++---- .../lib/services/base-string.service.js | 13 ++--- 12 files changed, 70 insertions(+), 101 deletions(-) diff --git a/awx/ui/client/lib/models/Base.js b/awx/ui/client/lib/models/Base.js index cd72106684..171c046a41 100644 --- a/awx/ui/client/lib/models/Base.js +++ b/awx/ui/client/lib/models/Base.js @@ -1,6 +1,7 @@ let $http; let $q; let cache; +let strings; function request (method, resource, config) { let req = this.parseRequestConfig(method, resource, config); @@ -473,14 +474,14 @@ function parseRequestConfig (method, resource, config) { /** * Base functionality for API interaction. * - * @arg {string} path - The API resource for the model extending BaseModel to + * @arg {string} resource - The API resource for the model extending BaseModel to * use. * @arg {Object=} settings - Configuration applied to all instances of the * extending model. * @arg {boolean=} settings.cache - Cache the model data. * */ -function BaseModel (path, settings) { +function BaseModel (resource, settings) { this.create = create; this.find = find; this.get = get; @@ -511,18 +512,20 @@ function BaseModel (path, settings) { }; this.model = {}; - this.path = this.normalizePath(path); + this.path = this.normalizePath(resource); + this.label = strings.get(`${resource}.LABEL`); this.settings = settings || {}; } -function BaseModelLoader (_$http_, _$q_, _cache_) { +function BaseModelLoader (_$http_, _$q_, _cache_, ModelsStrings) { $http = _$http_; $q = _$q_; cache = _cache_; + strings = ModelsStrings; return BaseModel; } -BaseModelLoader.$inject = ['$http', '$q', 'CacheService']; +BaseModelLoader.$inject = ['$http', '$q', 'CacheService', 'ModelsStrings']; export default BaseModelLoader; diff --git a/awx/ui/client/lib/models/Credential.js b/awx/ui/client/lib/models/Credential.js index ebf2ea141f..93d29bb002 100644 --- a/awx/ui/client/lib/models/Credential.js +++ b/awx/ui/client/lib/models/Credential.js @@ -5,7 +5,6 @@ let Project; let JobTemplate; let Inventory; let InventorySource; -let strings; function createFormSchema (method, config) { if (!config) { @@ -82,7 +81,6 @@ function CredentialModel (method, resource, config) { this.createFormSchema = createFormSchema.bind(this); this.assignInputGroupValues = assignInputGroupValues.bind(this); this.setDependentResources = setDependentResources.bind(this); - this.label = strings.get('labels.CREDENTIAL'); return this.create(method, resource, config); } @@ -92,15 +90,13 @@ function CredentialModelLoader ( ProjectModel, JobTemplateModel, InventoryModel, - InventorySourceModel, - ModelsStrings + InventorySourceModel ) { Base = BaseModel; Project = ProjectModel; JobTemplate = JobTemplateModel; Inventory = InventoryModel; InventorySource = InventorySourceModel; - strings = ModelsStrings; return CredentialModel; } @@ -110,8 +106,7 @@ CredentialModelLoader.$inject = [ 'ProjectModel', 'JobTemplateModel', 'InventoryModel', - 'InventorySourceModel', - 'ModelsStrings' + 'InventorySourceModel' ]; export default CredentialModelLoader; diff --git a/awx/ui/client/lib/models/CredentialType.js b/awx/ui/client/lib/models/CredentialType.js index 706839795c..0607350ad8 100644 --- a/awx/ui/client/lib/models/CredentialType.js +++ b/awx/ui/client/lib/models/CredentialType.js @@ -1,6 +1,5 @@ let Base; let Credential; -let strings; function categorizeByKind () { const group = {}; @@ -50,27 +49,20 @@ function CredentialTypeModel (method, resource, config) { this.categorizeByKind = categorizeByKind.bind(this); this.mergeInputProperties = mergeInputProperties.bind(this); this.setDependentResources = setDependentResources.bind(this); - this.label = strings.get('labels.CREDENTIAL_TYPE'); return this.create(method, resource, config); } -function CredentialTypeModelLoader ( - BaseModel, - CredentialModel, - ModelsStrings -) { +function CredentialTypeModelLoader (BaseModel, CredentialModel) { Base = BaseModel; Credential = CredentialModel; - strings = ModelsStrings; return CredentialTypeModel; } CredentialTypeModelLoader.$inject = [ 'BaseModel', - 'CredentialModel', - 'ModelsStrings' + 'CredentialModel' ]; export default CredentialTypeModelLoader; diff --git a/awx/ui/client/lib/models/Inventory.js b/awx/ui/client/lib/models/Inventory.js index 9ce657d4e5..3d270dfc79 100644 --- a/awx/ui/client/lib/models/Inventory.js +++ b/awx/ui/client/lib/models/Inventory.js @@ -1,6 +1,5 @@ let Base; let JobTemplate; -let strings; function setDependentResources (id) { this.dependentResources = [ @@ -18,27 +17,20 @@ function InventoryModel (method, resource, config) { this.Constructor = InventoryModel; this.setDependentResources = setDependentResources.bind(this); - this.label = strings.get('labels.INVENTORY'); return this.create(method, resource, config); } -function InventoryModelLoader ( - BaseModel, - JobTemplateModel, - ModelsStrings -) { +function InventoryModelLoader (BaseModel, JobTemplateModel) { Base = BaseModel; JobTemplate = JobTemplateModel; - strings = ModelsStrings; return InventoryModel; } InventoryModelLoader.$inject = [ 'BaseModel', - 'JobTemplateModel', - 'ModelsStrings' + 'JobTemplateModel' ]; export default InventoryModelLoader; diff --git a/awx/ui/client/lib/models/InventoryScript.js b/awx/ui/client/lib/models/InventoryScript.js index 9a1832b8da..1b759410ab 100644 --- a/awx/ui/client/lib/models/InventoryScript.js +++ b/awx/ui/client/lib/models/InventoryScript.js @@ -1,6 +1,5 @@ let Base; let InventorySource; -let strings; function setDependentResources (id) { this.dependentResources = [ @@ -18,27 +17,20 @@ function InventoryScriptModel (method, resource, config) { this.Constructor = InventoryScriptModel; this.setDependentResources = setDependentResources.bind(this); - this.label = strings.get('labels.INVENTORY_SCRIPT'); return this.create(method, resource, config); } -function InventoryScriptModelLoader ( - BaseModel, - InventorySourceModel, - ModelsStrings -) { +function InventoryScriptModelLoader (BaseModel, InventorySourceModel) { Base = BaseModel; InventorySource = InventorySourceModel; - strings = ModelsStrings; return InventoryScriptModel; } InventoryScriptModelLoader.$inject = [ 'BaseModel', - 'InventorySourceModel', - 'ModelsStrings' + 'InventorySourceModel' ]; export default InventoryScriptModelLoader; diff --git a/awx/ui/client/lib/models/InventorySource.js b/awx/ui/client/lib/models/InventorySource.js index b1529780f3..27ec05b6e9 100644 --- a/awx/ui/client/lib/models/InventorySource.js +++ b/awx/ui/client/lib/models/InventorySource.js @@ -1,6 +1,5 @@ let Base; let WorkflowJobTemplateNode; -let strings; function setDependentResources (id) { this.dependentResources = [ @@ -17,7 +16,6 @@ function InventorySourceModel (method, resource, config) { Base.call(this, 'inventory_sources'); this.Constructor = InventorySourceModel; - this.label = strings.get('labels.INVENTORY_SOURCE'); this.setDependentResources = setDependentResources.bind(this); return this.create(method, resource, config); @@ -25,20 +23,17 @@ function InventorySourceModel (method, resource, config) { function InventorySourceModelLoader ( BaseModel, - WorkflowJobTemplateNodeModel, - ModelsStrings + WorkflowJobTemplateNodeModel ) { Base = BaseModel; WorkflowJobTemplateNode = WorkflowJobTemplateNodeModel; - strings = ModelsStrings; return InventorySourceModel; } InventorySourceModelLoader.$inject = [ 'BaseModel', - 'WorkflowJobTemplateNodeModel', - 'ModelsStrings' + 'WorkflowJobTemplateNodeModel' ]; export default InventorySourceModelLoader; diff --git a/awx/ui/client/lib/models/JobTemplate.js b/awx/ui/client/lib/models/JobTemplate.js index c058171bee..885f1338a9 100644 --- a/awx/ui/client/lib/models/JobTemplate.js +++ b/awx/ui/client/lib/models/JobTemplate.js @@ -1,6 +1,5 @@ let Base; let WorkflowJobTemplateNode; -let strings; function setDependentResources (id) { this.dependentResources = [ @@ -18,27 +17,20 @@ function JobTemplateModel (method, resource, config) { this.Constructor = JobTemplateModel; this.setDependentResources = setDependentResources.bind(this); - this.label = strings.get('labels.JOB_TEMPLATE'); return this.create(method, resource, config); } -function JobTemplateModelLoader ( - BaseModel, - WorkflowJobTemplateNodeModel, - ModelsStrings -) { +function JobTemplateModelLoader (BaseModel, WorkflowJobTemplateNodeModel) { Base = BaseModel; WorkflowJobTemplateNode = WorkflowJobTemplateNodeModel; - strings = ModelsStrings; return JobTemplateModel; } JobTemplateModelLoader.$inject = [ 'BaseModel', - 'WorkflowJobTemplateNodeModel', - 'ModelsStrings' + 'WorkflowJobTemplateNodeModel' ]; export default JobTemplateModelLoader; diff --git a/awx/ui/client/lib/models/Organization.js b/awx/ui/client/lib/models/Organization.js index a518511ec6..2e29f72473 100644 --- a/awx/ui/client/lib/models/Organization.js +++ b/awx/ui/client/lib/models/Organization.js @@ -1,28 +1,21 @@ let Base; -let strings; function OrganizationModel (method, resource, config) { Base.call(this, 'organizations'); this.Constructor = OrganizationModel; - this.label = strings.get('labels.ORGANIZATION'); return this.create(method, resource, config); } -function OrganizationModelLoader ( - BaseModel, - ModelsStrings -) { +function OrganizationModelLoader (BaseModel) { Base = BaseModel; - strings = ModelsStrings; return OrganizationModel; } OrganizationModelLoader.$inject = [ - 'BaseModel', - 'ModelsStrings' + 'BaseModel' ]; export default OrganizationModelLoader; diff --git a/awx/ui/client/lib/models/Project.js b/awx/ui/client/lib/models/Project.js index 071350a385..bb08c09179 100644 --- a/awx/ui/client/lib/models/Project.js +++ b/awx/ui/client/lib/models/Project.js @@ -2,7 +2,6 @@ let Base; let JobTemplate; let WorkflowJobTemplateNode; let InventorySource; -let strings; function setDependentResources (id) { this.dependentResources = [ @@ -32,7 +31,6 @@ function ProjectModel (method, resource, config) { this.Constructor = ProjectModel; this.setDependentResources = setDependentResources.bind(this); - this.label = strings.get('labels.PROJECT'); return this.create(method, resource, config); } @@ -42,13 +40,11 @@ function ProjectModelLoader ( JobTemplateModel, WorkflowJobTemplateNodeModel, InventorySourceModel, - ModelsStrings ) { Base = BaseModel; JobTemplate = JobTemplateModel; WorkflowJobTemplateNode = WorkflowJobTemplateNodeModel; InventorySource = InventorySourceModel; - strings = ModelsStrings; return ProjectModel; } @@ -57,8 +53,7 @@ ProjectModelLoader.$inject = [ 'BaseModel', 'JobTemplateModel', 'WorkflowJobTemplateNodeModel', - 'InventorySourceModel', - 'ModelsStrings' + 'InventorySourceModel' ]; export default ProjectModelLoader; diff --git a/awx/ui/client/lib/models/WorkflowJobTemplateNode.js b/awx/ui/client/lib/models/WorkflowJobTemplateNode.js index 5ac7baed0a..c08cbd2e8c 100644 --- a/awx/ui/client/lib/models/WorkflowJobTemplateNode.js +++ b/awx/ui/client/lib/models/WorkflowJobTemplateNode.js @@ -1,28 +1,21 @@ let Base; -let strings; function WorkflowJobTemplateNodeModel (method, resource, config) { Base.call(this, 'workflow_job_template_nodes'); this.Constructor = WorkflowJobTemplateNodeModel; - this.label = strings.get('labels.WORKFLOW_JOB_TEMPLATE_NODE'); return this.create(method, resource, config); } -function WorkflowJobTemplateNodeModelLoader ( - BaseModel, - ModelsStrings -) { +function WorkflowJobTemplateNodeModelLoader (BaseModel) { Base = BaseModel; - strings = ModelsStrings; return WorkflowJobTemplateNodeModel; } WorkflowJobTemplateNodeModelLoader.$inject = [ - 'BaseModel', - 'ModelsStrings' + 'BaseModel' ]; export default WorkflowJobTemplateNodeModelLoader; diff --git a/awx/ui/client/lib/models/models.strings.js b/awx/ui/client/lib/models/models.strings.js index 55b72be5f0..acb2dd5bbf 100644 --- a/awx/ui/client/lib/models/models.strings.js +++ b/awx/ui/client/lib/models/models.strings.js @@ -4,16 +4,46 @@ function ModelsStrings (BaseString) { const { t } = this; const ns = this.models; - ns.labels = { - CREDENTIAL: t.s('Credentials'), - CREDENTIAL_TYPE: t.s('Credential Types'), - INVENTORY: t.s('Inventories'), - INVENTORY_SCRIPT: t.s('Inventory Scripts'), - INVENTORY_SOURCE: t.s('Inventory Sources'), - JOB_TEMPLATE: t.s('Job Templates'), - ORGANIZATION: t.s('Organizations'), - PROJECT: t.s('Projects'), - WORKFLOW_JOB_TEMPLATE_NODE: t.s('Workflow Job Template Nodes') + ns.credentials = { + LABEL: t.s('Credentials') + }; + + ns.credential_types = { + LABEL: t.s('Credential Types') + }; + + ns.inventories = { + LABEL: t.s('Inventories') + }; + + ns.inventory_scripts = { + LABEL: t.s('Inventory Scripts') + + }; + + ns.inventory_sources = { + LABEL: t.s('Inventory Sources') + + }; + + ns.job_templates = { + LABEL: t.s('Job Templates') + + }; + + ns.organizations = { + LABEL: t.s('Organizations') + + }; + + ns.projects = { + LABEL: t.s('Projects') + + }; + + ns.workflow_job_template_nodes = { + LABEL: t.s('Workflow Job Template Nodes') + }; } diff --git a/awx/ui/client/lib/services/base-string.service.js b/awx/ui/client/lib/services/base-string.service.js index 4f0df6b545..74d6611956 100644 --- a/awx/ui/client/lib/services/base-string.service.js +++ b/awx/ui/client/lib/services/base-string.service.js @@ -4,7 +4,6 @@ let i18n; function BaseStringService (namespace) { const ERROR_NO_NAMESPACE = 'BaseString cannot be extended without providing a namespace'; - const ERROR_NO_STRING = 'No string exists with this name'; if (!namespace) { throw new Error(ERROR_NO_NAMESPACE); @@ -67,8 +66,6 @@ function BaseStringService (namespace) { * the more globally relevant strings defined here. Strings with with dots as delimeters are * supported to give flexibility to extending classes to nest strings as necessary. * - * If no match is found, an error is thrown to alert the developer immediately instead of - * failing silently. * * The `t.s` and `t.p` calls should only be used where strings are defined in * .strings.js` files. To use translated strings elsewhere, access them through this @@ -88,13 +85,13 @@ function BaseStringService (namespace) { } else { value = value[key]; } - - if (!value) { - throw new Error(`${ERROR_NO_STRING}: ${name}`); - } }); - return typeof value === 'string' ? value : value(...args); + if (!value || typeof value === 'string') { + return value; + } + + return value(...args); }; } From 25dc3f8778c11ef7d27a811ca40982df01bf97be Mon Sep 17 00:00:00 2001 From: mabashian Date: Fri, 10 Nov 2017 11:29:46 -0500 Subject: [PATCH 4/8] Update delete modals and fixed unit test failures --- awx/ui/client/index.template.ejs | 5 +- .../list/credentials-list.controller.js | 5 +- .../list/inventory-list.controller.js | 5 +- .../sources/list/sources-list.controller.js | 5 +- .../inventory-scripts/list/list.controller.js | 5 +- .../src/job-results/job-results.service.js | 12 ++-- .../src/jobs/factories/delete-job.factory.js | 5 +- .../list.controller.js | 5 +- .../list/organizations-list.controller.js | 3 +- .../projects/list/projects-list.controller.js | 5 +- .../factories/delete-schedule.factory.js | 3 +- awx/ui/client/src/shared/modal/modal.less | 4 ++ awx/ui/client/src/shared/prompt-dialog.js | 1 + awx/ui/client/src/shared/prompt/prompt.less | 4 ++ .../src/teams/list/teams-list.controller.js | 7 ++- .../list/templates-list.controller.js | 61 +++++++++++-------- .../client/src/templates/templates.strings.js | 6 ++ .../workflow-maker.partial.html | 10 ++- .../src/users/list/users-list.controller.js | 3 +- .../workflow-results.service.js | 12 ++-- .../templates-list.controller-test.js | 34 +++++++++++ 21 files changed, 136 insertions(+), 64 deletions(-) diff --git a/awx/ui/client/index.template.ejs b/awx/ui/client/index.template.ejs index 5b082eb6e7..0301d42da0 100644 --- a/awx/ui/client/index.template.ejs +++ b/awx/ui/client/index.template.ejs @@ -33,7 +33,10 @@