diff --git a/app/localization/translated/be.json b/app/localization/translated/be.json index 695fade7a8..2d38e28316 100644 --- a/app/localization/translated/be.json +++ b/app/localization/translated/be.json @@ -1486,7 +1486,7 @@ "NotificationsEnableForm.integrationSettings": "Налады інтэграцыі", "NotificationsEnableForm.integrationSettingsDescription": "Наладзьце злучэнне плагінаў з серверамі", "NotificationsEnableForm.notConfiguredIntegration": "Integration not configured yet", - "NotificationsEnableForm.tabDescription": "Кіруйце апавяшчэннямі аб запуску для розных каналаў сувязі: Email, Slack, Teams і г.д.", + "NotificationsEnableForm.tabDescription": "Кіруйце апавяшчэннямі аб запуску для розных каналаў сувязі: Email, Slack, і г.д.", "NotificationsEnableForm.title": "Няма інтэграцыі з E-mail серверам", "NotificationsEnableForm.toggleNotificationsLabel": "Аўтаматычныя апавяшчэнні па электроннай пошце", "NotificationsEnableForm.toggleNotificationsNote": "Адпраўляць апавяшчэнні па электроннай пошце аб заканчэнні запуску", diff --git a/app/localization/translated/ru.json b/app/localization/translated/ru.json index a22fed1a01..7c36c6ddda 100644 --- a/app/localization/translated/ru.json +++ b/app/localization/translated/ru.json @@ -1486,7 +1486,7 @@ "NotificationsEnableForm.integrationSettings": "Настройки интеграции", "NotificationsEnableForm.integrationSettingsDescription": "Настройте соединение плагинов с серверами", "NotificationsEnableForm.notConfiguredIntegration": "Интеграция еще не настроена", - "NotificationsEnableForm.tabDescription": "Управляйте уведомлениями, связанными с запуском, для разных каналов связи: E-mail, Slack, Teams и т. д.", + "NotificationsEnableForm.tabDescription": "Управляйте уведомлениями, связанными с запуском, для разных каналов связи: E-mail, Slack, и т. д.", "NotificationsEnableForm.title": "Нет интеграции с E-mail сервером", "NotificationsEnableForm.toggleNotificationsLabel": "Автоматические уведомления по электронной почте", "NotificationsEnableForm.toggleNotificationsNote": "Отправлять уведомления по электронной почте о завершении запуска", diff --git a/app/localization/translated/uk.json b/app/localization/translated/uk.json index 533205d8ed..0511d89f84 100644 --- a/app/localization/translated/uk.json +++ b/app/localization/translated/uk.json @@ -1486,7 +1486,7 @@ "NotificationsEnableForm.integrationSettings": "Налаштування інтеграції", "NotificationsEnableForm.integrationSettingsDescription": "Налаштувати підключення плагінів до серверів", "NotificationsEnableForm.notConfiguredIntegration": "Інтеграцію ще не налаштовано", - "NotificationsEnableForm.tabDescription": "Керуйте повідомленнями, пов'язаними із запуском, для різних каналів зв'язку: Email, Slack, Teams і т.д.", + "NotificationsEnableForm.tabDescription": "Керуйте повідомленнями, пов'язаними із запуском, для різних каналів зв'язку: Email, Slack, і т.д.", "NotificationsEnableForm.title": "Немає інтеграції з електронною поштою сервером", "NotificationsEnableForm.toggleNotificationsLabel": "Автоматичне сповіщення електронною поштою", "NotificationsEnableForm.toggleNotificationsNote": "Надсилайте сповіщення електронною поштою про завершення запуску", diff --git a/app/localization/translated/zh.json b/app/localization/translated/zh.json index e589ebb0bf..06f100e8d6 100644 --- a/app/localization/translated/zh.json +++ b/app/localization/translated/zh.json @@ -1486,7 +1486,7 @@ "NotificationsEnableForm.integrationSettings": "集成设置", "NotificationsEnableForm.integrationSettingsDescription": "配置插件与服务器的连接", "NotificationsEnableForm.notConfiguredIntegration": "尚未配置集成", - "NotificationsEnableForm.tabDescription": "跨多个通信渠道管理与启动相关的通知:Email、Slack、Teams 等。", + "NotificationsEnableForm.tabDescription": "跨多个通信渠道管理与启动相关的通知:Email、Slack, 等。", "NotificationsEnableForm.title": "未与电子邮件集成", "NotificationsEnableForm.toggleNotificationsLabel": "电子邮件通知", "NotificationsEnableForm.toggleNotificationsNote": "在启测试任务成时发送电子邮件通知", @@ -2194,4 +2194,4 @@ "usersGrid.roleNonAdmin": "非管理", "usersGrid.type": "类型", "usersGrid.user": "登录" -} \ No newline at end of file +} diff --git a/app/src/common/constants/retentionPolicy.js b/app/src/common/constants/retentionPolicy.js new file mode 100644 index 0000000000..cdfa0b2ab6 --- /dev/null +++ b/app/src/common/constants/retentionPolicy.js @@ -0,0 +1,20 @@ +/* + * 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 const RETENTION_POLICY = { + REGULAR: 'REGULAR', + IMPORTANT: 'IMPORTANT', +}; diff --git a/app/src/common/img/star-inline.svg b/app/src/common/img/star-inline.svg new file mode 100644 index 0000000000..8c87092520 --- /dev/null +++ b/app/src/common/img/star-inline.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/common/urls.js b/app/src/common/urls.js index 3e2c3b13ca..9f4abd5b91 100644 --- a/app/src/common/urls.js +++ b/app/src/common/urls.js @@ -35,8 +35,8 @@ export const URLS = { apiDocs: (apiType) => `${apiType}/api-docs`, dataPhoto: (at, loadThumbnail) => `${urlBase}data/photo${getQueryParams({ at, loadThumbnail })}`, - dataUserPhoto: (projectKey, id, loadThumbnail) => - `${urlBase}data/${projectKey}/userphoto${getQueryParams({ id, loadThumbnail })}`, + dataUserPhoto: (projectKey, login, loadThumbnail) => + `${urlBase}data/${projectKey}/userphoto${getQueryParams({ login, loadThumbnail })}`, dashboard: (projectKey, id) => `${urlBase}${projectKey}/dashboard/${id}`, dashboards: (projectKey) => @@ -137,8 +137,8 @@ export const URLS = { projectDefectType: (projectKey) => `${urlBase}${projectKey}/settings/sub-type`, projectDeleteDefectType: (projectKey, id) => `${urlBase}${projectKey}/settings/sub-type/${id}`, projects: () => `${urlBase}project/list`, - projectPreferences: (projectKey, userId, filterId = '') => - `${urlBase}project/${projectKey}/preference/${userId}/${filterId}`, + projectPreferences: (projectKey, filterId = '') => + `${urlBase}project/${projectKey}/preference/${filterId}`, projectUsers: (projectKey) => `${urlBase}project/${projectKey}/users`, projectUserSearchUser: (projectKey) => (searchTerm) => `${urlBase}project/${projectKey}/usernames/search${getQueryParams({ diff --git a/app/src/components/extensionLoader/extensionLoader.jsx b/app/src/components/extensionLoader/extensionLoader.jsx index 46dcc9f0cc..fa96fdd087 100644 --- a/app/src/components/extensionLoader/extensionLoader.jsx +++ b/app/src/components/extensionLoader/extensionLoader.jsx @@ -1,30 +1,37 @@ +/* + * 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 { BubblesLoader } from '@reportportal/ui-kit'; +import { PLUGIN_TYPE_REMOTE } from 'controllers/plugins/uiExtensions/constants'; import { ErrorBoundary } from 'components/containers/errorBoundary'; -import { createImportProps } from 'controllers/plugins/uiExtensions/createImportProps'; import { ExtensionError } from './extensionError'; import { extensionType } from './extensionTypes'; -import { useFederatedComponent } from './hooks'; -import { getExtensionUrl } from './utils'; +import { FederatedExtensionLoader } from './federatedExtensionLoader'; +import { StandaloneExtensionLoader } from './standaloneExtensionLoader'; function ExtensionLoader({ extension, withPreloader, ...componentProps }) { - const { moduleName, scope, pluginName } = extension; - const url = getExtensionUrl(extension); - - const { failed, Component } = useFederatedComponent(scope, moduleName, url); - - if (failed) { - return

Failed to load extension: {moduleName}

; - } - - // TODO: remove legacy extensions when all existing plugins will be migrated to the new engine - const extensionImportProps = createImportProps(pluginName); - - return ( - : null}> - {Component ? : null} - + return extension.pluginType === PLUGIN_TYPE_REMOTE ? ( + + ) : ( + ); } ExtensionLoader.propTypes = { @@ -44,6 +51,7 @@ export function ExtensionLoaderWrapper({ }) { return ( }> + {/* TODO: remove legacy extensions when all existing plugins will be migrated to the new engine */} {extension.component ? ( ) : ( diff --git a/app/src/components/extensionLoader/extensionTypes.js b/app/src/components/extensionLoader/extensionTypes.js index de12e1159e..e92f4c239b 100644 --- a/app/src/components/extensionLoader/extensionTypes.js +++ b/app/src/components/extensionLoader/extensionTypes.js @@ -1,4 +1,21 @@ +/* + * 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 PropTypes from 'prop-types'; +import { PLUGIN_TYPE_REMOTE } from 'controllers/plugins/uiExtensions/constants'; /* TODO: remove legacy extensions when all existing plugins will be migrated to the new engine and within next major version release */ @@ -11,13 +28,31 @@ const oldExtensionType = PropTypes.shape({ /* New plugins mechanism related code below */ -const newExtensionType = PropTypes.shape({ +const embeddedExtensionType = PropTypes.shape({ name: PropTypes.string.isRequired, title: PropTypes.string, + // TODO: describe this field more specifically type: PropTypes.string.isRequired, moduleName: PropTypes.string, scope: PropTypes.string, pluginName: PropTypes.string.isRequired, }); -export const extensionType = PropTypes.oneOfType([oldExtensionType, newExtensionType]); +const standaloneExtensionType = PropTypes.shape({ + pluginName: PropTypes.string.isRequired, + pluginType: PropTypes.oneOf([PLUGIN_TYPE_REMOTE]), + // TODO: describe this field more specifically + type: PropTypes.string.isRequired, + url: PropTypes.string.isRequired, + internalRoute: PropTypes.string, + icon: PropTypes.shape({ + url: PropTypes.string, + svg: PropTypes.string, + }), +}); + +export const extensionType = PropTypes.oneOfType([ + oldExtensionType, + embeddedExtensionType, + standaloneExtensionType, +]); diff --git a/app/src/components/extensionLoader/federatedExtensionLoader/federatedExtensionLoader.jsx b/app/src/components/extensionLoader/federatedExtensionLoader/federatedExtensionLoader.jsx new file mode 100644 index 0000000000..af637a7ed3 --- /dev/null +++ b/app/src/components/extensionLoader/federatedExtensionLoader/federatedExtensionLoader.jsx @@ -0,0 +1,52 @@ +/* + * 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 { BubblesLoader } from '@reportportal/ui-kit'; +import { createImportProps } from 'controllers/plugins/uiExtensions/createImportProps'; +import { getExtensionUrl } from '../utils'; +import { useFederatedComponent } from '../hooks'; +import { extensionType } from '../extensionTypes'; + +export function FederatedExtensionLoader({ extension, withPreloader, ...componentProps }) { + const { moduleName, scope, pluginName } = extension; + const url = getExtensionUrl(extension); + + const { failed, Component } = useFederatedComponent(scope, moduleName, url); + + // TODO: replace with proper failed state + if (failed) { + return

Failed to load extension: {moduleName}

; + } + + // TODO: Provide extensionImportProps via React Context + const extensionImportProps = createImportProps(pluginName); + + return ( + : null}> + {Component ? : null} + + ); +} +FederatedExtensionLoader.propTypes = { + extension: extensionType, + withPreloader: PropTypes.bool, +}; +FederatedExtensionLoader.defaultProps = { + extension: {}, + withPreloader: false, +}; diff --git a/app/src/components/extensionLoader/federatedExtensionLoader/index.js b/app/src/components/extensionLoader/federatedExtensionLoader/index.js new file mode 100644 index 0000000000..73fb756d3e --- /dev/null +++ b/app/src/components/extensionLoader/federatedExtensionLoader/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 { FederatedExtensionLoader } from './federatedExtensionLoader'; diff --git a/app/src/components/extensionLoader/standaloneExtensionLoader/index.js b/app/src/components/extensionLoader/standaloneExtensionLoader/index.js new file mode 100644 index 0000000000..be040cfb9b --- /dev/null +++ b/app/src/components/extensionLoader/standaloneExtensionLoader/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 { StandaloneExtensionLoader } from './standaloneExtensionLoader'; diff --git a/app/src/components/extensionLoader/standaloneExtensionLoader/standaloneExtensionLoader.jsx b/app/src/components/extensionLoader/standaloneExtensionLoader/standaloneExtensionLoader.jsx new file mode 100644 index 0000000000..c00ed6593a --- /dev/null +++ b/app/src/components/extensionLoader/standaloneExtensionLoader/standaloneExtensionLoader.jsx @@ -0,0 +1,78 @@ +/* + * 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, { useRef, useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { userInfoSelector } from 'controllers/user'; +import { projectInfoSelector } from 'controllers/project'; +import { extensionType } from '../extensionTypes'; + +// http://localhost:3000/#superadmin_personal/plugin/BrowserKube +// TODO: add loader while loading the iframe +// TODO: configure sandbox for iframe +function StandaloneExtensionLoader({ extension, userInfo, projectInfo }) { + const [loaded, setLoaded] = useState(false); + const ref = useRef(); + + const onLoad = () => { + setLoaded(true); + }; + + const sendRpContext = () => { + const consumerOrigin = new URL(extension.url).origin; + const data = { + user: userInfo, + project: projectInfo, + }; + ref?.current?.contentWindow.postMessage(data, consumerOrigin); + }; + + useEffect(() => { + if (loaded) { + sendRpContext(); + } + }, [loaded, userInfo, projectInfo]); + + return ( +