diff --git a/RELEASE.md b/RELEASE.md index 3fe5a10a3d..35d152f739 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -18,6 +18,7 @@ Please follow the established format: - Fixes design issues in metadata panel. (#2009) - Fix missing run command in metadata panel for task nodes. (#2055) - Add `UnavailableDataset` as a default dataset for `--lite` mode. (#2083) +- Add `kedro viz --lite` user warning banner UI. (#2092) # Release 9.2.0 diff --git a/cypress/fixtures/mock/compatibleMetadata.json b/cypress/fixtures/mock/compatibleMetadata.json new file mode 100644 index 0000000000..7aca2c11bf --- /dev/null +++ b/cypress/fixtures/mock/compatibleMetadata.json @@ -0,0 +1,15 @@ +{ + "has_missing_dependencies": false, + "package_compatibilities": [ + { + "package_name": "fsspec", + "package_version": "2023.9.1", + "is_compatible": true + }, + { + "package_name": "kedro-datasets", + "package_version": "2.0.0", + "is_compatible": true + } + ] +} diff --git a/cypress/fixtures/mock/package-compatibilities-incompatible.json b/cypress/fixtures/mock/inCompatibleMetadata.json similarity index 66% rename from cypress/fixtures/mock/package-compatibilities-incompatible.json rename to cypress/fixtures/mock/inCompatibleMetadata.json index d33d26f125..109ca1bfa7 100644 --- a/cypress/fixtures/mock/package-compatibilities-incompatible.json +++ b/cypress/fixtures/mock/inCompatibleMetadata.json @@ -1,12 +1,15 @@ -[ - { +{ + "has_missing_dependencies": true, + "package_compatibilities": [ + { "package_name": "fsspec", "package_version": "2023.8.1", "is_compatible": false - }, - { + }, + { "package_name": "kedro-datasets", "package_version": "1.8.0", "is_compatible": false - } -] + } + ] +} diff --git a/cypress/fixtures/mock/package-compatibilities-compatible.json b/cypress/fixtures/mock/package-compatibilities-compatible.json deleted file mode 100644 index 4480b400e9..0000000000 --- a/cypress/fixtures/mock/package-compatibilities-compatible.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "package_name": "fsspec", - "package_version": "2023.9.1", - "is_compatible": true - }, - { - "package_name": "kedro-datasets", - "package_version": "1.8.0", - "is_compatible": false - } -] \ No newline at end of file diff --git a/cypress/tests/ui/flowchart/banners.cy.js b/cypress/tests/ui/flowchart/banners.cy.js new file mode 100644 index 0000000000..bdeb20bb4b --- /dev/null +++ b/cypress/tests/ui/flowchart/banners.cy.js @@ -0,0 +1,32 @@ +describe('Banners in Kedro-Viz', () => { + beforeEach(() => { + // Clears localStorage before each test + cy.clearLocalStorage(); + }); + + it("shows a missing dependencies banner in viz lite mode if the kedro project dependencies are not installed.", () => { + // Intercept the network request to mock with a fixture + cy.__interceptRest__( + '/api/metadata', + 'GET', + '/mock/inCompatibleMetadata.json' + ).as("appMetadata"); + + // Action + cy.reload(); + + // Assert after action + cy.get('[data-test="flowchart-wrapper--lite-banner"]').should('exist'); + cy.get('.banner-message-body').should('contains.text', 'please install the missing Kedro project dependencies') + cy.get('.banner-message-title').should('contains.text', 'Missing dependencies') + + // Test Learn more link + cy.get(".banner a") + .should("contains.attr", "href", "https://docs.kedro.org/projects/kedro-viz/en/latest/kedro-viz_visualisation.html#visualise-a-kedro-project-without-installing-project-dependencies"); + + // Close the banner + cy.get(".banner-close").click() + cy.get('[data-test="flowchart-wrapper--lite-banner"]').should('not.exist'); + + }); +}); diff --git a/cypress/tests/ui/flowchart/shareable-urls.cy.js b/cypress/tests/ui/flowchart/shareable-urls.cy.js index a02f31c5bd..776e745ffc 100644 --- a/cypress/tests/ui/flowchart/shareable-urls.cy.js +++ b/cypress/tests/ui/flowchart/shareable-urls.cy.js @@ -7,9 +7,9 @@ describe('Shareable URLs with empty localStorage', () => { it('verifies that users can open the Deploy Kedro-Viz modal if the localStorage is empty. #TC-52', () => { // Intercept the network request to mock with a fixture cy.__interceptRest__( - '/api/package-compatibilities', + '/api/metadata', 'GET', - '/mock/package-compatibilities-compatible.json' + '/mock/compatibleMetadata.json' ); // Action @@ -25,9 +25,9 @@ describe('Shareable URLs with empty localStorage', () => { it("shows an incompatible message given the user's fsspec package version is outdated. #TC-53", () => { // Intercept the network request to mock with a fixture cy.__interceptRest__( - '/api/package-compatibilities', + '/api/metadata', 'GET', - '/mock/package-compatibilities-incompatible.json' + '/mock/inCompatibleMetadata.json' ); // Action diff --git a/package/kedro_viz/api/rest/responses.py b/package/kedro_viz/api/rest/responses.py index 09eac0cc72..2f59d33b16 100644 --- a/package/kedro_viz/api/rest/responses.py +++ b/package/kedro_viz/api/rest/responses.py @@ -4,16 +4,14 @@ import abc import json import logging -from importlib.metadata import PackageNotFoundError from typing import Any, Dict, List, Optional, Union import orjson -import packaging from fastapi.encoders import jsonable_encoder from fastapi.responses import JSONResponse, ORJSONResponse from pydantic import BaseModel, ConfigDict -from kedro_viz.api.rest.utils import get_package_version +from kedro_viz.api.rest.utils import get_package_compatibilities from kedro_viz.data_access import data_access_manager from kedro_viz.models.flowchart import ( DataNode, @@ -24,6 +22,7 @@ TranscodedDataNode, TranscodedDataNodeMetadata, ) +from kedro_viz.models.metadata import Metadata, PackageCompatibility logger = logging.getLogger(__name__) @@ -259,17 +258,24 @@ class GraphAPIResponse(BaseAPIResponse): selected_pipeline: str -class PackageCompatibilityAPIResponse(BaseAPIResponse): - package_name: str - package_version: str - is_compatible: bool +class MetadataAPIResponse(BaseAPIResponse): + has_missing_dependencies: bool = False + package_compatibilities: List[PackageCompatibility] = [] model_config = ConfigDict( json_schema_extra={ - "example": { - "package_name": "fsspec", - "package_version": "2023.9.1", - "is_compatible": True, - } + "has_missing_dependencies": False, + "package_compatibilities": [ + { + "package_name": "fsspec", + "package_version": "2024.6.1", + "is_compatible": True, + }, + { + "package_name": "kedro-datasets", + "package_version": "4.0.0", + "is_compatible": True, + }, + ], } ) @@ -372,33 +378,11 @@ def get_selected_pipeline_response(registered_pipeline_id: str): ) -def get_package_compatibilities_response( - package_requirements: Dict[str, Dict[str, str]], -) -> List[PackageCompatibilityAPIResponse]: - """API response for `/api/package_compatibility`.""" - package_requirements_response = [] - - for package_name, package_info in package_requirements.items(): - compatible_version = package_info["min_compatible_version"] - try: - package_version = get_package_version(package_name) - except PackageNotFoundError: - logger.warning(package_info["warning_message"]) - package_version = "0.0.0" - - is_compatible = packaging.version.parse( - package_version - ) >= packaging.version.parse(compatible_version) - - package_requirements_response.append( - PackageCompatibilityAPIResponse( - package_name=package_name, - package_version=package_version, - is_compatible=is_compatible, - ) - ) - - return package_requirements_response +def get_metadata_response(): + """API response for `/api/metadata`.""" + package_compatibilities = get_package_compatibilities() + Metadata.set_package_compatibilities(package_compatibilities) + return Metadata() def get_encoded_response(response: Any) -> bytes: diff --git a/package/kedro_viz/api/rest/router.py b/package/kedro_viz/api/rest/router.py index 37d93b08d5..3cd6a18e9f 100644 --- a/package/kedro_viz/api/rest/router.py +++ b/package/kedro_viz/api/rest/router.py @@ -2,23 +2,21 @@ # pylint: disable=missing-function-docstring, broad-exception-caught import logging -from typing import List from fastapi import APIRouter from fastapi.responses import JSONResponse from kedro_viz.api.rest.requests import DeployerConfiguration -from kedro_viz.constants import PACKAGE_REQUIREMENTS from kedro_viz.integrations.deployment.deployer_factory import DeployerFactory from .responses import ( APIErrorMessage, GraphAPIResponse, + MetadataAPIResponse, NodeMetadataAPIResponse, - PackageCompatibilityAPIResponse, get_default_response, + get_metadata_response, get_node_metadata_response, - get_package_compatibilities_response, get_selected_pipeline_response, ) @@ -91,17 +89,15 @@ async def deploy_kedro_viz(input_values: DeployerConfiguration): @router.get( - "/package-compatibilities", - response_model=List[PackageCompatibilityAPIResponse], + "/metadata", + response_model=MetadataAPIResponse, ) -async def get_package_compatibilities(): +async def get_metadata(): try: - return get_package_compatibilities_response(PACKAGE_REQUIREMENTS) + return get_metadata_response() except Exception as exc: - logger.exception( - "An exception occurred while getting package compatibility info : %s", exc - ) + logger.exception("An exception occurred while getting app metadata: %s", exc) return JSONResponse( status_code=500, - content={"message": "Failed to get package compatibility info"}, + content={"message": "Failed to get app metadata"}, ) diff --git a/package/kedro_viz/api/rest/utils.py b/package/kedro_viz/api/rest/utils.py index 87ed619633..dd0ba584d1 100644 --- a/package/kedro_viz/api/rest/utils.py +++ b/package/kedro_viz/api/rest/utils.py @@ -1,10 +1,49 @@ """`kedro_viz.api.rest.utils` contains utility functions used in the `kedro_viz.api.rest` package""" + +import logging +from importlib.metadata import PackageNotFoundError +from typing import List + +import packaging + +from kedro_viz.constants import PACKAGE_REQUIREMENTS +from kedro_viz.models.metadata import PackageCompatibility + try: from importlib.metadata import version except ImportError: # pragma: no cover from importlib_metadata import version +logger = logging.getLogger(__name__) + def get_package_version(package_name: str): """Returns the version of the given package.""" return version(package_name) # pragma: no cover + + +def get_package_compatibilities() -> List[PackageCompatibility]: + """Returns the package compatibilities information + for the current python env.""" + package_compatibilities: List[PackageCompatibility] = [] + + for package_name, package_info in PACKAGE_REQUIREMENTS.items(): + compatible_version = package_info["min_compatible_version"] + try: + package_version = get_package_version(package_name) + except PackageNotFoundError: + logger.warning(package_info["warning_message"]) + package_version = "0.0.0" + + is_compatible = packaging.version.parse( + package_version + ) >= packaging.version.parse(compatible_version) + + package_compatibilities.append( + PackageCompatibility( + package_name=package_name, + package_version=package_version, + is_compatible=is_compatible, + ) + ) + return package_compatibilities diff --git a/package/kedro_viz/integrations/kedro/data_loader.py b/package/kedro_viz/integrations/kedro/data_loader.py index 2bfa405076..2955d73b29 100644 --- a/package/kedro_viz/integrations/kedro/data_loader.py +++ b/package/kedro_viz/integrations/kedro/data_loader.py @@ -24,6 +24,7 @@ from kedro_viz.integrations.kedro.abstract_dataset_lite import AbstractDatasetLite from kedro_viz.integrations.kedro.lite_parser import LiteParser from kedro_viz.integrations.utils import _VizNullPluginManager +from kedro_viz.models.metadata import Metadata logger = logging.getLogger(__name__) @@ -145,6 +146,9 @@ def load_data( if unresolved_imports and len(unresolved_imports) > 0: modules_to_mock: Set[str] = set() + # for the viz lite banner + Metadata.set_has_missing_dependencies(True) + for unresolved_module_set in unresolved_imports.values(): modules_to_mock = modules_to_mock.union(unresolved_module_set) diff --git a/package/kedro_viz/models/metadata.py b/package/kedro_viz/models/metadata.py new file mode 100644 index 0000000000..debe1f04e3 --- /dev/null +++ b/package/kedro_viz/models/metadata.py @@ -0,0 +1,47 @@ +"""`kedro_viz.models.metadata` defines metadata for Kedro-Viz application.""" + +# pylint: disable=missing-function-docstring +from typing import ClassVar, List + +from pydantic import BaseModel, field_validator + + +class PackageCompatibility(BaseModel): + """Represent package compatibility in app metadata""" + + package_name: str + package_version: str + is_compatible: bool + + @field_validator("package_name") + @classmethod + def set_package_name(cls, value): + assert isinstance(value, str) + return value + + @field_validator("package_version") + @classmethod + def set_package_version(cls, value): + assert isinstance(value, str) + return value + + @field_validator("is_compatible") + @classmethod + def set_is_compatible(cls, value): + assert isinstance(value, bool) + return value + + +class Metadata(BaseModel): + """Represent Kedro-Viz application metadata""" + + has_missing_dependencies: ClassVar[bool] = False + package_compatibilities: ClassVar[List[PackageCompatibility]] = [] + + @classmethod + def set_package_compatibilities(cls, value: List[PackageCompatibility]): + cls.package_compatibilities = value + + @classmethod + def set_has_missing_dependencies(cls, value: bool): + cls.has_missing_dependencies = value diff --git a/package/tests/test_api/test_rest/test_responses.py b/package/tests/test_api/test_rest/test_responses.py index 8873cfc3c9..3f75904404 100644 --- a/package/tests/test_api/test_rest/test_responses.py +++ b/package/tests/test_api/test_rest/test_responses.py @@ -1,6 +1,5 @@ # pylint: disable=too-many-lines import json -import logging import operator from pathlib import Path from typing import Any, Dict, Iterable, List @@ -13,9 +12,8 @@ from kedro_viz.api import apps from kedro_viz.api.rest.responses import ( EnhancedORJSONResponse, - PackageCompatibilityAPIResponse, get_kedro_project_json_data, - get_package_compatibilities_response, + get_metadata_response, save_api_main_response_to_fs, save_api_node_response_to_fs, save_api_pipeline_response_to_fs, @@ -23,6 +21,7 @@ write_api_response_to_fs, ) from kedro_viz.models.flowchart import TaskNode +from kedro_viz.models.metadata import Metadata def _is_dict_list(collection: Any) -> bool: @@ -835,6 +834,28 @@ def test_get_non_existing_pipeline(self, client): assert response.status_code == 404 +class TestAppMetadata: + def test_get_metadata_response(self, mocker): + mock_get_compat = mocker.patch( + "kedro_viz.api.rest.responses.get_package_compatibilities", + return_value="mocked_compatibilities", + ) + mock_set_compat = mocker.patch( + "kedro_viz.api.rest.responses.Metadata.set_package_compatibilities" + ) + + response = get_metadata_response() + + # Assert get_package_compatibilities was called + mock_get_compat.assert_called_once() + + # Assert set_package_compatibilities was called with the mocked compatibilities + mock_set_compat.assert_called_once_with("mocked_compatibilities") + + # Assert the function returns the Metadata instance + assert isinstance(response, Metadata) + + class TestAPIAppFromFile: def test_api_app_from_json_file_main_api(self): filepath = str(Path(__file__).parent.parent) @@ -851,82 +872,6 @@ def test_api_app_from_json_file_index(self): assert response.status_code == 200 -class TestPackageCompatibilities: - @pytest.mark.parametrize( - "package_name, package_version, package_requirements, expected_compatibility_response", - [ - ( - "fsspec", - "2023.9.1", - {"fsspec": {"min_compatible_version": "2023.0.0"}}, - True, - ), - ( - "fsspec", - "2023.9.1", - {"fsspec": {"min_compatible_version": "2024.0.0"}}, - False, - ), - ( - "kedro-datasets", - "2.1.0", - {"kedro-datasets": {"min_compatible_version": "2.1.0"}}, - True, - ), - ( - "kedro-datasets", - "1.8.0", - {"kedro-datasets": {"min_compatible_version": "2.1.0"}}, - False, - ), - ], - ) - def test_get_package_compatibilities_response( - self, - package_name, - package_version, - package_requirements, - expected_compatibility_response, - mocker, - ): - mocker.patch( - "kedro_viz.api.rest.responses.get_package_version", - return_value=package_version, - ) - response = get_package_compatibilities_response(package_requirements) - - for package_response in response: - assert package_response.package_name == package_name - assert package_response.package_version == package_version - assert package_response.is_compatible is expected_compatibility_response - - def test_get_package_compatibilities_exception_response(self, caplog): - mock_package_requirement = { - "random-package": { - "min_compatible_version": "1.0.0", - "warning_message": "random-package is not available", - } - } - - with caplog.at_level(logging.WARNING): - response = get_package_compatibilities_response(mock_package_requirement) - - assert len(caplog.records) == 1 - - record = caplog.records[0] - - assert record.levelname == "WARNING" - assert ( - mock_package_requirement["random-package"]["warning_message"] - in record.message - ) - - expected_response = PackageCompatibilityAPIResponse( - package_name="random-package", package_version="0.0.0", is_compatible=False - ) - assert response == [expected_response] - - class TestEnhancedORJSONResponse: @pytest.mark.parametrize( "content, expected", diff --git a/package/tests/test_api/test_rest/test_router.py b/package/tests/test_api/test_rest/test_router.py index 9ba1de7e2c..d84f1ce0f2 100644 --- a/package/tests/test_api/test_rest/test_router.py +++ b/package/tests/test_api/test_rest/test_router.py @@ -47,42 +47,46 @@ def test_deploy_kedro_viz( ( None, 200, - [ - { - "package_name": "fsspec", - "package_version": "2023.9.1", - "is_compatible": True, - }, - { - "package_name": "kedro-datasets", - "package_version": "1.8.0", - "is_compatible": False, - }, - ], + { + "has_missing_dependencies": False, + "package_compatibilities": [ + { + "package_name": "fsspec", + "package_version": "2023.9.1", + "is_compatible": True, + }, + { + "package_name": "kedro-datasets", + "package_version": "1.8.0", + "is_compatible": False, + }, + ], + }, ), ( Exception, 500, - {"message": "Failed to get package compatibility info"}, + {"message": "Failed to get app metadata"}, ), ], ) -def test_get_package_compatibilities( +def test_metadata( client, exception_type, expected_status_code, expected_response, mocker ): # Mock the function that may raise an exception if exception_type is None: - mocker.patch( - "kedro_viz.api.rest.router.get_package_compatibilities_response", + mock_get_metadata_response = mocker.patch( + "kedro_viz.api.rest.router.get_metadata_response", return_value=expected_response, ) else: - mocker.patch( - "kedro_viz.api.rest.router.get_package_compatibilities_response", + mock_get_metadata_response = mocker.patch( + "kedro_viz.api.rest.router.get_metadata_response", side_effect=exception_type("Test Exception"), ) - response = client.get("/api/package-compatibilities") + response = client.get("/api/metadata") + mock_get_metadata_response.assert_called_once() assert response.status_code == expected_status_code assert response.json() == expected_response diff --git a/package/tests/test_api/test_rest/test_utils.py b/package/tests/test_api/test_rest/test_utils.py new file mode 100644 index 0000000000..32a69cc371 --- /dev/null +++ b/package/tests/test_api/test_rest/test_utils.py @@ -0,0 +1,92 @@ +import logging + +import pytest + +from kedro_viz.api.rest.utils import get_package_compatibilities +from kedro_viz.models.metadata import PackageCompatibility + +logger = logging.getLogger(__name__) + + +@pytest.mark.parametrize( + "package_name, package_version, package_requirements, expected_compatibility_response", + [ + ( + "fsspec", + "2023.9.1", + {"fsspec": {"min_compatible_version": "2023.0.0"}}, + True, + ), + ( + "fsspec", + "2023.9.1", + {"fsspec": {"min_compatible_version": "2024.0.0"}}, + False, + ), + ( + "kedro-datasets", + "2.1.0", + {"kedro-datasets": {"min_compatible_version": "2.1.0"}}, + True, + ), + ( + "kedro-datasets", + "1.8.0", + {"kedro-datasets": {"min_compatible_version": "2.1.0"}}, + False, + ), + ], +) +def test_get_package_compatibilities( + package_name, + package_version, + package_requirements, + expected_compatibility_response, + mocker, +): + mocker.patch( + "kedro_viz.api.rest.utils.get_package_version", + return_value=package_version, + ) + mocker.patch( + "kedro_viz.api.rest.utils.PACKAGE_REQUIREMENTS", + package_requirements, + ) + + response = get_package_compatibilities() + + for package_response in response: + assert package_response.package_name == package_name + assert package_response.package_version == package_version + assert package_response.is_compatible is expected_compatibility_response + + +def test_get_package_compatibilities_exception_response(caplog, mocker): + mock_package_requirement = { + "random-package": { + "min_compatible_version": "1.0.0", + "warning_message": "random-package is not available", + } + } + mocker.patch( + "kedro_viz.api.rest.utils.PACKAGE_REQUIREMENTS", + mock_package_requirement, + ) + + with caplog.at_level(logging.WARNING): + response = get_package_compatibilities() + + assert len(caplog.records) == 1 + + record = caplog.records[0] + + assert record.levelname == "WARNING" + assert ( + mock_package_requirement["random-package"]["warning_message"] + in record.message + ) + + expected_response = PackageCompatibility( + package_name="random-package", package_version="0.0.0", is_compatible=False + ) + assert response == [expected_response] diff --git a/package/tests/test_models/test_metadata.py b/package/tests/test_models/test_metadata.py new file mode 100644 index 0000000000..d81bb04502 --- /dev/null +++ b/package/tests/test_models/test_metadata.py @@ -0,0 +1,70 @@ +import pytest +from pydantic import ValidationError + +from kedro_viz.models.metadata import Metadata, PackageCompatibility + + +class TestPackageCompatibility: + def test_package_compatibility_valid_data(self): + package = PackageCompatibility( + package_name="kedro", package_version="0.18.0", is_compatible=True + ) + assert package.package_name == "kedro" + assert package.package_version == "0.18.0" + assert package.is_compatible is True + + def test_package_compatibility_invalid_package_name(self): + with pytest.raises(ValidationError) as excinfo: + PackageCompatibility( + package_name=123, # invalid type + package_version="0.18.0", + is_compatible=True, + ) + assert "Input should be a valid string" in str(excinfo.value) + + def test_package_compatibility_invalid_package_version(self): + with pytest.raises(ValidationError) as excinfo: + PackageCompatibility( + package_name="kedro", + package_version=123, # invalid type + is_compatible=True, + ) + assert "Input should be a valid string" in str(excinfo.value) + + def test_package_compatibility_invalid_is_compatible(self): + with pytest.raises(ValidationError) as excinfo: + PackageCompatibility( + package_name="kedro", + package_version="0.18.0", + is_compatible="random", # invalid type + ) + assert "Input should be a valid boolean" in str(excinfo.value) + + +class TestMetadata: + def test_metadata_default_values(self): + # Test default values of Metadata + assert Metadata.has_missing_dependencies is False + assert not Metadata.package_compatibilities + + def test_metadata_set_package_compatibilities(self): + kedro_package = PackageCompatibility( + package_name="kedro", package_version="0.18.0", is_compatible=True + ) + pandas_package = PackageCompatibility( + package_name="pandas", package_version="1.2.0", is_compatible=False + ) + + # Set the package compatibilities using the class method + Metadata.set_package_compatibilities([kedro_package, pandas_package]) + + # Assert the values have been set correctly + assert Metadata.package_compatibilities == [kedro_package, pandas_package] + + def test_metadata_set_has_missing_dependencies(self): + # Test changing the has_missing_dependencies value + Metadata.set_has_missing_dependencies(True) + assert Metadata.has_missing_dependencies is True + + Metadata.set_has_missing_dependencies(False) + assert Metadata.has_missing_dependencies is False diff --git a/src/actions/index.js b/src/actions/index.js index 8e30a0e7f9..e169c38900 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -230,6 +230,21 @@ export function changeFlag(name, value) { }; } +export const SET_BANNER = 'SET_BANNER'; + +/** + * Change the given banner status + * @param {String} name The banner name + * @param {Value} value The value to set + */ +export function setBanner(name, value) { + return { + type: SET_BANNER, + name, + value, + }; +} + export const TOGGLE_IGNORE_LARGE_WARNING = 'TOGGLE_IGNORE_LARGE_WARNING'; /** diff --git a/src/components/experiment-wrapper/experiment-wrapper.js b/src/components/experiment-wrapper/experiment-wrapper.js index ce9fb3b718..ce1195e7c1 100644 --- a/src/components/experiment-wrapper/experiment-wrapper.js +++ b/src/components/experiment-wrapper/experiment-wrapper.js @@ -18,7 +18,7 @@ import { PACKAGE_KEDRO_DATASETS, } from '../../config'; import { findMatchedPath } from '../../utils/match-path'; -import { fetchPackageCompatibilities } from '../../utils'; +import { fetchMetadata } from '../../utils'; import { saveLocalStorage, loadLocalStorage } from '../../store/helpers'; import './experiment-wrapper.scss'; @@ -193,23 +193,24 @@ const ExperimentWrapper = ({ theme, runsMetadata }) => { }, []); useEffect(() => { - async function fetchPackageCompatibility() { + async function checkPackageCompatibility() { try { - const request = await fetchPackageCompatibilities(); + const request = await fetchMetadata(); const response = await request.json(); if (request.ok) { - const kedroDatasetsPackage = response.find( + const packageCompatibilityInfo = response.package_compatibilities; + const kedroDatasetsPackage = packageCompatibilityInfo.find( (pckg) => pckg.package_name === PACKAGE_KEDRO_DATASETS ); setIsKedroDatasetsCompatible(kedroDatasetsPackage.is_compatible); } } catch (error) { - console.error('package-compatibilities fetch error: ', error); + console.error('metadata fetch error: ', error); } } - fetchPackageCompatibility(); + checkPackageCompatibility(); }, []); useEffect(() => { diff --git a/src/components/flowchart-wrapper/flowchart-wrapper.js b/src/components/flowchart-wrapper/flowchart-wrapper.js index 9f3837f71f..73fec53272 100644 --- a/src/components/flowchart-wrapper/flowchart-wrapper.js +++ b/src/components/flowchart-wrapper/flowchart-wrapper.js @@ -19,6 +19,7 @@ import ExportModal from '../export-modal'; import FlowChart from '../flowchart'; import PipelineWarning from '../pipeline-warning'; import LoadingIcon from '../icons/loading'; +import AlertIcon from '../icons/alert'; import MetaData from '../metadata'; import MetadataModal from '../metadata-modal'; import ShareableUrlMetadata from '../shareable-url-modal/shareable-url-metadata'; @@ -31,13 +32,18 @@ import { linkToFlowchartInitialVal, localStorageFlowchartLink, localStorageName, + localStorageBannerStatus, params, + BANNER_METADATA, + BANNER_KEYS, } from '../../config'; import { findMatchedPath } from '../../utils/match-path'; import { getKeyByValue, getKeysByValue } from '../../utils/object-utils'; import { isRunningLocally, mapNodeTypes } from '../../utils'; import { useGeneratePathname } from '../../utils/hooks/use-generate-pathname'; import './flowchart-wrapper.scss'; +import Banner from '../ui/banner'; +import { getDataTestAttribute } from '../../utils/get-data-test-attribute'; /** * Main flowchart container. Handles showing/hiding the sidebar nav for flowchart view, @@ -64,6 +70,7 @@ export const FlowChartWrapper = ({ expandAllPipelines, displayMetadataPanel, displayExportBtn, + displayBanner, }) => { const history = useHistory(); const { pathname, search } = useLocation(); @@ -304,6 +311,18 @@ export const FlowChartWrapper = ({ resetLinkingToFlowchartLocalStorage(); }; + const handleBannerClose = (bannerKey) => { + saveLocalStorage(localStorageBannerStatus, { [bannerKey]: false }); + }; + + const showBanner = (bannerKey) => { + const bannerStatus = loadLocalStorage(localStorageBannerStatus); + const shouldShowBanner = + displayBanner[bannerKey] && + (bannerStatus[bannerKey] || bannerStatus[bannerKey] === undefined); + return shouldShowBanner; + }; + if (isInvalidUrl) { return (