diff --git a/packages/manager/modules/iam/src/components/deleteEntity/deleteEntity.constants.js b/packages/manager/modules/iam/src/components/deleteEntity/deleteEntity.constants.js index c81d8cbefe3a..8f893f962d1d 100644 --- a/packages/manager/modules/iam/src/components/deleteEntity/deleteEntity.constants.js +++ b/packages/manager/modules/iam/src/components/deleteEntity/deleteEntity.constants.js @@ -29,6 +29,12 @@ export const DELETE_ENTITY_TAG = { error: TAG.RESOURCE_GROUPS__DELETE_GROUP_CONFIRM_BANNER__ERROR, success: TAG.RESOURCE_GROUPS__DELETE_GROUP_CONFIRM_BANNER__SUCCESS, }, + [ENTITY.APPLICATION]: { + close: TAG.DELETE_APPLICATION__CANCEL, + delete: TAG.DELETE_APPLICATION__CONFIRM, + error: TAG.APPLICATIONS__DELETE_APPLICATION_CONFIRM_BANNER__ERROR, + success: TAG.APPLICATIONS__DELETE_APPLICATION_CONFIRM_BANNER__SUCCESS, + }, }; export default { diff --git a/packages/manager/modules/iam/src/components/deleteEntity/deleteEntity.controller.js b/packages/manager/modules/iam/src/components/deleteEntity/deleteEntity.controller.js index 43e7ab51d055..5db09ba3f061 100644 --- a/packages/manager/modules/iam/src/components/deleteEntity/deleteEntity.controller.js +++ b/packages/manager/modules/iam/src/components/deleteEntity/deleteEntity.controller.js @@ -87,6 +87,8 @@ export default class DeleteEntityController { promise = this.deletePolicy(); } else if (this.entity.type === ENTITY.RESOURCE_GROUP) { promise = this.deleteResourceGroup(); + } else if (this.entity.type === ENTITY.APPLICATION) { + promise = this.deleteApplication(); } else if (this.entity.type === ENTITY.RESOURCE_TYPE) { promise = this.$q.when(true); } else { @@ -135,6 +137,14 @@ export default class DeleteEntityController { return this.IAMService.deleteResourceGroup(this.entity.data.id); } + /** + * Delete the entity using the IAMService + * @returns {Promise} + */ + deleteApplication() { + return this.IAMService.deleteApplication(this.entity.data.applicationId); + } + /** * Custom trackClick wrapper witch uses the tagPrefix bound property * @param {'close'|'delete'} tagKey diff --git a/packages/manager/modules/iam/src/components/deleteEntity/translations/Messages_fr_FR.json b/packages/manager/modules/iam/src/components/deleteEntity/translations/Messages_fr_FR.json index ee9760ceb484..219b8e27bcd9 100644 --- a/packages/manager/modules/iam/src/components/deleteEntity/translations/Messages_fr_FR.json +++ b/packages/manager/modules/iam/src/components/deleteEntity/translations/Messages_fr_FR.json @@ -12,6 +12,12 @@ "iam_delete_entity_resourceGroup_name": "Suppression du groupe de ressources : ", "iam_delete_entity_resourceGroup_success": "Le groupe de ressources a bien été supprimé", "iam_delete_entity_resourceGroup_warn": "Êtes-vous sûr.e de confirmer la suppression ?", + "iam_delete_entity_application_error": "An error occurred while deleting the application: {{ message }}", + "iam_delete_entity_application_field": "Please enter the word \"{{ statement }}\" to delete your application", + "iam_delete_entity_application_heading": "Delete an application", + "iam_delete_entity_application_name": "Deleting application: ", + "iam_delete_entity_application_success": "Application deleted", + "iam_delete_entity_application_warn": "Warning: this action will delete the application and it will revoke all credential belonging to this application.", "iam_delete_entity_resourceType_error": "Une erreur est survenue lors de la suppression du type de produit : {{ message }}", "iam_delete_entity_resourceType_heading": "Supprimer un type de produit", "iam_delete_entity_resourceType_name": "Suppression du type de produit : ", diff --git a/packages/manager/modules/iam/src/dashboard/applications/applications.component.js b/packages/manager/modules/iam/src/dashboard/applications/applications.component.js new file mode 100644 index 000000000000..73fb0aac643c --- /dev/null +++ b/packages/manager/modules/iam/src/dashboard/applications/applications.component.js @@ -0,0 +1,13 @@ +import controller from './applications.controller'; +import template from './applications.template.html'; + +export default { + bindings: { + applications: '<', + alert: '<', + goTo: '<', + trackClick: '<', + }, + controller, + template, +}; diff --git a/packages/manager/modules/iam/src/dashboard/applications/applications.controller.js b/packages/manager/modules/iam/src/dashboard/applications/applications.controller.js new file mode 100644 index 000000000000..06eabc3a15f5 --- /dev/null +++ b/packages/manager/modules/iam/src/dashboard/applications/applications.controller.js @@ -0,0 +1,23 @@ +import { AbstractCursorDatagridController } from '@ovh-ux/manager-ng-apiv2-helper'; +import { TAG } from '../../iam.constants'; + +export default class ApplicationsController extends AbstractCursorDatagridController { + /* @ngInject */ + constructor(IAMService) { + super(); + this.IAMService = IAMService; + } + + /** + * Go to resourceGroup deletion + * @param {string} id The application id + * @returns {Promise} + */ + deleteApplication(id) { + this.trackClick(TAG.APPLICATIONS__DELETE); + this.goTo({ + name: 'iam.dashboard.applications.delete', + params: { application: id }, + }); + } +} diff --git a/packages/manager/modules/iam/src/dashboard/applications/applications.module.js b/packages/manager/modules/iam/src/dashboard/applications/applications.module.js new file mode 100644 index 000000000000..7964aa5aaa33 --- /dev/null +++ b/packages/manager/modules/iam/src/dashboard/applications/applications.module.js @@ -0,0 +1,15 @@ +import angular from 'angular'; + +import component from './applications.component'; +import routing from './applications.routing'; +import deleteModule from './delete'; + +const moduleName = 'ovhManagerIAMDashboardApplications'; + +angular + .module(moduleName, [deleteModule]) + .component('iamApplications', component) + .config(routing) + .run(/* @ngTranslationsInject:json ./translations */); + +export default moduleName; diff --git a/packages/manager/modules/iam/src/dashboard/applications/applications.routing.js b/packages/manager/modules/iam/src/dashboard/applications/applications.routing.js new file mode 100644 index 000000000000..ab3a7af20b89 --- /dev/null +++ b/packages/manager/modules/iam/src/dashboard/applications/applications.routing.js @@ -0,0 +1,16 @@ +import { TAG } from '../../iam.constants'; + +export default /* @ngInject */ ($stateProvider) => { + $stateProvider.state('iam.dashboard.applications', { + url: '/applications?cursors', + component: 'iamApplications', + resolve: { + breadcrumb: () => null, + applications: /* @ngInject */ (IAMService) => + IAMService.getApplications(), + }, + atInternet: { + rename: TAG.APPLICATIONS, + }, + }); +}; diff --git a/packages/manager/modules/iam/src/dashboard/applications/applications.template.html b/packages/manager/modules/iam/src/dashboard/applications/applications.template.html new file mode 100644 index 000000000000..a3b2df6f42f3 --- /dev/null +++ b/packages/manager/modules/iam/src/dashboard/applications/applications.template.html @@ -0,0 +1,58 @@ +
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/packages/manager/modules/iam/src/dashboard/applications/delete/delete.module.js b/packages/manager/modules/iam/src/dashboard/applications/delete/delete.module.js new file mode 100644 index 000000000000..db5b906b908a --- /dev/null +++ b/packages/manager/modules/iam/src/dashboard/applications/delete/delete.module.js @@ -0,0 +1,10 @@ +import angular from 'angular'; + +import deleteEntity from '../../../components/deleteEntity'; +import routing from './delete.routing'; + +const moduleName = 'ovhManagerIAMDashboardApplicationsDelete'; + +angular.module(moduleName, [deleteEntity]).config(routing); + +export default moduleName; diff --git a/packages/manager/modules/iam/src/dashboard/applications/delete/delete.routing.js b/packages/manager/modules/iam/src/dashboard/applications/delete/delete.routing.js new file mode 100644 index 000000000000..90a843484806 --- /dev/null +++ b/packages/manager/modules/iam/src/dashboard/applications/delete/delete.routing.js @@ -0,0 +1,43 @@ +import { ENTITY, TAG } from '../../../iam.constants'; + +export default /* @ngInject */ ($stateProvider) => { + $stateProvider.state('iam.dashboard.applications.delete', { + url: '/delete/{application:string}', + component: 'iamDeleteEntity', + resolve: { + breadcrumb: () => null, + + /** + * A polymorphic DTO required by the deleteEntity component + * @returns {{ + * data: Object, + * type: string + * }|null} + */ + entity: /* @ngInject */ (application) => { + if (application) { + return { data: application, type: ENTITY.APPLICATION }; + } + return null; + }, + + /** + * The application to delete if an id is provided + * @returns {Object|null} + */ + application: /* @ngInject */ ($transition$, IAMService) => { + const { application: id } = $transition$.params(); + return id ? IAMService.getApplication(id) : null; + }, + + /** + * Whether the entity requires a statement + * @returns {boolean} + */ + statement: /* @ngInject */ (entity) => entity.type === ENTITY.APPLICATION, + }, + atInternet: { + rename: TAG.DELETE_APPLICATION, + }, + }); +}; diff --git a/packages/manager/modules/iam/src/dashboard/applications/delete/index.js b/packages/manager/modules/iam/src/dashboard/applications/delete/index.js new file mode 100644 index 000000000000..eef7e516159b --- /dev/null +++ b/packages/manager/modules/iam/src/dashboard/applications/delete/index.js @@ -0,0 +1,22 @@ +import angular from 'angular'; +import uiRouter from '@uirouter/angularjs'; +import ocLazyLoad from 'oclazyload'; + +const moduleName = 'ovhManagerIAMDashboardApplicationsDeleteLazyLoading'; + +angular.module(moduleName, [uiRouter, ocLazyLoad]).config( + /* @ngInject */ ($stateProvider) => { + $stateProvider.state('iam.dashboard.applications.delete.**', { + url: '/delete/{application:string}', + lazyLoad: (transition) => + import('./delete.module').then((module) => + transition + .injector() + .get('$ocLazyLoad') + .inject(module.default), + ), + }); + }, +); + +export default moduleName; diff --git a/packages/manager/modules/iam/src/dashboard/applications/index.js b/packages/manager/modules/iam/src/dashboard/applications/index.js new file mode 100644 index 000000000000..23a1506e0af1 --- /dev/null +++ b/packages/manager/modules/iam/src/dashboard/applications/index.js @@ -0,0 +1,22 @@ +import angular from 'angular'; +import uiRouter from '@uirouter/angularjs'; +import ocLazyLoad from 'oclazyload'; + +const moduleName = 'ovhManagerIAMDashboardApplicationsLazyLoading'; + +angular.module(moduleName, [uiRouter, ocLazyLoad]).config( + /* @ngInject */ ($stateProvider) => { + $stateProvider.state('iam.dashboard.applications.**', { + url: '/applications', + lazyLoad: (transition) => + import('./applications.module').then((module) => + transition + .injector() + .get('$ocLazyLoad') + .inject(module.default), + ), + }); + }, +); + +export default moduleName; diff --git a/packages/manager/modules/iam/src/dashboard/applications/translations/Messages_fr_FR.json b/packages/manager/modules/iam/src/dashboard/applications/translations/Messages_fr_FR.json new file mode 100644 index 000000000000..a9b0af94d96e --- /dev/null +++ b/packages/manager/modules/iam/src/dashboard/applications/translations/Messages_fr_FR.json @@ -0,0 +1,11 @@ +{ + "iam_applications_datagrid_column_application_id": "Application id", + "iam_applications_datagrid_column_application_name": "Application name", + "iam_applications_datagrid_column_application_description": "Description", + "iam_applications_datagrid_column_application_status": "Status", + "iam_applications_datagrid_column_application_status_active": "Active", + "iam_applications_datagrid_column_application_status_inactive": "Inactive", + "iam_applications_datagrid_column_application_key": "Application key", + "iam_applications_datagrid_action_delete_application": "Delete application", + "iam_applications_description": "View and manage your applications. For more information about applications, see the documentation." +} diff --git a/packages/manager/modules/iam/src/dashboard/dashboard.module.js b/packages/manager/modules/iam/src/dashboard/dashboard.module.js index 5a61865b226b..8a48ad100465 100644 --- a/packages/manager/modules/iam/src/dashboard/dashboard.module.js +++ b/packages/manager/modules/iam/src/dashboard/dashboard.module.js @@ -2,6 +2,7 @@ import angular from 'angular'; import policies from './policies'; import resourceGroups from './resourceGroups'; +import applications from './applications'; import users from './users/users.module'; import component from './dashboard.component'; @@ -10,7 +11,7 @@ import routing from './dashboard.routing'; const moduleName = 'ovhManagerIAMDashboard'; angular - .module(moduleName, [policies, resourceGroups, users]) + .module(moduleName, [policies, resourceGroups, applications, users]) .component('iamDashboard', component) .config(routing) .run(/* @ngTranslationsInject:json ./translations */); diff --git a/packages/manager/modules/iam/src/dashboard/dashboard.template.html b/packages/manager/modules/iam/src/dashboard/dashboard.template.html index 3635635ac992..235edf80be4c 100644 --- a/packages/manager/modules/iam/src/dashboard/dashboard.template.html +++ b/packages/manager/modules/iam/src/dashboard/dashboard.template.html @@ -19,6 +19,11 @@ data-translate="iam_dashboard_header_tabs_item_resource_groups" > + diff --git a/packages/manager/modules/iam/src/dashboard/translations/Messages_fr_FR.json b/packages/manager/modules/iam/src/dashboard/translations/Messages_fr_FR.json index d94cde1eb64d..783923c7c582 100644 --- a/packages/manager/modules/iam/src/dashboard/translations/Messages_fr_FR.json +++ b/packages/manager/modules/iam/src/dashboard/translations/Messages_fr_FR.json @@ -4,5 +4,6 @@ "iam_dashboard_header_heading": "Gestion des identités et des accès (IAM)", "iam_dashboard_header_tabs_item_identities": "Identités", "iam_dashboard_header_tabs_item_policies": "Politiques", - "iam_dashboard_header_tabs_item_resource_groups": "Groupes de ressources" + "iam_dashboard_header_tabs_item_resource_groups": "Groupes de ressources", + "iam_dashboard_header_tabs_item_applications": "Applications" } diff --git a/packages/manager/modules/iam/src/iam.constants.js b/packages/manager/modules/iam/src/iam.constants.js index d8d49907fbeb..6ba26d885648 100644 --- a/packages/manager/modules/iam/src/iam.constants.js +++ b/packages/manager/modules/iam/src/iam.constants.js @@ -35,6 +35,7 @@ const ENTITY = { IDENTITY: 'identity', RESOURCE_GROUP: 'resourceGroup', RESOURCE_TYPE: 'resourceType', + APPLICATION: 'application', }; const ENTITY_NAME_PATTERN = /^[a-zA-Z0-9-/_+]*$/; @@ -192,6 +193,11 @@ const TAG = { 'dedicated::account::iam::delete-group-ressources::cancel', DELETE_RESOURCE_GROUP__CONFIRM: 'dedicated::account::iam::delete-group-ressources::confirm', + DELETE_APPLICATION: 'dedicated::account::iam::delete-application', + DELETE_APPLICATION__CANCEL: + 'dedicated::account::iam::delete-application::cancel', + DELETE_APPLICATION__CONFIRM: + 'dedicated::account::iam::delete-application::confirm', // Policy edition EDIT_POLICY: 'dedicated::account::iam::edit-policy', @@ -254,6 +260,16 @@ const TAG = { RESOURCE_GROUPS__EDIT_GROUP_CONFIRM_BANNER__SUCCESS: 'iam::group-ressources::edit-group-confirm-banner::success', + // List of applications + APPLICATIONS: 'dedicated::account::iam::applications', + APPLICATIONS__DELETE: 'dedicated::account::iam::applications::delete', + + // List of applications - banners + APPLICATIONS__DELETE_APPLICATION_CONFIRM_BANNER__ERROR: + 'iam::applications::delete-application-confirm-banner::error', + APPLICATIONS__DELETE_APPLICATION_CONFIRM_BANNER__SUCCESS: + 'iam::applications::delete-application-confirm-banner::success', + // Commons ADD_ACTION_MANUALLY_SUCCESS: 'add-manually-success', ADD_ACTION_MANUALLY: 'add-manually', diff --git a/packages/manager/modules/iam/src/iam.service.js b/packages/manager/modules/iam/src/iam.service.js index 6dac09cd64d4..e181eb44f242 100644 --- a/packages/manager/modules/iam/src/iam.service.js +++ b/packages/manager/modules/iam/src/iam.service.js @@ -11,6 +11,7 @@ export const URL = { RESOURCE_GROUP: '/engine/api/v2/iam/resourceGroup', RESOURCE_TYPE: '/engine/api/v2/iam/reference/resource/type', PERMISSIONS_GROUPS: '/engine/api/v2/iam/permissionsGroup', + APPLICATIONS: '/me/api/application', }; export default class IAMService { @@ -489,4 +490,38 @@ export default class IAMService { data, }).then(({ data: resourceGroup }) => resourceGroup); } + + /** + * Retrieves a list of all applications. + * @returns {Promise} A Promise that resolves to an array of application objects, or null if an application fetch fails. + */ + getApplications() { + return this.$http + .get(URL.APPLICATIONS) + .then(({ data }) => + this.$q.all( + data + .map((id) => this.getApplication(id).catch(() => null)) + .filter((application) => application !== null), + ), + ); + } + + /** + * Retrieves the details of a specific application. + * @param {string} id The unique identifier of the application. + * @returns {Promise} A Promise that resolves to the application object. + */ + getApplication(id) { + return this.$http.get(`${URL.APPLICATIONS}/${id}`).then(({ data }) => data); + } + + /** + * Deletes an application. + * @param {string} id The unique identifier of the application to be deleted. + * @returns {Promise} A Promise that resolves when the deletion is complete. + */ + deleteApplication(id) { + return this.$http.delete(`${URL.APPLICATIONS}/${id}`); + } }