diff --git a/app/localization/translated/be.json b/app/localization/translated/be.json index df806bd0ef..13c067867c 100644 --- a/app/localization/translated/be.json +++ b/app/localization/translated/be.json @@ -324,6 +324,7 @@ "Common.proceedValidItems": "Апрацоўвайце сапраўдныя элементы", "Common.processData": "Пачакайце, мы апрацоўваем вашыя дадзеныя", "Common.refresh": "Абнавіць", + "Common.rename": "Перайменаваць", "Common.requiredFieldHint": "Гэта поле абавязковае", "Common.reset": "Скінуць", "Common.saturday": "Субота", @@ -578,6 +579,7 @@ "DeleteLaunchModal.warningMultiple": "Вы збіраецеся выдаліць не свой запускі. Гэта можа паўплываць на інфармацыю іншых карыстальнікаў праекта.", "DeleteNotificationCaseModal.title": "Выдаліць правіла апавяшчэння", "DeleteNotificationModal.message": "Вы ўпэўнены, што хочаце выдаліць гэта правіла апавяшчэнняў?", + "DeleteProjectModal.keywordMatcherHint": "Уведзены тэкст не супадае з патрабаваным ключавым словам", "DeleteWidgetModal.deleteNotOwnWidgetWarning": "Вы збіраецеся выдаліць не ваш відждэт. Гэта можа паўплываць на інфармацыю іншых карыстальнікаў праекта.", "DeleteWidgetModal.deleteOwnWidgetWarning": "Вы збіраецеся выдаліць ваш відждэт. Гэта можа паўплываць на інфармацыю на вашых панэлях кіравання.", "DeleteWidgetModal.deleteWidgetHeader": "Выдаліць відждэт", @@ -1544,7 +1546,11 @@ "NotificationsEnableForm.unableToConfigure": "Чаму я не магу яго наладзіць?", "NotificationsEnableForm.unableToConfigureDescription": "Даведайцеся больш пра ролі і дазволы", "NotificationsTab.updateProjectNotificationsConfigurationSuccess": "Налады апавяшчэнняў былі паспяхова абноўлены!", + "OrganizationProjectsPage.actionInviteUser": "Запрасіць карыстальніка", + "OrganizationProjectsPage.actionUnassign": "Адмяніць прызначэнне", "OrganizationProjectsPage.allOrganizations": "Усе арганізацыі", + "OrganizationProjectsPage.confirmDeleteProjectMessage": "Вы ўпэўнены, што хочаце выдаліць праект \"{projectName}\"? Гэта незваротнае дзеянне прывядзе да выдалення ўсіх дадзеных.", + "OrganizationProjectsPage.confirmProjectNameEntry": "Каб пацвердзіць, калі ласка, увядзіце назву праекта", "OrganizationProjectsPage.createProject": "Стварыць праект", "OrganizationProjectsPage.noProjectsListWithPermission": "Стварыце новы праект, каб пачаць сваё падарожжа ReportPortal", "OrganizationProjectsPage.noProjectsListWithoutPermission": "Спіс даступных вам праектаў зараз пусты.
Звярніцеся да кіраўніка вашай арганізацыі для атрымання падрабязнай інфармацыі.", @@ -1789,14 +1795,7 @@ "ProjectsPage.assignSuccess": "Вы прызначаныя на праект", "ProjectsPage.dateCol": "Дата", "ProjectsPage.deleteError": "Пры выдаленні праекта ўзнікла памылка", - "ProjectsPage.deleteErrorMultiple": "Памылка пры выдаленні праекта", - "ProjectsPage.deleteModalContent": "Вы ўпэўненыя, што хочаце выдаліць праект {name}?", - "ProjectsPage.deleteModalHeader": "Выдаліць праект", - "ProjectsPage.deleteModalMultipleContent": "Вы ўпэўненыя, што хочаце выдаліць праекты {names}?", - "ProjectsPage.deleteModalMultipleHeader": "Выдаліць праекты", - "ProjectsPage.deleteProjectsCount": "{count} элементаў абрана", - "ProjectsPage.deleteSuccess": "Праект быў паспяхова выдалены", - "ProjectsPage.deleteSuccessMultiple": "Праекты быў паспяхова выдалены", + "ProjectsPage.deleteProjectSuccess": "Праект ''{name}'' быў паспяхова выдалены", "ProjectsPage.noResultsDescription": "Вашым крытэрам пошуку або фільтра не знойдзена ніводнага выніку. Калі ласка, паспрабуйце іншыя ключавыя словы або змяніце налады фільтра.", "ProjectsPage.projectDuplicateHint": "Праект з дадзеным найменнем ўжо існуе ў сістэме", "ProjectsPage.projectExists": "Праект з такой назвай ужо існуе ў гэтай арганізацыі", diff --git a/app/localization/translated/es.json b/app/localization/translated/es.json index 70e5838d6e..7c1bc1411f 100644 --- a/app/localization/translated/es.json +++ b/app/localization/translated/es.json @@ -323,6 +323,7 @@ "Common.proceedValidItems": "Procesar elementos válidos", "Common.processData": "Espera, estamos procesando tus datos", "Common.refresh": "Actualizar", + "Common.rename": "Rename", "Common.requiredFieldHint": "Este campo es obligatorio", "Common.reset": "Restablecer", "Common.saturday": "Sábado", @@ -577,6 +578,7 @@ "DeleteLaunchModal.warningMultiple": "Estás a punto de eliminar ejecuciones que no son tuyas. Esto puede afectar la información de otros usuarios del proyecto.", "DeleteNotificationCaseModal.title": "Eliminar regla de notificación", "DeleteNotificationModal.message": "¿Estás seguro de que deseas eliminar esta regla de notificaciones?", + "DeleteProjectModal.keywordMatcherHint": "The entered text does not match the required keyword", "DeleteWidgetModal.deleteNotOwnWidgetWarning": "Estás a punto de eliminar un widget que no es tuyo. Esto puede afectar la información de otros usuarios del proyecto.", "DeleteWidgetModal.deleteOwnWidgetWarning": "Estás a punto de eliminar tu propio widget. Esto puede afectar la información en tus paneles de control.", "DeleteWidgetModal.deleteWidgetHeader": "Eliminar widget", @@ -1542,7 +1544,11 @@ "NotificationsEnableForm.unableToConfigure": "¿Por qué no puedo configurarlo?", "NotificationsEnableForm.unableToConfigureDescription": "Más información sobre funciones y permisos", "NotificationsTab.updateProjectNotificationsConfigurationSuccess": "¡La configuración de notificaciones se ha actualizado correctamente!", + "OrganizationProjectsPage.actionInviteUser": "Invite user", + "OrganizationProjectsPage.actionUnassign": "Unassign", "OrganizationProjectsPage.allOrganizations": "All organizations", + "OrganizationProjectsPage.confirmDeleteProjectMessage": "Are you sure you want to delete the \"{projectName}\" project? This irreversible action will delete all its data.", + "OrganizationProjectsPage.confirmProjectNameEntry": "To confirm, please enter the name of the project", "OrganizationProjectsPage.createProject": "Create project", "OrganizationProjectsPage.noProjectsListWithPermission": "Create a new project to begin your ReportPortal journey", "OrganizationProjectsPage.noProjectsListWithoutPermission": "The list of available to you projects is currently empty.
Contact your Organization’s manager for details.", @@ -1783,14 +1789,7 @@ "ProjectsPage.assignSuccess": "Ha sido asignado al proyecto", "ProjectsPage.dateCol": "Fecha", "ProjectsPage.deleteError": "Ocurrió un error al eliminar el proyecto", - "ProjectsPage.deleteErrorMultiple": "Ocurrieron errores al eliminar los proyectos", - "ProjectsPage.deleteModalContent": "¿Realmente desea eliminar el proyecto {name}?", - "ProjectsPage.deleteModalHeader": "Eliminar proyecto", - "ProjectsPage.deleteModalMultipleContent": "¿Realmente desea eliminar los proyectos {names}?", - "ProjectsPage.deleteModalMultipleHeader": "Eliminar proyectos", - "ProjectsPage.deleteProjectsCount": "{count} elementos seleccionados", - "ProjectsPage.deleteSuccess": "El proyecto ha sido eliminado exitosamente", - "ProjectsPage.deleteSuccessMultiple": "Los proyectos han sido eliminados exitosamente", + "ProjectsPage.deleteProjectSuccess": "The project ''{name}'' has been successfully deleted", "ProjectsPage.noResultsDescription": "Your search or filter criteria didn't match any results. Please try different keywords or adjust your filter settings.", "ProjectsPage.projectDuplicateHint": "Ya existe un proyecto con este nombre en el esta organización", "ProjectsPage.projectExists": "Project with the same name already exists in this organization", diff --git a/app/localization/translated/ru.json b/app/localization/translated/ru.json index aac3f495fd..f5cc71ea5d 100644 --- a/app/localization/translated/ru.json +++ b/app/localization/translated/ru.json @@ -324,6 +324,7 @@ "Common.proceedValidItems": "Обработать действительные элементы", "Common.processData": "Подождите, мы обрабатываем ваши данные", "Common.refresh": "Обновить", + "Common.rename": "Переименовать", "Common.requiredFieldHint": "Это поле обязательно", "Common.reset": "Сбросить", "Common.saturday": "Суббота", @@ -578,6 +579,7 @@ "DeleteLaunchModal.warningMultiple": "Вы собираетесь удалить не свой запуски. Это может повлиять на информацию других пользователей проекта.", "DeleteNotificationCaseModal.title": "Удалить правило уведомления", "DeleteNotificationModal.message": "Вы уверены, что хотите удалить это правило уведомлений?", + "DeleteProjectModal.keywordMatcherHint": "Введенный текст не соответствует требуемому ключевому слову", "DeleteWidgetModal.deleteNotOwnWidgetWarning": "Вы собираетесь удалить не свой виджет. Это может повлиять на информацию других пользователей проекта.", "DeleteWidgetModal.deleteOwnWidgetWarning": "Вы собираетесь удалить свой виджет. Это может повлиять на информацию на ваших панелях управления.", "DeleteWidgetModal.deleteWidgetHeader": "Удаление виджета", @@ -1539,7 +1541,11 @@ "NotificationsEnableForm.unableToConfigure": "Почему я не могу настроить его?", "NotificationsEnableForm.unableToConfigureDescription": "Подробнее о ролях и разрешениях", "NotificationsTab.updateProjectNotificationsConfigurationSuccess": "Настройки уведомлений были успешно обновлены!", + "OrganizationProjectsPage.actionInviteUser": "Пригласить пользователя", + "OrganizationProjectsPage.actionUnassign": "Отменить назначение", "OrganizationProjectsPage.allOrganizations": "Все организации", + "OrganizationProjectsPage.confirmDeleteProjectMessage": "Вы уверены, что хотите удалить проект \"{projectName}\"? Это необратимое действие удалит все его данные.", + "OrganizationProjectsPage.confirmProjectNameEntry": "Для подтверждения введите название проекта", "OrganizationProjectsPage.createProject": "Создать проект", "OrganizationProjectsPage.noProjectsListWithPermission": "Создайте новый проект, чтобы начать путешествие по ReportPortal.", "OrganizationProjectsPage.noProjectsListWithoutPermission": "Список доступных вам проектов на данный момент пуст.
За подробностями обращайтесь к менеджеру вашей организации.", @@ -1784,14 +1790,7 @@ "ProjectsPage.assignSuccess": "Вы назначены на проект", "ProjectsPage.dateCol": "Дата", "ProjectsPage.deleteError": "При удалении проекта возникла ошибка", - "ProjectsPage.deleteErrorMultiple": "При удалении проектов возникла ошибка", - "ProjectsPage.deleteModalContent": "Вы действительно хотите удалить проект {name}?", - "ProjectsPage.deleteModalHeader": "Удалить проект", - "ProjectsPage.deleteModalMultipleContent": "Вы действительно хотите удалить проекты {names}?", - "ProjectsPage.deleteModalMultipleHeader": "Удалить проекты", - "ProjectsPage.deleteProjectsCount": "{count} элементов выбрано", - "ProjectsPage.deleteSuccess": "Проект был успешно удалён", - "ProjectsPage.deleteSuccessMultiple": "Проекты были успешно удалены", + "ProjectsPage.deleteProjectSuccess": "Проект ''{name}'' был успешно удален", "ProjectsPage.noResultsDescription": "Ваши критерии поиска или фильтра не дали никаких результатов. Попробуйте другие ключевые слова или измените настройки фильтра.", "ProjectsPage.projectDuplicateHint": "Проект с данным наименованием уже существует в этой организации", "ProjectsPage.projectExists": "Проект с таким названием уже существует в этой организации", diff --git a/app/localization/translated/uk.json b/app/localization/translated/uk.json index 081b780882..93bc7d5fd5 100644 --- a/app/localization/translated/uk.json +++ b/app/localization/translated/uk.json @@ -324,6 +324,7 @@ "Common.proceedValidItems": "Обробити дійсні елементи", "Common.processData": "Зачекайте, ми обробляємо ваші дані", "Common.refresh": "Оновити", + "Common.rename": "Перейменувати", "Common.requiredFieldHint": "Це поле обов’язкове", "Common.reset": "Скинути", "Common.saturday": "Субота", @@ -578,6 +579,7 @@ "DeleteLaunchModal.warningMultiple": "Ви збираєтеся видалити свій запуски. Це може вплинути на інформацію інших користувачів проекту.", "DeleteNotificationCaseModal.title": "Видалити правило повідомлення", "DeleteNotificationModal.message": "Ви впевнені, що хочете видалити це правило сповіщень?", + "DeleteProjectModal.keywordMatcherHint": "Введений текст не відповідає необхідному ключовому слову", "DeleteWidgetModal.deleteNotOwnWidgetWarning": "Ви збираєтеся видалити свій віджет. Це може вплинути на інформацію інших користувачів проекту.", "DeleteWidgetModal.deleteOwnWidgetWarning": "Ви збираєтеся видалити свій віджет. Це може вплинути на інформацію на ваших панелях управління.", "DeleteWidgetModal.deleteWidgetHeader": "Видалення міні-програми", @@ -1541,7 +1543,11 @@ "NotificationsEnableForm.unableToConfigure": "Чому я не можу це налаштувати?", "NotificationsEnableForm.unableToConfigureDescription": "Докладніше про ролі та дозволи", "NotificationsTab.updateProjectNotificationsConfigurationSuccess": "Налаштування сповіщень були успішно оновлені!", + "OrganizationProjectsPage.actionInviteUser": "Запросити користувача", + "OrganizationProjectsPage.actionUnassign": "Скасувати призначення", "OrganizationProjectsPage.allOrganizations": "Всі організації", + "OrganizationProjectsPage.confirmDeleteProjectMessage": "Ви впевнені, що бажаєте видалити проект \"{projectName}\"? Ця необоротна дія призведе до видалення всіх даних.", + "OrganizationProjectsPage.confirmProjectNameEntry": "Для підтвердження введіть назву проекту", "OrganizationProjectsPage.createProject": "Створити проект", "OrganizationProjectsPage.noProjectsListWithPermission": "Створіть новий проект, щоб почати свою подорож ReportPortal", "OrganizationProjectsPage.noProjectsListWithoutPermission": "Список доступних вам проектів наразі порожній.
Зверніться до менеджера вашої організації для отримання деталей.", @@ -1786,14 +1792,7 @@ "ProjectsPage.assignSuccess": "Ви призначені на проект", "ProjectsPage.dateCol": "Дата", "ProjectsPage.deleteError": "При видаленні проекту виникла помилка", - "ProjectsPage.deleteErrorMultiple": "При видаленні проектів виникла помилка", - "ProjectsPage.deleteModalContent": "Вы действительно хотите удалить проект {name}?", - "ProjectsPage.deleteModalHeader": "Видалити проект", - "ProjectsPage.deleteModalMultipleContent": "Вы действительно хотите удалить проекты {names}?", - "ProjectsPage.deleteModalMultipleHeader": "Видалити проекти", - "ProjectsPage.deleteProjectsCount": "{count} елементів вибрано", - "ProjectsPage.deleteSuccess": "Проект був успішно видалений", - "ProjectsPage.deleteSuccessMultiple": "Проекти були успішно видалені", + "ProjectsPage.deleteProjectSuccess": "Проект ''{name}'' успішно видалено", "ProjectsPage.noResultsDescription": "Ваші критерії пошуку чи фільтра не відповідають жодному результату. Будь ласка, спробуйте інші ключові слова або змініть налаштування фільтра.", "ProjectsPage.projectDuplicateHint": "Проект з таким найменуванням вже існує в цій організації", "ProjectsPage.projectExists": "Проект з такою назвою вже існує в цій організації", diff --git a/app/localization/translated/zh.json b/app/localization/translated/zh.json index f61c5d0db9..da6bcca719 100644 --- a/app/localization/translated/zh.json +++ b/app/localization/translated/zh.json @@ -1786,14 +1786,7 @@ "ProjectsPage.assignSuccess": "您已被分配至该项目吗", "ProjectsPage.dateCol": "日期", "ProjectsPage.deleteError": "删除项目的过程中出现错误", - "ProjectsPage.deleteErrorMultiple": "删除项目的过程中出现错误", - "ProjectsPage.deleteModalContent": "您确定要删除项目 {name} 吗?", - "ProjectsPage.deleteModalHeader": "删除此项目", - "ProjectsPage.deleteModalMultipleContent": "您确定要删除项目{names}吗?", - "ProjectsPage.deleteModalMultipleHeader": "删除项目", - "ProjectsPage.deleteProjectsCount": "已选择{count}项", - "ProjectsPage.deleteSuccess": "项目删除成功", - "ProjectsPage.deleteSuccessMultiple": "已选项目删除成功", + "ProjectsPage.deleteProjectSuccess": "The project ''{name}'' has been successfully deleted", "ProjectsPage.noResultsDescription": "Your search or filter criteria didn't match any results. Please try different keywords or adjust your filter settings.", "ProjectsPage.projectDuplicateHint": "Project with the same name already exists in this organization", "ProjectsPage.projectExists": "Project with the same name already exists in this organization", diff --git a/app/package-lock.json b/app/package-lock.json index 8ce2b6379e..459ea75418 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -12,7 +12,7 @@ "@formatjs/intl-pluralrules": "1.3.9", "@formatjs/intl-relativetimeformat": "4.5.1", "@formatjs/intl-utils": "1.6.0", - "@reportportal/ui-kit": "^0.0.1-alpha.30", + "@reportportal/ui-kit": "^0.0.1-alpha.32", "axios": "1.6.4", "c3": "0.7.20", "chart.js": "2.9.4", @@ -3677,9 +3677,9 @@ "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" }, "node_modules/@reportportal/ui-kit": { - "version": "0.0.1-alpha.30", - "resolved": "https://registry.npmjs.org/@reportportal/ui-kit/-/ui-kit-0.0.1-alpha.30.tgz", - "integrity": "sha512-JCznJ79eyOary2dwPXTtwwEcgj2r8KnywiUTg/zTtw8NKeYyOQDj/g1qqdtzmNQJXgXx6f7/5SIoy4VobM01vg==", + "version": "0.0.1-alpha.32", + "resolved": "https://registry.npmjs.org/@reportportal/ui-kit/-/ui-kit-0.0.1-alpha.32.tgz", + "integrity": "sha512-yjEmtKYgHWplNBgLKhNs+GEP1zyt9p9clFXVlfB6/nTTe2mzWxtf/b6I5ajAppDQjTI5cJZ2HFN3zF5hYtRrXw==", "dependencies": { "@floating-ui/react": "^0.26.16", "@floating-ui/react-dom": "^2.0.1", diff --git a/app/package.json b/app/package.json index ccc1b8d98c..14b24fe323 100644 --- a/app/package.json +++ b/app/package.json @@ -25,7 +25,7 @@ "@formatjs/intl-pluralrules": "1.3.9", "@formatjs/intl-relativetimeformat": "4.5.1", "@formatjs/intl-utils": "1.6.0", - "@reportportal/ui-kit": "^0.0.1-alpha.30", + "@reportportal/ui-kit": "^0.0.1-alpha.32", "axios": "1.6.4", "c3": "0.7.20", "chart.js": "2.9.4", diff --git a/app/src/common/constants/localization.js b/app/src/common/constants/localization.js index 467180be46..a1b668373a 100644 --- a/app/src/common/constants/localization.js +++ b/app/src/common/constants/localization.js @@ -31,6 +31,10 @@ export const COMMON_LOCALE_KEYS = defineMessages({ id: 'Common.cancel', defaultMessage: 'Cancel', }, + RENAME: { + id: 'Common.rename', + defaultMessage: 'Rename', + }, CLOSE: { id: 'Common.close', defaultMessage: 'Close', diff --git a/app/src/common/constants/permissions.js b/app/src/common/constants/permissions.js index 9da13dbcbc..9f09a99139 100644 --- a/app/src/common/constants/permissions.js +++ b/app/src/common/constants/permissions.js @@ -24,6 +24,7 @@ export const ACTIONS = { CREATE_PROJECT: 'CREATE_PROJECT', DELETE_PROJECT: 'DELETE_PROJECT', RENAME_PROJECT: 'RENAME_PROJECT', + INVITE_USER_TO_PROJECT: 'INVITE_USER_TO_PROJECT', CHANGE_ACCESS_PROJECT: 'CHANGE_ACCESS_PROJECT', VIEW_INFO_BILLING: 'VIEW_INFO_BILLING', UPDATE_SETTINGS: 'UPDATE_SETTINGS', @@ -94,6 +95,7 @@ export const PERMISSIONS_MAP = { [ACTIONS.CREATE_PROJECT]: true, [ACTIONS.DELETE_PROJECT]: true, [ACTIONS.RENAME_PROJECT]: true, + [ACTIONS.INVITE_USER_TO_PROJECT]: true, [ACTIONS.CHANGE_ACCESS_PROJECT]: true, [ACTIONS.VIEW_INFO_BILLING]: true, [ACTIONS.RENAME_ORGANIZATION]: true, @@ -132,6 +134,7 @@ export const PERMISSIONS_MAP = { [ACTIONS.WORK_WITH_FILTERS]: true, [ACTIONS.WORK_WITH_WIDGETS]: true, [ACTIONS.RENAME_PROJECT]: true, + [ACTIONS.INVITE_USER_TO_PROJECT]: true, [ACTIONS.WORK_WITH_DEFECT_TYPES]: true, [ACTIONS.SEE_DEMO_DATA]: true, [ACTIONS.WORK_WITH_DASHBOARD]: true, diff --git a/app/src/common/urls.js b/app/src/common/urls.js index 93d166f36c..b9144f87ce 100644 --- a/app/src/common/urls.js +++ b/app/src/common/urls.js @@ -131,6 +131,8 @@ export const URLS = { `${urlCommonBase}organizations/${organizationId}/projects${getQueryParams(preferencesObj)}`, organizationUsers: (organizationId, preferencesObj = {}) => `${urlCommonBase}organizations/${organizationId}/users${getQueryParams(preferencesObj)}`, + projectDelete: ({ organizationId, projectId }) => + `${urlCommonBase}organizations/${organizationId}/projects/${projectId}`, projectByName: (projectKey) => `${urlBase}project/${projectKey}`, project: (ids = []) => `${urlBase}project?ids=${ids.join(',')}`, diff --git a/app/src/common/utils/permissions/permissions.js b/app/src/common/utils/permissions/permissions.js index 9cc74386c3..c7ca057613 100644 --- a/app/src/common/utils/permissions/permissions.js +++ b/app/src/common/utils/permissions/permissions.js @@ -44,6 +44,7 @@ export const hasAccessToManagementSystem = checkPermission(ACTIONS.ACCESS_TO_MAN export const canCreateProject = checkPermission(ACTIONS.CREATE_PROJECT); export const canDeleteProject = checkPermission(ACTIONS.DELETE_PROJECT); export const canRenameProject = checkPermission(ACTIONS.RENAME_PROJECT); +export const canInviteUserToProject = checkPermission(ACTIONS.INVITE_USER_TO_PROJECT); export const canChangeAccessProject = checkPermission(ACTIONS.CHANGE_ACCESS_PROJECT); export const canViewInfoBilling = checkPermission(ACTIONS.VIEW_INFO_BILLING); export const canUpdateSettings = checkPermission(ACTIONS.UPDATE_SETTINGS); diff --git a/app/src/common/utils/validation/commonValidators.js b/app/src/common/utils/validation/commonValidators.js index d106e28a0b..15f2a12eb9 100644 --- a/app/src/common/utils/validation/commonValidators.js +++ b/app/src/common/utils/validation/commonValidators.js @@ -84,3 +84,6 @@ export const createDescriptionValidator = bindMessageToValidator( validate.descriptionField, 'descriptionHint', ); + +export const createKeywordMatcherValidator = (keyword) => + bindMessageToValidator(validate.keywordMatcher(keyword), 'keywordMatcherHint'); diff --git a/app/src/common/utils/validation/validate.js b/app/src/common/utils/validation/validate.js index 91b3d72408..bcc0e94af0 100644 --- a/app/src/common/utils/validation/validate.js +++ b/app/src/common/utils/validation/validate.js @@ -132,3 +132,5 @@ export const uniqueApiKeyName = (names) => (value) => names.every((name) => name.toLowerCase() !== value.trim().toLowerCase()); export const deleteAccountFeedbackOtherValue = maxLength(128); export const anyOptionSelected = (options) => Object.values(options).some((option) => !!option); +export const keywordMatcher = (keyword) => (value) => + keyword.toLowerCase().trim() === value?.toLowerCase()?.trim(); diff --git a/app/src/components/fields/fieldErrorHint/fieldErrorHint.jsx b/app/src/components/fields/fieldErrorHint/fieldErrorHint.jsx index df9625179c..104bf7ef76 100644 --- a/app/src/components/fields/fieldErrorHint/fieldErrorHint.jsx +++ b/app/src/components/fields/fieldErrorHint/fieldErrorHint.jsx @@ -264,6 +264,10 @@ const messages = defineMessages({ id: 'DeleteAccountFeedbackModal.deleteAccountReasonSizeHint', defaultMessage: 'The field should have size not more than 128 symbols.', }, + keywordMatcherHint: { + id: 'DeleteProjectModal.keywordMatcherHint', + defaultMessage: 'The entered text does not match the required keyword', + }, }); @injectIntl diff --git a/app/src/components/main/notification/notificationList/notificationListItem/notificationItem.jsx b/app/src/components/main/notification/notificationList/notificationListItem/notificationItem.jsx index 711ba276d3..22edc47097 100644 --- a/app/src/components/main/notification/notificationList/notificationListItem/notificationItem.jsx +++ b/app/src/components/main/notification/notificationList/notificationListItem/notificationItem.jsx @@ -52,6 +52,10 @@ const messages = defineMessages({ id: 'ProjectsPage.deleteError', defaultMessage: 'An error occurred during deleting the project', }, + deleteProjectSuccess: { + id: 'ProjectsPage.deleteProjectSuccess', + defaultMessage: "The project ''{name}'' has been successfully deleted", + }, addDefectTypeSuccess: { id: 'Project.addDefectTypeSuccess', defaultMessage: 'Defect Type has been successfully created', diff --git a/app/src/controllers/organization/projects/actionCreators.js b/app/src/controllers/organization/projects/actionCreators.js index cab6d4b96a..d6117f8c2a 100644 --- a/app/src/controllers/organization/projects/actionCreators.js +++ b/app/src/controllers/organization/projects/actionCreators.js @@ -14,7 +14,7 @@ * limitations under the License. */ -import { CREATE_PROJECT, FETCH_ORGANIZATION_PROJECTS } from './constants'; +import { CREATE_PROJECT, DELETE_PROJECT, FETCH_ORGANIZATION_PROJECTS } from './constants'; export const fetchOrganizationProjectsAction = (params) => { return { @@ -27,3 +27,8 @@ export const createProjectAction = (project) => ({ type: CREATE_PROJECT, payload: project, }); + +export const deleteProjectAction = (project) => ({ + type: DELETE_PROJECT, + payload: project, +}); diff --git a/app/src/controllers/organization/projects/constants.js b/app/src/controllers/organization/projects/constants.js index 051c1bd9bd..c9f1abcb85 100644 --- a/app/src/controllers/organization/projects/constants.js +++ b/app/src/controllers/organization/projects/constants.js @@ -20,6 +20,7 @@ import { formatSortingString, SORTING_ASC } from 'controllers/sorting'; export const FETCH_ORGANIZATION_PROJECTS = 'fetchOrganizationProjects'; export const NAMESPACE = 'organizationProjects'; export const CREATE_PROJECT = 'createProject'; +export const DELETE_PROJECT = 'deleteProject'; export const DEFAULT_LIMITATION = 20; export const DEFAULT_OFFSET = 0; export const DEFAULT_SORT_COLUMN = 'name'; diff --git a/app/src/controllers/organization/projects/sagas.js b/app/src/controllers/organization/projects/sagas.js index c090cf9492..e06d9044fe 100644 --- a/app/src/controllers/organization/projects/sagas.js +++ b/app/src/controllers/organization/projects/sagas.js @@ -24,7 +24,13 @@ import { fetchOrganizationBySlugAction } from '..'; import { querySelector } from './selectors'; import { activeOrganizationSelector } from '../selectors'; import { fetchOrganizationProjectsAction } from './actionCreators'; -import { CREATE_PROJECT, FETCH_ORGANIZATION_PROJECTS, ERROR_CODES, NAMESPACE } from './constants'; +import { + CREATE_PROJECT, + FETCH_ORGANIZATION_PROJECTS, + ERROR_CODES, + NAMESPACE, + DELETE_PROJECT, +} from './constants'; function* fetchOrganizationProjects({ payload: organizationId }) { const query = yield select(querySelector); @@ -79,6 +85,37 @@ function* watchCreateProject() { yield takeEvery(CREATE_PROJECT, createProject); } +function* deleteProject({ payload: { projectId, projectName } }) { + const { id: organizationId, slug: organizationSlug } = yield select(activeOrganizationSelector); + try { + yield call(fetch, URLS.projectDelete({ organizationId, projectId }), { + method: 'delete', + }); + yield put(fetchOrganizationBySlugAction(organizationSlug)); + yield put(fetchOrganizationProjectsAction(organizationId)); + yield put(hideModalAction()); + yield put( + showNotification({ + messageId: 'deleteProjectSuccess', + type: NOTIFICATION_TYPES.SUCCESS, + values: { name: projectName }, + }), + ); + } catch (err) { + const error = err.message; + yield put( + showNotification({ + messageId: 'deleteError', + type: NOTIFICATION_TYPES.ERROR, + values: { error }, + }), + ); + } +} + +function* watchDeleteProject() { + yield takeEvery(DELETE_PROJECT, deleteProject); +} export function* projectsSagas() { - yield all([watchFetchProjects(), watchCreateProject()]); + yield all([watchFetchProjects(), watchCreateProject(), watchDeleteProject()]); } diff --git a/app/src/pages/instance/organizationsPage/organizationsPanelView/organizationsTable/organizationsTable.jsx b/app/src/pages/instance/organizationsPage/organizationsPanelView/organizationsTable/organizationsTable.jsx index 6004bac2c2..83e1c5c20a 100644 --- a/app/src/pages/instance/organizationsPage/organizationsPanelView/organizationsTable/organizationsTable.jsx +++ b/app/src/pages/instance/organizationsPage/organizationsPanelView/organizationsTable/organizationsTable.jsx @@ -117,7 +117,7 @@ export const OrganizationsTable = ({ organizationsList }) => { }, ]; - const rowActionMenu = ( + const renderRowActions = () => ( { data={data} primaryColumn={primaryColumn} fixedColumns={fixedColumns} - rowActionMenu={rowActionMenu} + renderRowActions={renderRowActions} sortableColumns={[]} /> diff --git a/app/src/pages/organization/common/membersPage/membersListTable/membersListTable.jsx b/app/src/pages/organization/common/membersPage/membersListTable/membersListTable.jsx index d1d782e6c2..c2e4057bfa 100644 --- a/app/src/pages/organization/common/membersPage/membersListTable/membersListTable.jsx +++ b/app/src/pages/organization/common/membersPage/membersListTable/membersListTable.jsx @@ -29,7 +29,7 @@ export const MembersListTable = ({ fixedColumns, onTableSorting, showPagination, - rowActionMenu, + renderRowActions, sortingDirection, pageSize, activePage, @@ -54,7 +54,7 @@ export const MembersListTable = ({ data={data} primaryColumn={primaryColumn} fixedColumns={fixedColumns} - rowActionMenu={rowActionMenu} + renderRowActions={renderRowActions} className={cx('members-list-table')} sortingColumn={primaryColumn} sortingDirection={sortingDirection.toLowerCase()} @@ -71,7 +71,7 @@ MembersListTable.propTypes = { fixedColumns: PropTypes.array.isRequired, onTableSorting: PropTypes.func.isRequired, showPagination: PropTypes.bool.isRequired, - rowActionMenu: PropTypes.node, + renderRowActions: PropTypes.func, sortingDirection: PropTypes.string.isRequired, pageSize: PropTypes.number.isRequired, activePage: PropTypes.number.isRequired, diff --git a/app/src/pages/organization/organizationProjectsPage/index.js b/app/src/pages/organization/organizationProjectsPage/index.js index 6c4a93001d..cae3eb517b 100644 --- a/app/src/pages/organization/organizationProjectsPage/index.js +++ b/app/src/pages/organization/organizationProjectsPage/index.js @@ -15,4 +15,4 @@ */ export { OrganizationProjectsPage } from './organizationProjectsPage'; -export { AddProjectModal } from 'pages/organization/organizationProjectsPage/modals'; +export { AddProjectModal } from './modals/addProjectModal'; diff --git a/app/src/pages/organization/organizationProjectsPage/messages.js b/app/src/pages/organization/organizationProjectsPage/messages.js index 7a9edf79cc..b8319ca5a2 100644 --- a/app/src/pages/organization/organizationProjectsPage/messages.js +++ b/app/src/pages/organization/organizationProjectsPage/messages.js @@ -87,4 +87,21 @@ export const messages = defineMessages({ id: 'ProjectsPage.searchPlaceholder', defaultMessage: 'Type to search by name', }, + actionInviteUser: { + id: 'OrganizationProjectsPage.actionInviteUser', + defaultMessage: 'Invite user', + }, + actionUnassign: { + id: 'OrganizationProjectsPage.actionUnassign', + defaultMessage: 'Unassign', + }, + confirmProjectNameEntry: { + id: 'OrganizationProjectsPage.confirmProjectNameEntry', + defaultMessage: 'To confirm, please enter the name of the project', + }, + confirmDeleteProjectMessage: { + id: 'OrganizationProjectsPage.confirmDeleteProjectMessage', + defaultMessage: + 'Are you sure you want to delete the "{projectName}" project? This irreversible action will delete all its data.', + }, }); diff --git a/app/src/pages/organization/organizationProjectsPage/modals/addProjectModal.jsx b/app/src/pages/organization/organizationProjectsPage/modals/addProjectModal/addProjectModal.jsx similarity index 98% rename from app/src/pages/organization/organizationProjectsPage/modals/addProjectModal.jsx rename to app/src/pages/organization/organizationProjectsPage/modals/addProjectModal/addProjectModal.jsx index cfe8d493d7..42df74e71f 100644 --- a/app/src/pages/organization/organizationProjectsPage/modals/addProjectModal.jsx +++ b/app/src/pages/organization/organizationProjectsPage/modals/addProjectModal/addProjectModal.jsx @@ -26,7 +26,7 @@ import { COMMON_LOCALE_KEYS } from 'common/constants/localization'; import { Modal, FieldText } from '@reportportal/ui-kit'; import { hideModalAction } from 'controllers/modal'; import { useDispatch } from 'react-redux'; -import { messages } from '../messages'; +import { messages } from '../../messages'; const PROJECT_NAME_FIELD = 'projectName'; export const AddProjectModal = ({ data = {}, handleSubmit, anyTouched, invalid }) => { diff --git a/app/src/pages/organization/organizationProjectsPage/modals/index.js b/app/src/pages/organization/organizationProjectsPage/modals/addProjectModal/index.js similarity index 100% rename from app/src/pages/organization/organizationProjectsPage/modals/index.js rename to app/src/pages/organization/organizationProjectsPage/modals/addProjectModal/index.js diff --git a/app/src/pages/organization/organizationProjectsPage/modals/deleteProjectModal/deleteProjectModal.jsx b/app/src/pages/organization/organizationProjectsPage/modals/deleteProjectModal/deleteProjectModal.jsx new file mode 100644 index 0000000000..5ea84674a7 --- /dev/null +++ b/app/src/pages/organization/organizationProjectsPage/modals/deleteProjectModal/deleteProjectModal.jsx @@ -0,0 +1,98 @@ +/* + * Copyright 2024 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import { useIntl } from 'react-intl'; +import { reduxForm } from 'redux-form'; +import { FieldErrorHint } from 'components/fields/fieldErrorHint'; +import { FieldProvider } from 'components/fields/fieldProvider'; +import { commonValidators } from 'common/utils/validation'; +import { withModal } from 'components/main/modal'; +import { COMMON_LOCALE_KEYS } from 'common/constants/localization'; +import { Modal, FieldText } from '@reportportal/ui-kit'; +import { hideModalAction } from 'controllers/modal'; +import { useDispatch } from 'react-redux'; +import classNames from 'classnames/bind'; +import { messages } from '../../messages'; +import styles from './deleteProjectModal.scss'; + +const cx = classNames.bind(styles); + +const PROJECT_NAME_FIELD = 'projectName'; +const DELETE_PROJECT_FORM = 'deleteProjectForm'; + +export const DeleteProjectModal = ({ data: { onSave, projectDetails }, handleSubmit }) => { + const dispatch = useDispatch(); + const { formatMessage } = useIntl(); + + const hideModal = () => dispatch(hideModalAction()); + const handleDelete = () => { + const { projectId, projectName } = projectDetails; + onSave({ projectId, projectName }); + }; + + return ( + { + handleSubmit(handleDelete)(); + }, + variant: 'danger', + }} + cancelButton={{ + children: formatMessage(COMMON_LOCALE_KEYS.CANCEL), + }} + onClose={hideModal} + > +

