diff --git a/CHANGELOG.md b/CHANGELOG.md
index b050ca42d4..b8f4bc5047 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -58,6 +58,11 @@
Salt dependencies from "base" RHEL 7 repository
(PR [#3083](https://github.com/scality/metalk8s/pull/3083))
+### Deprecations and Removals
+
+- [#3168](https://github.com/scality/metalk8s/issues/3168) - [UI] Remove the environment page
+ (PR [#3167](https://github.com/scality/metalk8s/pull/3167))
+
## Release 2.7.4 (in development)
## Release 2.7.3
diff --git a/eve/main.yml b/eve/main.yml
index 0116364830..3c607f14fe 100644
--- a/eve/main.yml
+++ b/eve/main.yml
@@ -2521,30 +2521,6 @@ stages:
env:
<<: *_env_bastion_tests
PYTEST_FILTERS: "solution"
- - SetPropertyFromCommand: *set_bootstrap_cp_ip_ssh
- - ShellCommand: &import_solution_archive_ssh
- name: Import Solution example-solution archive
- env:
- SOLUTION_ARCHIVE: /var/tmp/example-solution.iso
- command: >
- ssh -F ssh_config bootstrap
- sudo /var/tmp/metalk8s/solutions.sh
- import --archive "$SOLUTION_ARCHIVE"
- workdir: build/eve/workers/openstack-terraform/terraform/
- haltOnFailure: true
- - ShellCommand:
- <<: *import_solution_archive_ssh
- name: Import Solution next example-solution archive
- env:
- SOLUTION_ARCHIVE: /var/tmp/example-solution-next.iso
- - ShellCommand:
- <<: *bastion_ui_tests
- name: Run Solutions UI tests
- env:
- <<: *_env_bastion_ui_tests
- TEST_FILTER: "e2esolutions"
- - ShellCommand: *collect_cypress_result_ssh
- - Upload: *upload_cypress_artifacts
- ShellCommand: *generate_report_over_ssh
- ShellCommand:
<<: *collect_report_over_ssh
diff --git a/ui/cypress/integration/e2e/Solutions.feature b/ui/cypress/integration/e2e/Solutions.feature
deleted file mode 100644
index 080cd13d49..0000000000
--- a/ui/cypress/integration/e2e/Solutions.feature
+++ /dev/null
@@ -1,50 +0,0 @@
-Feature: Solutions
-
- I can manage Solutions and Environments from the Solutions page.
-
- @solutions
- Scenario: Add a Solution to Environment
- Given I am logged in
- When I go to the solutions list by clicking the solution icon in the sidebar
- And I go to the Create Environment page by clicking the Create a New Environment button
- And I fill out the Create Environment form and check if the environment I created is displayed on the Environments list
- When I click on the Add Solution button to add a solution to the environment
- Then I fill out the Add Solution form in the modal and I check if the solution is added the environment
-
- @solutions
- Scenario: Create a New Environment
- Given I am logged in
- When I go to the solutions list by clicking the solution icon in the sidebar
- And I go to the Create Environment page by clicking the Create a New Environment button
- Then I fill out the Create Environment form and check if the environment I created is displayed on the Environments list
-
- @solutions
- Scenario: Delete a Environment
- Given I am logged in
- When I go to the solutions list by clicking the solution icon in the sidebar
- And I go to the Create Environment page by clicking the Create a New Environment button
- And I fill out the Create Environment form and check if the environment I created is displayed on the Environments list
- Then I click on the delete button and check if the environment is deleted from the Environments list
-
- @solutions
- Scenario: Upgrade a Solution
- Given I am logged in
- When I go to the solutions list by clicking the solution icon in the sidebar
- And I go to the Create Environment page by clicking the Create a New Environment button
- And I fill out the Create Environment form and check if the environment I created is displayed on the Environments list
- When I click on the Add Solution button to add a solution to the environment
- And I fill out the Add Solution form in the modal and I check if the solution is added the environment
- When I go to the Environment Detail page by clicking the environment list
- Then I click on upgrade button and check the solution is upgraded
-
- @solutions
- Scenario: Downgrade a Solution
- Given I am logged in
- When I go to the solutions list by clicking the solution icon in the sidebar
- And I go to the Create Environment page by clicking the Create a New Environment button
- And I fill out the Create Environment form and check if the environment I created is displayed on the Environments list
- When I click on the Add Solution button to add a solution to the environment
- And I fill out the Add Solution form in the modal and I check if the solution is added the environment
- When I go to the Environment Detail page by clicking the environment list
- And I click on upgrade button and check the solution is upgraded
- Then I click on the downgrade button and check the solution is downgraded
diff --git a/ui/cypress/integration/e2e/Solutions/steps.js b/ui/cypress/integration/e2e/Solutions/steps.js
deleted file mode 100644
index 38b47dab61..0000000000
--- a/ui/cypress/integration/e2e/Solutions/steps.js
+++ /dev/null
@@ -1,169 +0,0 @@
-import { When, Then, And } from 'cypress-cucumber-preprocessor/steps';
-
-const environmentName = `environment-${new Date().getTime()}`;
-const environmentDescription = `Test environment ${environmentName}`;
-const solutionName = 'example-solution';
-const solutionVersion = '0.1.0-dev';
-const upgradeSolutionVersion = '0.1.1-dev';
-
-When(
- 'I go to the solutions list by clicking the solution icon in the sidebar',
- () => {
- cy.server();
-
- cy.route(
- 'GET',
- '/api/kubernetes/api/v1/namespaces?labelSelector=solutions.metalk8s.scality.com/environment',
- ).as('getEnvironmentsList');
-
- cy.get('[data-cy="sidebar_item_environments"]').click(); // go to solutions list
-
- const timeOut = {
- requestTimeout: 60000,
- responseTimeout: 60000,
- };
- cy.wait('@getEnvironmentsList', timeOut);
- cy.get('.sc-table:first .sc-table-row').should('have.length', 1); //Only Table header
- },
-);
-
-And(
- 'I go to the Create Environment page by clicking the Create a New Environment button',
- () => {
- cy.get('[data-cy="create_new_environment_button"]').click();
- },
-);
-
-Then(
- 'I fill out the Create Environment form and check if the environment I created is displayed on the Environments list',
- () => {
- cy.get('input[name=name]').type(environmentName);
- cy.get('textarea[name=description]').type(environmentDescription);
-
- cy.get('[data-cy="submit-create-environment"]').click();
-
- cy.get('.sc-table-column-cell-name').should('contain', environmentName);
- },
-);
-
-When(
- 'I click on the Add Solution button to add a solution to the environment',
- () => {
- cy.get(`[data-cy="add_solution_to_${environmentName}_button"]`).click();
- cy.get('.sc-modal').should('have.length', 1);
- },
-);
-
-Then(
- 'I fill out the Add Solution form in the modal and I check if the solution is added the environment',
- () => {
- cy.route(
- 'GET',
- `api/kubernetes/apis/apps/v1/namespaces/${environmentName}/deployments/example-solution-operator`,
- ).as('getSolutionOperatorDeployment');
-
- cy.get('.sc-modal .sc-select').eq(0).click();
- cy.get(`[data-cy="${solutionName}"]`).click();
- cy.get('.sc-modal .sc-select').eq(1).click();
- cy.get(`[data-cy="${solutionVersion}"]`).click();
-
- cy.get('[data-cy="add_solution_submit_button"]').click();
- // check if the solution name and version displayed in the Environment table
- const timeOut = {
- requestTimeout: 60000,
- responseTimeout: 60000,
- };
- // To make sure the prepare environment is ready, because something we maybe update the env during the preparation
- cy.wait('@getSolutionOperatorDeployment', timeOut);
- cy.wait('@getSolutionOperatorDeployment', timeOut);
-
- cy.get('.sc-table-column-cell-container-solutions').should(
- 'contain',
- `${solutionName} (v.${solutionVersion}`,
- );
- },
-);
-
-Then(
- 'I click on the delete button and check if the environment is deleted from the Environments list',
- () => {
- cy.route(
- 'GET',
- '/api/kubernetes/api/v1/namespaces?labelSelector=solutions.metalk8s.scality.com/environment',
- ).as('getEnvironmentsList');
- cy.route(
- 'DELETE',
- `api/kubernetes/api/v1/namespaces/${environmentName}`,
- ).as('deleteEnvironment');
- cy.route(
- 'GET',
- `api/kubernetes/api/v1/namespaces/metalk8s-solutions/configmaps/metalk8s-solutions`,
- ).as('getEnvironmentConfigMap');
- cy.get(`[data-cy="delete_${environmentName}_button"]`).click();
-
- const timeOut = {
- requestTimeout: 60000,
- responseTimeout: 60000,
- };
- cy.wait('@deleteEnvironment', timeOut);
- cy.wait('@getEnvironmentsList', timeOut);
- cy.wait('@getEnvironmentConfigMap', timeOut); // wait until the next time updating the environment
-
- cy.get('.sc-table-column-cell-name').should('not.contain', environmentName); // check the environment I created is being deleted
- },
-);
-
-When(
- 'I go to the Environment Detail page by clicking the environment list',
- () => {
- cy.route(
- 'GET',
- `api/kubernetes/apis/apps/v1/namespaces/${environmentName}/deployments/example-solution-operator`,
- ).as('getSolutionOperatorDeployment');
- cy.route(
- 'GET',
- '/api/kubernetes/api/v1/namespaces?labelSelector=solutions.metalk8s.scality.com/environment',
- ).as('getEnvironmentsList');
- cy.get(`[data-cy="${environmentName}"]`).click();
- },
-);
-
-Then('I click on upgrade button and check the solution is upgraded', () => {
- cy.get('[data-cy="upgrade"]').click();
-
- cy.get('.sc-modal .sc-select').eq(0).click();
- cy.get(`[data-cy="${upgradeSolutionVersion}"]`).click();
- cy.get('[data-cy="upgrade_downgrade_button"]').click();
- const timeOut = {
- requestTimeout: 60000,
- responseTimeout: 60000,
- };
-
- cy.wait('@getSolutionOperatorDeployment', timeOut);
- cy.wait('@getSolutionOperatorDeployment', timeOut);
- cy.wait('@getSolutionOperatorDeployment', timeOut);
-
- cy.get('.sc-table-column-cell-version').should(
- 'contain',
- upgradeSolutionVersion,
- );
-});
-
-Then(
- 'I click on the downgrade button and check the solution is downgraded',
- () => {
- cy.get('[data-cy="downgrade"]').click();
- cy.get('.sc-modal .sc-select').eq(0).click();
- cy.get(`[data-cy="${solutionVersion}"]`).click();
- cy.get('[data-cy="upgrade_downgrade_button"]').click();
- const timeOut = {
- requestTimeout: 60000,
- responseTimeout: 60000,
- };
-
- cy.wait('@getSolutionOperatorDeployment', timeOut);
- cy.wait('@getSolutionOperatorDeployment', timeOut);
-
- cy.get('.sc-table-column-cell-version').should('contain', solutionVersion);
- },
-);
diff --git a/ui/cypress/integration/sidebar.spec.js b/ui/cypress/integration/sidebar.spec.js
index 36a50f3f04..8d63b62ecb 100644
--- a/ui/cypress/integration/sidebar.spec.js
+++ b/ui/cypress/integration/sidebar.spec.js
@@ -30,12 +30,6 @@ describe('Sidebar', () => {
cy.get('@historyPush').should('be.calledWith', '/volumes');
});
- it('brings me to the environment page', () => {
- cy.get('[data-cy="sidebar_item_environments"]').click();
-
- cy.get('@historyPush').should('be.calledWith', '/environments');
- });
-
it('can be expanded', () => {
cy.window()
.its('localStorage')
diff --git a/ui/package.json b/ui/package.json
index 47d70a12a6..c16c5ba968 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -47,8 +47,7 @@
"eject": "react-scripts eject",
"test:nowatch": "CI=true react-app-rewired test --env=jsdom --reporters=default --reporters=jest-junit",
"test:integration": "cypress run --spec 'cypress/integration/**/*.spec.js'",
- "test:e2e": "cypress run --spec 'cypress/integration/e2e/**/!(Solutions).feature'",
- "test:e2esolutions": "cypress run --spec 'cypress/integration/e2e/Solutions.feature'",
+ "test:e2e": "cypress run --spec 'cypress/integration/e2e/**/*.feature'",
"flow": "flow check"
},
"eslintConfig": {
diff --git a/ui/src/containers/EnvironmentCreationForm.js b/ui/src/containers/EnvironmentCreationForm.js
deleted file mode 100644
index 1a76780ebc..0000000000
--- a/ui/src/containers/EnvironmentCreationForm.js
+++ /dev/null
@@ -1,132 +0,0 @@
-import React from 'react';
-import { useDispatch } from 'react-redux';
-import { useHistory } from 'react-router';
-import { Formik, Form } from 'formik';
-import * as yup from 'yup';
-import styled from 'styled-components';
-import isEmpty from 'lodash.isempty';
-import { Input, Button } from '@scality/core-ui';
-import { padding } from '@scality/core-ui/dist/style/theme';
-
-import { intl } from '../translations/IntlGlobalProvider';
-import { createEnvironmentAction } from '../ducks/app/solutions';
-
-const EnvironmentCreationFormContainer = styled.div`
- display: inline-block;
- padding-left: ${padding.base};
-`;
-
-const CreationFormContainer = styled.div`
- margin-top: ${padding.base};
-`;
-
-const ActionContainer = styled.div`
- display: flex;
- margin: ${padding.large} 0;
- justify-content: flex-end;
- button {
- margin-right: ${padding.large};
- }
-`;
-
-const FormSection = styled.div`
- display: flex;
- padding: 0 ${padding.larger};
- flex-direction: column;
-
- .sc-input {
- display: inline-flex;
- margin: ${padding.smaller} 0;
- .sc-input-label {
- width: 200px;
- }
- .sc-input-wrapper {
- width: 200px;
- }
- }
-`;
-
-const EnvironmentCreationForm = (props) => {
- const dispatch = useDispatch();
- const history = useHistory();
-
- const initialValues = {
- name: '',
- description: '',
- };
- const environmentNameRegex = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$/;
- const validationSchema = yup.object().shape({
- name: yup
- .string()
- .matches(environmentNameRegex, intl.translate('name_error'))
- .required(
- intl.translate('generic_missing_field', {
- field: intl.translate('name').toLowerCase(),
- }),
- ),
-
- description: yup.string(),
- });
-
- return (
-
-
- {
- dispatch(createEnvironmentAction(values));
- }}
- >
- {(formikProps) => {
- const { setFieldValue, errors, dirty } = formikProps;
-
- //handleChange of the Formik props does not update 'values' when field value is empty
- const handleChange = (field) => (e) => {
- const { value, checked, type } = e.target;
- setFieldValue(field, type === 'checkbox' ? checked : value, true);
- };
-
- return (
-
- );
- }}
-
-
-
- );
-};
-
-export default EnvironmentCreationForm;
diff --git a/ui/src/containers/Layout.js b/ui/src/containers/Layout.js
index 947874757f..b009dc94b6 100644
--- a/ui/src/containers/Layout.js
+++ b/ui/src/containers/Layout.js
@@ -9,13 +9,10 @@ import { Layout as CoreUILayout, Notifications } from '@scality/core-ui';
import { intl } from '../translations/IntlGlobalProvider';
import NodeCreateForm from './NodeCreateForm';
import NodePage from './NodePage';
-import SolutionList from './SolutionList';
-import EnvironmentCreationForm from './EnvironmentCreationForm';
import NodeDeployment from './NodeDeployment';
import ClusterMonitoring from './ClusterMonitoring';
import About from './About';
import PrivateRoute from './PrivateRoute';
-import SolutionDetail from './SolutionDetail';
import VolumePage from './VolumePage';
import DashboardPage from './DashboardPage';
@@ -35,7 +32,6 @@ const Layout = () => {
const notifications = useTypedSelector(
(state) => state.app.notifications.list,
);
- const solutions = useTypedSelector((state) => state.app.solutions.solutions);
const isUserLoaded = useTypedSelector((state) => !!state.oidc.user);
const api = useTypedSelector((state) => state.config.api);
const dispatch = useDispatch();
@@ -113,19 +109,6 @@ const Layout = () => {
}),
'data-cy': 'sidebar_item_volumes',
},
- {
- label: intl.translate('environments'),
- icon: ,
- onClick: () => {
- history.push('/environments');
- },
- active: useRouteMatch({
- path: '/environments',
- exact: false,
- strict: true,
- }),
- 'data-cy': 'sidebar_item_environments',
- },
],
};
// Remove the access to dashboard page if no flags property in the config.json,
@@ -137,21 +120,6 @@ const Layout = () => {
sidebarConfig.actions.shift();
}
- let applications = null;
- if (solutions?.length) {
- applications = solutions.reduce((prev, solution) => {
- let solutionDeployedVersions = solution.versions.filter(
- (version) => version?.deployed && version?.ui_url,
- );
- let app = solutionDeployedVersions.map((version) => ({
- label: solution.name,
- // TO BE IMPROVED in core-ui to allow display Link or
- onClick: () => window.open(version.ui_url, '_self'),
- }));
- return [...prev, ...app];
- }, []);
- }
-
// In this particular case, the label should not be translated
const languages = [
{
@@ -217,16 +185,6 @@ const Layout = () => {
},
];
- const applicationsAction = {
- type: 'dropdown',
- icon: ,
- items: applications,
- };
-
- if (applications && applications.length) {
- rightActions.splice(1, 0, applicationsAction);
- }
-
const navbar = {
productName: intl.translate('product_name'),
logo: ,
@@ -261,24 +219,13 @@ const Layout = () => {
component={CreateVolume}
/>
-
-
{api && api.flags && api.flags.includes('dashboard') && (
)}
-
diff --git a/ui/src/containers/SolutionDetail.js b/ui/src/containers/SolutionDetail.js
deleted file mode 100644
index 7f3a07a3d4..0000000000
--- a/ui/src/containers/SolutionDetail.js
+++ /dev/null
@@ -1,281 +0,0 @@
-import React, { useState } from 'react';
-import { useSelector, useDispatch } from 'react-redux';
-import { useRouteMatch } from 'react-router';
-import { Formik, Form } from 'formik';
-import * as yup from 'yup';
-import styled from 'styled-components';
-import { Table, Button, Modal, Input, Loader } from '@scality/core-ui';
-import { sortSelector } from '../services/utils';
-import NoRowsRenderer from '../components/NoRowsRenderer';
-import PageContainer from '../components/TableBasedPageStyle';
-import { FormStyle, ActionContainer } from '../components/ModalFormStyle';
-import { intl } from '../translations/IntlGlobalProvider';
-import { useRefreshEffect } from '../services/utils';
-import {
- refreshSolutionsAction,
- stopRefreshSolutionsAction,
- prepareEnvironmentAction,
-} from '../ducks/app/solutions';
-
-const SelectContainer = styled.div`
- display: flex;
- flex-direction: column;
- justify-content: center;
- margin-top: 45px;
-`;
-
-const SolutionDetail = () => {
- const match = useRouteMatch();
- const environments = useSelector((state) => state.app.solutions.environments);
- const environment = environments.find((env) => env.name === match.params.id);
- const deployedSolutions = environment?.solutions;
-
- // get all the available solutions from the global redux store
- const availableSolutions = useSelector(
- (state) => state.app.solutions.solutions,
- );
- const dispatch = useDispatch();
- useRefreshEffect(refreshSolutionsAction, stopRefreshSolutionsAction);
-
- const [
- isUpgradeDowngradeSolutionModalOpen,
- setIsUpgradeDowngradeSolutionModalOpen,
- ] = useState(false);
- // used by the modal
- const [selectedSolName, setSelectedSolName] = useState('');
- // `Upgrade` or `Downgrade` in order to reuse the modal
- const [upgradeOrDowngrade, setUpgradeOrDowngrade] = useState('');
- const [solSortBy, setSolSortBy] = useState('name');
- const [solSortDirection, setSolSortDirection] = useState('ASC');
-
- const onSort = (setSortBy, setSortDirection) => ({
- sortBy,
- sortDirection,
- }) => {
- setSortBy(sortBy);
- setSortDirection(sortDirection);
- };
-
- const solutionDetailColumn = [
- {
- label: intl.translate('name'),
- dataKey: 'name',
- },
- {
- label: intl.translate('version_env'),
- dataKey: 'version',
- },
- {
- label: intl.translate('action'),
- dataKey: 'action',
- disableSort: true,
- flexGrow: 1,
- renderer: (_, rowData) => {
- const solName = rowData.name;
- const solution =
- deployedSolutions.find((depSol) => depSol.name === solName) ?? {};
- const availableDeployingSolution = availableSolutions?.find(
- (avaSol) => avaSol.name === solName,
- );
-
- const availableUpgradeVersion = [];
- const availableDowngradeVersion = [];
-
- availableDeployingSolution.versions.forEach((avaDepSol) => {
- if (avaDepSol.version.localeCompare(solution.version) <= -1) {
- availableDowngradeVersion.push(avaDepSol);
- } else if (avaDepSol.version.localeCompare(solution.version) >= 1) {
- availableUpgradeVersion.push(avaDepSol);
- }
- });
- solution.availableDowngradeVersion = availableDowngradeVersion;
- solution.availableUpgradeVersion = availableUpgradeVersion;
-
- return (
- <>
- {solution?.availableUpgradeVersion?.length > 0 && (
-