[LYN-4288] Adding error page if resource mapping tool has invalid setup (#1219)
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
from PySide2.QtCore import (QCoreApplication, QObject)
|
||||
|
||||
from manager.view_manager import ViewManager
|
||||
from view.error_page import ErrorPage
|
||||
|
||||
|
||||
class ErrorController(QObject):
|
||||
"""
|
||||
ErrorPage Controller
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
super(ErrorController, self).__init__()
|
||||
# Initialize manager references
|
||||
self._view_manager: ViewManager = ViewManager.get_instance()
|
||||
# Initialize view references
|
||||
self._error_page: ErrorPage = self._view_manager.get_error_page()
|
||||
|
||||
def _ok(self) -> None:
|
||||
QCoreApplication.instance().quit()
|
||||
|
||||
def setup(self) -> None:
|
||||
self._error_page.ok_button.clicked.connect(self._ok)
|
||||
@@ -48,11 +48,15 @@ class ConfigurationManager(object):
|
||||
def configuration(self, new_configuration: ConfigurationManager) -> None:
|
||||
self._configuration = new_configuration
|
||||
|
||||
def setup(self, config_path: str) -> bool:
|
||||
def setup(self, profile_name: str, config_path: str) -> bool:
|
||||
result: bool = True
|
||||
logger.info("Setting up default configuration ...")
|
||||
logger.debug("Setting up default configuration ...")
|
||||
try:
|
||||
normalized_config_path: str = file_utils.normalize_file_path(config_path);
|
||||
logger.debug("Setting up boto3 default session ...")
|
||||
aws_utils.setup_default_session(profile_name)
|
||||
|
||||
logger.debug("Setting up config directory and files ...")
|
||||
normalized_config_path: str = file_utils.normalize_file_path(config_path)
|
||||
if normalized_config_path:
|
||||
self._configuration.config_directory = normalized_config_path
|
||||
else:
|
||||
@@ -61,6 +65,7 @@ class ConfigurationManager(object):
|
||||
file_utils.find_files_with_suffix_under_directory(self._configuration.config_directory,
|
||||
constants.RESOURCE_MAPPING_CONFIG_FILE_NAME_SUFFIX)
|
||||
|
||||
logger.debug("Setting up aws account id and region ...")
|
||||
self._configuration.account_id = aws_utils.get_default_account_id()
|
||||
self._configuration.region = aws_utils.get_default_region()
|
||||
except (RuntimeError, FileNotFoundError) as e:
|
||||
|
||||
@@ -12,6 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from controller.error_controller import ErrorController
|
||||
from controller.import_resources_controller import ImportResourcesController
|
||||
from controller.view_edit_controller import ViewEditController
|
||||
from model import error_messages
|
||||
@@ -33,8 +34,9 @@ class ControllerManager(object):
|
||||
|
||||
def __init__(self) -> None:
|
||||
if ControllerManager.__instance is None:
|
||||
self._view_edit_controller: ViewEditController = ViewEditController()
|
||||
self._import_resources_controller: ImportResourcesController = ImportResourcesController()
|
||||
self._error_controller: ErrorController = None
|
||||
self._view_edit_controller: ViewEditController = None
|
||||
self._import_resources_controller: ImportResourcesController = None
|
||||
ControllerManager.__instance = self
|
||||
else:
|
||||
raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ControllerManager"))
|
||||
@@ -47,9 +49,17 @@ class ControllerManager(object):
|
||||
def view_edit_controller(self) -> ViewEditController:
|
||||
return self._view_edit_controller
|
||||
|
||||
def setup(self) -> None:
|
||||
logger.info("Setting up ViewEdit and ImportResource controllers ...")
|
||||
self._view_edit_controller.setup()
|
||||
self._import_resources_controller.setup()
|
||||
self._import_resources_controller.add_import_resources_sender.connect(
|
||||
self._view_edit_controller.add_import_resources_receiver)
|
||||
def setup(self, setup_error: bool) -> None:
|
||||
if setup_error:
|
||||
logger.debug("Setting up Error controllers ...")
|
||||
self._error_controller = ErrorController()
|
||||
self._error_controller.setup()
|
||||
else:
|
||||
logger.debug("Setting up ViewEdit and ImportResource controllers ...")
|
||||
self._view_edit_controller = ViewEditController()
|
||||
self._import_resources_controller = ImportResourcesController()
|
||||
|
||||
self._view_edit_controller.setup()
|
||||
self._import_resources_controller.setup()
|
||||
self._import_resources_controller.add_import_resources_sender.connect(
|
||||
self._view_edit_controller.add_import_resources_receiver)
|
||||
|
||||
@@ -37,10 +37,13 @@ class ThreadManager(object):
|
||||
else:
|
||||
raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ThreadManager"))
|
||||
|
||||
def setup(self, thread_count: int = 1) -> None:
|
||||
# Based on prototype use case, we just need 1 thread
|
||||
logger.info(f"Setting up thread pool with MaxThreadCount={thread_count} ...")
|
||||
self._thread_pool.setMaxThreadCount(thread_count)
|
||||
def setup(self, setup_error: bool, thread_count: int = 1) -> None:
|
||||
if setup_error:
|
||||
logger.debug("Skip thread pool creation, as there is major setup error.")
|
||||
else:
|
||||
# Based on prototype use case, we just need 1 thread
|
||||
logger.debug(f"Setting up thread pool with MaxThreadCount={thread_count} ...")
|
||||
self._thread_pool.setMaxThreadCount(thread_count)
|
||||
|
||||
"""Reserves a thread and uses it to run runnable worker, unless this thread will make
|
||||
the current thread count exceed max thread count. In that case, runnable is added to a run queue instead."""
|
||||
|
||||
@@ -16,6 +16,7 @@ from PySide2.QtGui import QIcon
|
||||
from PySide2.QtWidgets import (QMainWindow, QStackedWidget, QWidget)
|
||||
|
||||
from model import (error_messages, view_size_constants)
|
||||
from view.error_page import ErrorPage
|
||||
from view.import_resources_page import ImportResourcesPage
|
||||
from view.view_edit_page import ViewEditPage
|
||||
|
||||
@@ -27,6 +28,10 @@ class ViewManagerConstants(object):
|
||||
IMPORT_RESOURCES_PAGE_INDEX: int = 1
|
||||
|
||||
|
||||
# Error page will be a single page
|
||||
ERROR_PAGE_INDEX: int = 0
|
||||
|
||||
|
||||
class ViewManager(object):
|
||||
"""
|
||||
View manager maintains the main stacked pages for this tool, which
|
||||
@@ -58,21 +63,32 @@ class ViewManager(object):
|
||||
ViewManager.__instance = self
|
||||
else:
|
||||
raise AssertionError(error_messages.SINGLETON_OBJECT_ERROR_MESSAGE.format("ViewManager"))
|
||||
|
||||
|
||||
def get_error_page(self) -> QWidget:
|
||||
return self._resource_mapping_stacked_pages.widget(ERROR_PAGE_INDEX)
|
||||
|
||||
def get_view_edit_page(self) -> QWidget:
|
||||
return self._resource_mapping_stacked_pages.widget(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX)
|
||||
|
||||
def get_import_resources_page(self) -> QWidget:
|
||||
return self._resource_mapping_stacked_pages.widget(ViewManagerConstants.IMPORT_RESOURCES_PAGE_INDEX)
|
||||
|
||||
def setup(self) -> None:
|
||||
logger.debug("Setting up ViewEdit and ImportResources view pages ...")
|
||||
self._resource_mapping_stacked_pages.addWidget(ViewEditPage())
|
||||
self._resource_mapping_stacked_pages.addWidget(ImportResourcesPage())
|
||||
def setup(self, setup_error: bool) -> None:
|
||||
if setup_error:
|
||||
logger.debug("Setting up Error view pages ...")
|
||||
self._resource_mapping_stacked_pages.addWidget(ErrorPage())
|
||||
self._main_window.adjustSize() # fit error page size
|
||||
else:
|
||||
logger.debug("Setting up ViewEdit and ImportResources view pages ...")
|
||||
self._resource_mapping_stacked_pages.addWidget(ViewEditPage())
|
||||
self._resource_mapping_stacked_pages.addWidget(ImportResourcesPage())
|
||||
|
||||
def show(self) -> None:
|
||||
def show(self, setup_error: bool) -> None:
|
||||
"""Show up the tool view by setting default page index and showing main widget"""
|
||||
self._resource_mapping_stacked_pages.setCurrentIndex(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX)
|
||||
if setup_error:
|
||||
self._resource_mapping_stacked_pages.setCurrentIndex(ERROR_PAGE_INDEX)
|
||||
else:
|
||||
self._resource_mapping_stacked_pages.setCurrentIndex(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX)
|
||||
self._main_window.show()
|
||||
|
||||
def switch_to_view_edit_page(self) -> None:
|
||||
|
||||
@@ -9,6 +9,12 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
ERROR_PAGE_TOOL_SETUP_ERROR_MESSAGE: str = \
|
||||
"AWS credentials are missing or invalid. See " \
|
||||
"<a href=\"https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-core/configuring-credentials/\">"\
|
||||
"<span style=\"color:#4A90E2;\">documentation</span></a> for details." \
|
||||
"<br>Check log file under Gems/AWSCore/Code/Tool/ResourceMappingTool for further information."
|
||||
|
||||
VIEW_EDIT_PAGE_SAVING_FAILED_WITH_INVALID_ROW_ERROR_MESSAGE: str = \
|
||||
"Row {} have errors. Please correct errors or delete the row to proceed."
|
||||
VIEW_EDIT_PAGE_READ_FROM_JSON_FAILED_WITH_UNEXPECTED_FILE_ERROR_MESSAGE: str = \
|
||||
|
||||
@@ -11,6 +11,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
NOTIFICATION_LOADING_MESSAGE: str = "Loading..."
|
||||
|
||||
ERROR_PAGE_OK_TEXT: str = "OK"
|
||||
|
||||
VIEW_EDIT_PAGE_CONFIG_FILE_TEXT: str = "Config File"
|
||||
VIEW_EDIT_PAGE_CONFIG_LOCATION_TEXT: str = "Config Location:"
|
||||
VIEW_EDIT_PAGE_ADD_ROW_TEXT: str = "Add Row"
|
||||
|
||||
@@ -17,6 +17,18 @@ MAIN_PAGE_LAYOUT_MARGIN_TOPBOTTOM: int = 15
|
||||
|
||||
INTERACTION_COMPONENT_HEIGHT: int = 25
|
||||
|
||||
"""error page related constants"""
|
||||
ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT: int = 10
|
||||
ERROR_PAGE_LAYOUT_MARGIN_TOPBOTTOM: int = 10
|
||||
|
||||
ERROR_PAGE_MAIN_WINDOW_WIDTH: int = 600
|
||||
ERROR_PAGE_MAIN_WINDOW_HEIGHT: int = 145
|
||||
|
||||
ERROR_PAGE_NOTIFICATION_AREA_HEIGHT: int = 100
|
||||
ERROR_PAGE_FOOTER_AREA_HEIGHT: int = 45
|
||||
|
||||
OK_BUTTON_WIDTH: int = 90
|
||||
|
||||
"""view edit page related constants"""
|
||||
VIEW_EDIT_PAGE_HEADER_AREA_HEIGHT: int = 65
|
||||
VIEW_EDIT_PAGE_CENTER_AREA_HEIGHT: int = 500
|
||||
|
||||
@@ -73,32 +73,22 @@ if __name__ == "__main__":
|
||||
except FileNotFoundError:
|
||||
logger.warning("Failed to load style sheet for resource mapping tool")
|
||||
|
||||
logger.info("Initializing boto3 default session ...")
|
||||
try:
|
||||
aws_utils.setup_default_session(arguments.profile)
|
||||
except RuntimeError as error:
|
||||
logger.error(error)
|
||||
environment_utils.cleanup_qt_environment()
|
||||
exit(-1)
|
||||
|
||||
logger.info("Initializing configuration manager ...")
|
||||
configuration_manager: ConfigurationManager = ConfigurationManager()
|
||||
if not configuration_manager.setup(arguments.config_path):
|
||||
environment_utils.cleanup_qt_environment()
|
||||
exit(-1)
|
||||
configuration_error: bool = not configuration_manager.setup(arguments.profile, arguments.config_path)
|
||||
|
||||
logger.info("Initializing thread manager ...")
|
||||
thread_manager: ThreadManager = ThreadManager()
|
||||
thread_manager.setup()
|
||||
thread_manager.setup(configuration_error)
|
||||
|
||||
logger.info("Initializing view manager ...")
|
||||
view_manager: ViewManager = ViewManager()
|
||||
view_manager.setup()
|
||||
view_manager.setup(configuration_error)
|
||||
|
||||
logger.info("Initializing controller manager ...")
|
||||
controller_manager: ControllerManager = ControllerManager()
|
||||
controller_manager.setup()
|
||||
controller_manager.setup(configuration_error)
|
||||
|
||||
view_manager.show()
|
||||
view_manager.show(configuration_error)
|
||||
|
||||
sys.exit(app.exec_())
|
||||
|
||||
@@ -368,3 +368,18 @@ QFrame#NotificationFrame
|
||||
margin: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
QFrame#ErrorPage
|
||||
{
|
||||
background-color: #2d2d2d;
|
||||
border: 1px solid #4A90E2;
|
||||
border-radius: 2px;
|
||||
margin: 0px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
QFrame#ErrorPage QLabel#NotificationIcon
|
||||
{
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
+11
-4
@@ -33,6 +33,7 @@ class TestConfigurationManager(TestCase):
|
||||
def test_get_instance_raise_exception(self) -> None:
|
||||
self.assertRaises(Exception, ConfigurationManager)
|
||||
|
||||
@patch("utils.aws_utils.setup_default_session")
|
||||
@patch("utils.aws_utils.get_default_region", return_value=_expected_region)
|
||||
@patch("utils.aws_utils.get_default_account_id", return_value=_expected_account_id)
|
||||
@patch("utils.file_utils.find_files_with_suffix_under_directory", return_value=_expected_config_files)
|
||||
@@ -42,8 +43,10 @@ class TestConfigurationManager(TestCase):
|
||||
mock_check_path_exists: MagicMock,
|
||||
mock_find_files_with_suffix_under_directory: MagicMock,
|
||||
mock_get_default_account_id: MagicMock,
|
||||
mock_get_default_region: MagicMock) -> None:
|
||||
TestConfigurationManager._expected_configuration_manager.setup("")
|
||||
mock_get_default_region: MagicMock,
|
||||
mock_setup_default_session: MagicMock) -> None:
|
||||
TestConfigurationManager._expected_configuration_manager.setup("", "")
|
||||
mock_setup_default_session.assert_called_once()
|
||||
mock_get_current_directory_path.assert_called_once()
|
||||
mock_check_path_exists.assert_called_once_with(TestConfigurationManager._expected_directory_path)
|
||||
mock_find_files_with_suffix_under_directory.assert_called_once_with(
|
||||
@@ -59,6 +62,7 @@ class TestConfigurationManager(TestCase):
|
||||
assert TestConfigurationManager._expected_configuration_manager.configuration.region == \
|
||||
TestConfigurationManager._expected_region
|
||||
|
||||
@patch("utils.aws_utils.setup_default_session")
|
||||
@patch("utils.aws_utils.get_default_region", return_value=_expected_region)
|
||||
@patch("utils.aws_utils.get_default_account_id", return_value=_expected_account_id)
|
||||
@patch("utils.file_utils.find_files_with_suffix_under_directory", return_value=_expected_config_files)
|
||||
@@ -68,8 +72,11 @@ class TestConfigurationManager(TestCase):
|
||||
mock_check_path_exists: MagicMock,
|
||||
mock_find_files_with_suffix_under_directory: MagicMock,
|
||||
mock_get_default_account_id: MagicMock,
|
||||
mock_get_default_region: MagicMock) -> None:
|
||||
TestConfigurationManager._expected_configuration_manager.setup(TestConfigurationManager._expected_directory_path)
|
||||
mock_get_default_region: MagicMock,
|
||||
mock_setup_default_session: MagicMock) -> None:
|
||||
TestConfigurationManager._expected_configuration_manager.setup(
|
||||
"", TestConfigurationManager._expected_directory_path)
|
||||
mock_setup_default_session.assert_called_once()
|
||||
mock_normalize_file_path.assert_called_once()
|
||||
mock_check_path_exists.assert_called_once_with(TestConfigurationManager._expected_directory_path)
|
||||
mock_find_files_with_suffix_under_directory.assert_called_once_with(
|
||||
|
||||
+10
-1
@@ -25,6 +25,9 @@ class TestControllerManager(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
error_controller_patcher: patch = patch("manager.controller_manager.ErrorController")
|
||||
cls._mock_error_controller = error_controller_patcher.start()
|
||||
|
||||
import_resources_controller_patcher: patch = patch("manager.controller_manager.ImportResourcesController")
|
||||
cls._mock_import_resources_controller = import_resources_controller_patcher.start()
|
||||
|
||||
@@ -52,8 +55,14 @@ class TestControllerManager(TestCase):
|
||||
mocked_import_resources_controller: MagicMock = \
|
||||
TestControllerManager._mock_import_resources_controller.return_value
|
||||
|
||||
TestControllerManager._expected_controller_manager.setup()
|
||||
TestControllerManager._expected_controller_manager.setup(False)
|
||||
mocked_view_edit_controller.setup.assert_called_once()
|
||||
mocked_import_resources_controller.setup.assert_called_once()
|
||||
mocked_import_resources_controller.add_import_resources_sender.connect.assert_called_once_with(
|
||||
mocked_view_edit_controller.add_import_resources_receiver)
|
||||
|
||||
def test_setup_error_controller_setup_gets_invoked(self) -> None:
|
||||
mocked_error_controller: MagicMock = TestControllerManager._mock_error_controller.return_value
|
||||
|
||||
TestControllerManager._expected_controller_manager.setup(True)
|
||||
mocked_error_controller.setup.assert_called_once()
|
||||
|
||||
+7
-1
@@ -45,9 +45,15 @@ class TestThreadManager(TestCase):
|
||||
def test_setup_thread_pool_setup_with_expected_configuration(self) -> None:
|
||||
mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value
|
||||
|
||||
TestThreadManager._expected_thread_manager.setup()
|
||||
TestThreadManager._expected_thread_manager.setup(False)
|
||||
mocked_thread_pool.setMaxThreadCount.assert_called_once_with(1)
|
||||
|
||||
def test_setup_thread_pool_skip_setup(self) -> None:
|
||||
mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value
|
||||
|
||||
TestThreadManager._expected_thread_manager.setup(True)
|
||||
mocked_thread_pool.setMaxThreadCount.asset_not_called()
|
||||
|
||||
def test_start_thread_pool_start_expected_worker(self) -> None:
|
||||
mocked_thread_pool: MagicMock = TestThreadManager._mock_thread_pool.return_value
|
||||
expected_mocked_worker: MagicMock = MagicMock()
|
||||
|
||||
+32
-3
@@ -13,13 +13,14 @@ from typing import List
|
||||
from unittest import TestCase
|
||||
from unittest.mock import (call, MagicMock, patch)
|
||||
|
||||
from manager.view_manager import (ViewManager, ViewManagerConstants)
|
||||
from manager.view_manager import (ERROR_PAGE_INDEX, ViewManager, ViewManagerConstants)
|
||||
|
||||
|
||||
class TestViewManager(TestCase):
|
||||
"""
|
||||
ViewManager unit test cases
|
||||
"""
|
||||
_mock_error_page: MagicMock
|
||||
_mock_import_resources_page: MagicMock
|
||||
_mock_view_edit_page: MagicMock
|
||||
_mock_main_window: MagicMock
|
||||
@@ -28,6 +29,9 @@ class TestViewManager(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
error_page_patcher: patch = patch("manager.view_manager.ErrorPage")
|
||||
cls._mock_error_page = error_page_patcher.start()
|
||||
|
||||
import_resources_page_patcher: patch = patch("manager.view_manager.ImportResourcesPage")
|
||||
cls._mock_import_resources_page = import_resources_page_patcher.start()
|
||||
|
||||
@@ -60,6 +64,15 @@ class TestViewManager(TestCase):
|
||||
def test_get_instance_raise_exception(self) -> None:
|
||||
self.assertRaises(Exception, ViewManager)
|
||||
|
||||
def test_get_error_page_return_expected_page(self) -> None:
|
||||
expected_page: MagicMock = TestViewManager._mock_error_page.return_value
|
||||
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||
mocked_stacked_pages.widget.return_value = expected_page
|
||||
|
||||
actual_page: MagicMock = TestViewManager._expected_view_manager.get_error_page()
|
||||
mocked_stacked_pages.widget.assert_called_once_with(ERROR_PAGE_INDEX)
|
||||
assert actual_page == expected_page
|
||||
|
||||
def test_get_import_resources_page_return_expected_page(self) -> None:
|
||||
expected_page: MagicMock = TestViewManager._mock_import_resources_page.return_value
|
||||
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||
@@ -83,18 +96,34 @@ class TestViewManager(TestCase):
|
||||
mocked_import_resources_page: MagicMock = TestViewManager._mock_import_resources_page.return_value
|
||||
mocked_view_edit_page: MagicMock = TestViewManager._mock_view_edit_page.return_value
|
||||
|
||||
TestViewManager._expected_view_manager.setup()
|
||||
TestViewManager._expected_view_manager.setup(False)
|
||||
mocked_calls: List[call] = [call(mocked_view_edit_page), call(mocked_import_resources_page)]
|
||||
mocked_stacked_pages.addWidget.assert_has_calls(mocked_calls)
|
||||
|
||||
def test_setup_error_page_only(self) -> None:
|
||||
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||
mocked_error_page: MagicMock = TestViewManager._mock_error_page.return_value
|
||||
|
||||
TestViewManager._expected_view_manager.setup(True)
|
||||
mocked_calls: List[call] = [call(mocked_error_page)]
|
||||
mocked_stacked_pages.addWidget.assert_has_calls(mocked_calls)
|
||||
|
||||
def test_show_stacked_pages_show_with_expected_index(self) -> None:
|
||||
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||
mocked_main_window: MagicMock = TestViewManager._mock_main_window.return_value
|
||||
|
||||
TestViewManager._expected_view_manager.show()
|
||||
TestViewManager._expected_view_manager.show(False)
|
||||
mocked_stacked_pages.setCurrentIndex.assert_called_once_with(ViewManagerConstants.VIEW_AND_EDIT_PAGE_INDEX)
|
||||
mocked_main_window.show.assert_called_once()
|
||||
|
||||
def test_show_stacked_pages_show_error_plage(self) -> None:
|
||||
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||
mocked_main_window: MagicMock = TestViewManager._mock_main_window.return_value
|
||||
|
||||
TestViewManager._expected_view_manager.show(True)
|
||||
mocked_stacked_pages.setCurrentIndex.assert_called_once_with(ERROR_PAGE_INDEX)
|
||||
mocked_main_window.show.assert_called_once()
|
||||
|
||||
def test_switch_to_view_edit_page_stacked_pages_switch_to_expected_index(self) -> None:
|
||||
mocked_stacked_pages: MagicMock = TestViewManager._mock_stacked_pages.return_value
|
||||
|
||||
|
||||
@@ -37,10 +37,12 @@ class NotificationFrame(QFrame):
|
||||
self.setFrameStyle(QFrame.StyledPanel | QFrame.Plain)
|
||||
|
||||
icon_label: QLabel = QLabel(self)
|
||||
icon_label.setObjectName("NotificationIcon")
|
||||
icon_label.setPixmap(pixmap)
|
||||
|
||||
self._title_label: QLabel = QLabel(title, self)
|
||||
self._title_label.setObjectName("Title")
|
||||
self._title_label.setOpenExternalLinks(True)
|
||||
self._title_label.setObjectName("NotificationTitle")
|
||||
self._title_label.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred))
|
||||
self._title_label.setWordWrap(True)
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
from PySide2.QtGui import QPixmap
|
||||
from PySide2.QtWidgets import (QHBoxLayout, QLayout, QPushButton, QSizePolicy, QSpacerItem, QVBoxLayout, QWidget)
|
||||
|
||||
from model import (error_messages, notification_label_text, view_size_constants)
|
||||
from view.common_view_components import NotificationFrame
|
||||
|
||||
|
||||
class ErrorPage(QWidget):
|
||||
"""
|
||||
Error Page
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.setGeometry(0, 0,
|
||||
view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH,
|
||||
view_size_constants.ERROR_PAGE_MAIN_WINDOW_HEIGHT)
|
||||
|
||||
page_vertical_layout: QVBoxLayout = QVBoxLayout(self)
|
||||
page_vertical_layout.setSizeConstraint(QLayout.SetMinimumSize)
|
||||
page_vertical_layout.setMargin(0)
|
||||
|
||||
self._setup_notification_area()
|
||||
page_vertical_layout.addWidget(self._notification_area)
|
||||
|
||||
self._setup_footer_area()
|
||||
page_vertical_layout.addWidget(self._footer_area)
|
||||
|
||||
def _setup_notification_area(self) -> None:
|
||||
self._notification_area: QWidget = QWidget(self)
|
||||
self._notification_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
self._notification_area.setMinimumSize(view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH,
|
||||
view_size_constants.ERROR_PAGE_NOTIFICATION_AREA_HEIGHT)
|
||||
|
||||
notification_area_layout: QVBoxLayout = QVBoxLayout(self._notification_area)
|
||||
notification_area_layout.setSizeConstraint(QLayout.SetMinimumSize)
|
||||
notification_area_layout.setContentsMargins(
|
||||
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT,
|
||||
view_size_constants.MAIN_PAGE_LAYOUT_MARGIN_TOPBOTTOM,
|
||||
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT, 0)
|
||||
|
||||
notification_frame: NotificationFrame = \
|
||||
NotificationFrame(self, QPixmap(":/error_report_warning.svg"),
|
||||
error_messages.ERROR_PAGE_TOOL_SETUP_ERROR_MESSAGE, False)
|
||||
notification_frame.setObjectName("ErrorPage")
|
||||
notification_frame.setMinimumSize(view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH,
|
||||
view_size_constants.ERROR_PAGE_NOTIFICATION_AREA_HEIGHT)
|
||||
notification_frame.setVisible(True)
|
||||
notification_area_layout.addWidget(notification_frame)
|
||||
|
||||
def _setup_footer_area(self) -> None:
|
||||
self._footer_area: QWidget = QWidget(self)
|
||||
self._footer_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
self._footer_area.setMaximumSize(view_size_constants.TOOL_APPLICATION_MAIN_WINDOW_WIDTH,
|
||||
view_size_constants.ERROR_PAGE_FOOTER_AREA_HEIGHT)
|
||||
|
||||
footer_area_layout: QHBoxLayout = QHBoxLayout(self._footer_area)
|
||||
footer_area_layout.setSizeConstraint(QLayout.SetMinimumSize)
|
||||
footer_area_layout.setContentsMargins(
|
||||
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT,
|
||||
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_TOPBOTTOM,
|
||||
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_LEFTRIGHT,
|
||||
view_size_constants.ERROR_PAGE_LAYOUT_MARGIN_TOPBOTTOM)
|
||||
|
||||
footer_area_spacer: QSpacerItem = QSpacerItem(view_size_constants.ERROR_PAGE_MAIN_WINDOW_WIDTH,
|
||||
view_size_constants.INTERACTION_COMPONENT_HEIGHT,
|
||||
QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)
|
||||
footer_area_layout.addItem(footer_area_spacer)
|
||||
|
||||
self._ok_button: QPushButton = QPushButton(self._footer_area)
|
||||
self._ok_button.setObjectName("Secondary")
|
||||
self._ok_button.setText(notification_label_text.ERROR_PAGE_OK_TEXT)
|
||||
self._ok_button.setMinimumSize(view_size_constants.OK_BUTTON_WIDTH,
|
||||
view_size_constants.INTERACTION_COMPONENT_HEIGHT)
|
||||
footer_area_layout.addWidget(self._ok_button)
|
||||
|
||||
@property
|
||||
def ok_button(self) -> QPushButton:
|
||||
return self._ok_button
|
||||
Reference in New Issue
Block a user