+ {formatMessage(messages.confirmDeleteProjectMessage, { + projectName: projectDetails?.projectName, + })} +

+ + + + + +
+ ); +}; + +DeleteProjectModal.propTypes = { + data: PropTypes.object, + handleSubmit: PropTypes.func, +}; + +export default withModal('deleteProjectModal')( + reduxForm({ + form: DELETE_PROJECT_FORM, + validate: ({ projectName: inputProjectValue }, { data: { projectDetails } }) => { + return { + projectName: commonValidators.createKeywordMatcherValidator(projectDetails.projectName)( + inputProjectValue, + ), + }; + }, + })(DeleteProjectModal), +); diff --git a/app/src/pages/organization/organizationProjectsPage/modals/deleteProjectModal/deleteProjectModal.scss b/app/src/pages/organization/organizationProjectsPage/modals/deleteProjectModal/deleteProjectModal.scss new file mode 100644 index 0000000000..e1a300694b --- /dev/null +++ b/app/src/pages/organization/organizationProjectsPage/modals/deleteProjectModal/deleteProjectModal.scss @@ -0,0 +1,19 @@ +/*! + * Copyright 2024 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.message{ + margin-bottom: 16px; +} \ No newline at end of file diff --git a/app/src/pages/organization/organizationProjectsPage/modals/deleteProjectModal/index.js b/app/src/pages/organization/organizationProjectsPage/modals/deleteProjectModal/index.js new file mode 100644 index 0000000000..5fff546a18 --- /dev/null +++ b/app/src/pages/organization/organizationProjectsPage/modals/deleteProjectModal/index.js @@ -0,0 +1,17 @@ +/*! + * Copyright 2024 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { DeleteProjectModal } from './deleteProjectModal'; diff --git a/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectActionMenu/index.js b/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectActionMenu/index.js new file mode 100644 index 0000000000..9311928e9d --- /dev/null +++ b/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectActionMenu/index.js @@ -0,0 +1,18 @@ +/*! + * Copyright 2024 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { ProjectActionMenu } from './projectActionMenu'; +export { DeleteProjectModal } from '../../modals/deleteProjectModal'; diff --git a/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectActionMenu/projectActionMenu.jsx b/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectActionMenu/projectActionMenu.jsx new file mode 100644 index 0000000000..9c80d6fff0 --- /dev/null +++ b/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectActionMenu/projectActionMenu.jsx @@ -0,0 +1,133 @@ +/*! + * Copyright 2024 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { MeatballMenuIcon, Popover } from '@reportportal/ui-kit'; +import classNames from 'classnames/bind'; +import Link from 'redux-first-router-link'; +import { useDispatch, useSelector } from 'react-redux'; +import React, { useMemo } from 'react'; +import PropTypes from 'prop-types'; +import { setActiveProjectKeyAction } from 'controllers/user'; +import { + canDeleteProject, + canInviteUserToProject, + canRenameProject, +} from 'common/utils/permissions/permissions'; +import { userRolesSelector } from 'controllers/pages'; +import { showModalAction } from 'controllers/modal'; +import { deleteProjectAction } from 'controllers/organization/projects/actionCreators'; +import { useIntl } from 'react-intl'; +import { COMMON_LOCALE_KEYS } from 'common/constants/localization'; +import { messages } from '../../messages'; +import styles from './projectActionMenu.scss'; + +const cx = classNames.bind(styles); + +export const ProjectActionMenu = ({ details }) => { + const { projectName, projectKey, projectId, projectSlug, organizationSlug } = details; + const userRoles = useSelector(userRolesSelector); + const dispatch = useDispatch(); + const { formatMessage } = useIntl(); + const actionsButtons = useMemo(() => { + return [ + { + actionLabel: formatMessage(COMMON_LOCALE_KEYS.RENAME), + onclick: () => {}, + hasPermission: canRenameProject(userRoles), + }, + { + actionLabel: formatMessage(messages.actionInviteUser), + onclick: () => {}, + hasPermission: canInviteUserToProject(userRoles), + }, + { + actionLabel: formatMessage(messages.actionUnassign), + onclick: () => {}, + hasPermission: true, + }, + { + actionLabel: formatMessage(COMMON_LOCALE_KEYS.DELETE), + onclick: () => { + dispatch( + showModalAction({ + id: 'deleteProjectModal', + data: { + projectDetails: details, + onSave: () => { + dispatch(deleteProjectAction({ projectName, projectId })); + }, + }, + }), + ); + }, + className: cx('delete-button'), + hasPermission: canDeleteProject(userRoles), + }, + ]; + }, [userRoles]); + + return ( + + dispatch(setActiveProjectKeyAction(projectKey))} + > + Settings + + dispatch(setActiveProjectKeyAction(projectKey))} + > + Team + +
+ {actionsButtons.map( + (button) => + button.hasPermission && ( + + ), + )} +
+ } + className={cx('actions-popover')} + > + + + +
+ ); +}; + +ProjectActionMenu.propTypes = { + details: PropTypes.object, +}; diff --git a/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectActionMenu/projectActionMenu.scss b/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectActionMenu/projectActionMenu.scss new file mode 100644 index 0000000000..7d6f13287d --- /dev/null +++ b/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectActionMenu/projectActionMenu.scss @@ -0,0 +1,53 @@ +/*! + * Copyright 2024 EPAM Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.actions-popover { + padding: 8px 0; +} + +.action-dropdown { + display: flex; + flex-direction: column; + width: 120px; + + .action-item { + padding: 8px 16px; + align-items: center; + font-size: 13px; + line-height: 20px; + font-family: $FONT-ROBOTO-REGULAR; + color: $COLOR--almost-black; + cursor: pointer; + text-decoration: none; + outline: none; + background: none; + border: none; + text-align: start; + + &.delete-button { + color: $COLOR--error; + } + + &:hover { + filter: brightness(80%); + } + } +} + +.divider { + height: 1px; + background-color: $COLOR--e-100; + margin: 8px 12px; +} \ No newline at end of file diff --git a/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectsListTable.jsx b/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectsListTable.jsx index cdb6b09e29..d1e0d2439e 100644 --- a/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectsListTable.jsx +++ b/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectsListTable.jsx @@ -17,7 +17,7 @@ import { useMemo } from 'react'; import PropTypes from 'prop-types'; import { useIntl } from 'react-intl'; -import { MeatballMenuIcon, Popover, Table } from '@reportportal/ui-kit'; +import { Table } from '@reportportal/ui-kit'; import classNames from 'classnames/bind'; import { useDispatch, useSelector } from 'react-redux'; import { AbsRelTime } from 'components/main/absRelTime'; @@ -36,6 +36,7 @@ import { SORTING_KEY, } from 'controllers/organization/projects'; import { NAMESPACE } from 'controllers/organization/projects/constants'; +import { ProjectActionMenu } from 'pages/organization/organizationProjectsPage/projectsListTable/projectActionMenu'; import { messages } from '../messages'; import { ProjectName } from './projectName'; import styles from './projectsListTable.scss'; @@ -64,20 +65,20 @@ export const ProjectsListTable = ({ () => projects.map((project) => { const lastLaunch = project.stats.launch_stats.last_occurred_at; + const metaData = { + projectName: project.name, + projectSlug: project.slug, + projectKey: project.key, + projectId: project.id, + organizationSlug, + }; return { id: project.id, name: { content: project.name, component: (
- +
), }, @@ -91,6 +92,7 @@ export const ProjectsListTable = ({ n/a ), }, + metaData, }; }), [projects, organizationSlug], @@ -121,22 +123,6 @@ export const ProjectsListTable = ({ }, ]; - const rowActionMenu = ( - -

Edit

-

Rename

- - } - > - - - -
- ); - return ( 0} @@ -156,7 +142,7 @@ export const ProjectsListTable = ({ sortingDirection={sortingDirection.toLowerCase()} sortingColumn={primaryColumn} sortableColumns={primaryColumn.key} - rowActionMenu={rowActionMenu} + renderRowActions={(metaData) => } className={cx('projects-list-table')} onChangeSorting={onTableColumnSort} /> diff --git a/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectsListTable.scss b/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectsListTable.scss index d3c6972ae1..200f63d2ed 100644 --- a/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectsListTable.scss +++ b/app/src/pages/organization/organizationProjectsPage/projectsListTable/projectsListTable.scss @@ -28,27 +28,6 @@ } } -.row-action-dropdown { - display: flex; - flex-direction: column; - - p { - padding: 7px 16px; - align-items: center; - font-size: 13px; - line-height: 20px; - width: 88px; - - &.rename { - color: $COLOR--almost-black; - } - - &.delete { - color: $COLOR--error; - } - } -} - .project-name-col { display: flex; flex-direction: column; diff --git a/app/src/pages/organization/organizationUsersPage/organizationUsersListTable/organizationUsersListTable.jsx b/app/src/pages/organization/organizationUsersPage/organizationUsersListTable/organizationUsersListTable.jsx index 07d79ee9e3..44e31eb712 100644 --- a/app/src/pages/organization/organizationUsersPage/organizationUsersListTable/organizationUsersListTable.jsx +++ b/app/src/pages/organization/organizationUsersPage/organizationUsersListTable/organizationUsersListTable.jsx @@ -138,7 +138,7 @@ const OrgTeamListTableWrapped = ({ [formatMessage], ); - const rowActionMenu = ( + const renderRowActions = () => ( ( 0} - rowActionMenu={canSeeRowActionMenu(userRoles) ? rowActionMenu : null} + renderRowActions={canSeeRowActionMenu(userRoles) ? renderRowActions : null} sortingDirection={sortingDirection} pageSize={pageSize} activePage={activePage}