Editor/Window/Containers/ContainersUserInput.cs (371 lines of code) (raw):

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UIElements; using UnityEditor; using System.Linq; using AmazonGameLiftPlugin.Core.ContainerManagement.Models; using Amazon.ECR.Model; namespace AmazonGameLift.Editor { internal class ContainersUserInput : StatefulInput { private readonly VisualElement _container; private readonly DeploymentScenariosInput _deploymentScenarioInput; private VisualElement _containerServerBuildInputRow; private VisualElement _containerServerExecutableInputRow; private VisualElement _selectECRRepositoryDropdownRow; private VisualElement _containerECRImageDropdownRow; private VisualElement _dockerImageIDInputRow; private VisualElement _imageTagInputRow; private TextField _containerGameServerBuildInput; private TextField _containerGameServerExecutableInput; private TextField _dockerImageIDInput; private TextField _containerPortRangeInput; private TextField _containerTotalMemoryInput; private TextField _containerTotalVcpuInput; private TextField _containerImageTagInput; private TextField _containerGameNameInput; private Label _invalidPortRangeLabel; private Label _invalidMemoryLimitLabel; private Label _invalidVcpuLimitLabel; private Label _invalidGameNameLabel; private Label _invalidContainerImageTagLabel; private Label _invalidGameServerBuildLabel; private Label _invalidGameServerExecutableLabel; private Label _invalidECRRepoLabel; private Label _invalidECRImageLabel; private Label _invalidDockerImageIDLabel; private DropdownField _selectECRRepositoryDropdownContainer; private DropdownField _selectECRImageDropdownContainer; private Button _serverFolderButton; private Button _serverFileButton; private DescribeECRRepositoriesResponse _ecrRepositories; private Foldout _defaultPropertiesFoldout; private readonly Dictionary<string, string> _ecrRepoNameUriMap = new Dictionary<string, string>(); private readonly StateManager _stateManager; private readonly CoreApi _coreApi; private readonly ContainersUserInputValidation _inputValidator; public Action<DeploymentScenarios> OnValueChanged; public Action OnValidationEvent; public ContainersUserInput(VisualElement container, StateManager stateManager, bool enabled) { var uxml = Resources.Load<VisualTreeAsset>("EditorWindow/Components/Containers/ContainersUserInput"); container.Add(uxml.Instantiate()); _container = container; _stateManager = stateManager; _coreApi = CoreApi.SharedInstance; ReferenceComponents(); _inputValidator = new ContainersUserInputValidation(GetErrorMessageMappings(), GetInputMappings()); RegisterCallbacks(); var scenarioContainer = container.Q("ContainersDeploymentScenarioContainer"); _deploymentScenarioInput = new DeploymentScenariosInput(scenarioContainer, _stateManager.ContainerDeploymentScenario, _stateManager.IsBootstrapped() && _stateManager.IsInContainersRegion(), stateManager, () => _stateManager.ContainerDeploymentScenario); _deploymentScenarioInput.OnValueChanged += value => { _stateManager.ContainerDeploymentScenario = value; }; _stateManager.OnContainerQuestionnaireScenarioChanged += UpdateGUI; _stateManager.OnUserProfileUpdated += UpdateGUI; SetupInputsValues(); _defaultPropertiesFoldout.value = false; SetEnabled(enabled); _inputValidator.OnValidationEvent += TriggerValidation; LocalizeText(); UpdateGUI(); } private void ReferenceComponents() { _containerServerBuildInputRow = _container.Q<VisualElement>("ContainerServerBuildInputRow"); _containerServerExecutableInputRow = _container.Q<VisualElement>("ContainerServerExecutableInputRow"); _selectECRRepositoryDropdownRow = _container.Q<VisualElement>("SelectECRRepositoryDropdownRow"); _containerECRImageDropdownRow = _container.Q<VisualElement>("ContainerECRImageDropdownRow"); _dockerImageIDInputRow = _container.Q<VisualElement>("DockerImageIDInputRow"); _imageTagInputRow = _container.Q<VisualElement>("ImageTagInputInputRow"); _containerGameServerBuildInput = _container.Q<TextField>("ContainerGameServerBuildInput"); _containerGameServerExecutableInput = _container.Q<TextField>("ContainerGameServerExecutableInput"); _dockerImageIDInput = _container.Q<TextField>("DockerImageIDInput"); _containerPortRangeInput = _container.Q<TextField>("ContainerPortRangeInput"); _containerTotalMemoryInput = _container.Q<TextField>("ContainerTotalMemoryInput"); _containerTotalVcpuInput = _container.Q<TextField>("ContainerTotalVcpuInput"); _containerImageTagInput = _container.Q<TextField>("ContainerImageTagInput"); _containerGameNameInput = _container.Q<TextField>("ContainerGameNameInput"); _invalidPortRangeLabel = _container.Q<Label>("ContainerConnectionPortRangeInvalidMessage"); _invalidMemoryLimitLabel = _container.Q<Label>("ContainerTotalMemoryInvalidMessage"); _invalidVcpuLimitLabel = _container.Q<Label>("ContainerTotalVcpuInvalidMessage"); _invalidGameNameLabel = _container.Q<Label>("ContainerGameNameInvalidMessage"); _invalidContainerImageTagLabel = _container.Q<Label>("ContainerImageTagInvalidMessage"); _invalidDockerImageIDLabel = _container.Q<Label>("DockerImageIDInvalidMessage"); _invalidECRImageLabel = _container.Q<Label>("SelectECRImageDropdownInvalidMessage"); _invalidECRRepoLabel = _container.Q<Label>("SelectECRRepositoryDropdownInvalidMessage"); _invalidGameServerExecutableLabel = _container.Q<Label>("ContainerGameServerExecutableInputInvalidMessage"); _invalidGameServerBuildLabel = _container.Q<Label>("ContainerGameServerBuildInputInvalidMessage"); _selectECRRepositoryDropdownContainer = _container.Q<DropdownField>("SelectECRRepositoryDropdown"); _selectECRImageDropdownContainer = _container.Q<DropdownField>("SelectECRImageDropdown"); _serverFileButton = _container.Q<Button>("ContainerGameServerExecutableButton"); _serverFolderButton = _container.Q<Button>("ContainerGameServerBuildButton"); _defaultPropertiesFoldout = _container.Q<Foldout>("DefaultSettingsFoldout"); } private void RegisterCallbacks() { // buttons _serverFileButton.RegisterCallback<ClickEvent>(_ => { var value = EditorUtility.OpenFilePanel("Game Server Build Executable Path", _stateManager.ContainerGameServerBuildPath, ""); _containerGameServerExecutableInput.value = value; }); _serverFolderButton.RegisterCallback<ClickEvent>(_ => { var value = EditorUtility.OpenFolderPanel("Game Server Build Directory Path", Application.dataPath, ""); _containerGameServerBuildInput.value = value; }); // dropdown selections _selectECRRepositoryDropdownContainer.RegisterValueChangedCallback(evt => { _stateManager.ContainerECRRepositoryName = evt.newValue; _stateManager.ContainerECRRepositoryUri = evt.newValue != null ? _ecrRepoNameUriMap[evt.newValue] : evt.newValue; // repopulate or clear images when ecr repo changes PopulateECRImagesDropdown(evt.newValue); }); _selectECRImageDropdownContainer.RegisterValueChangedCallback(evt => { _stateManager.ContainerECRImageId = evt.newValue; }); // input validation actions _inputValidator.RegisterValidationCallbacks(); } private Dictionary<ContainersUserInputType, Label> GetErrorMessageMappings() { var errorMessagesMappings = new Dictionary<ContainersUserInputType, Label> { { ContainersUserInputType.ConnectionPortRangeInput, _invalidPortRangeLabel }, { ContainersUserInputType.ContainerImageTagInput, _invalidContainerImageTagLabel }, { ContainersUserInputType.DockerImageInput, _invalidDockerImageIDLabel }, { ContainersUserInputType.EcrImageDropdown, _invalidECRImageLabel }, { ContainersUserInputType.EcrRepositoryDropdown, _invalidECRRepoLabel }, { ContainersUserInputType.GameNameInput, _invalidGameNameLabel }, { ContainersUserInputType.GameServerExecutableInput, _invalidGameServerExecutableLabel }, { ContainersUserInputType.GameServerFolderInput, _invalidGameServerBuildLabel }, { ContainersUserInputType.MemoryLimitInput, _invalidMemoryLimitLabel }, { ContainersUserInputType.VcpuLimitInput, _invalidVcpuLimitLabel } }; return errorMessagesMappings; } private Dictionary<ContainersUserInputType, VisualElement> GetInputMappings() { var inputMappings = new Dictionary<ContainersUserInputType, VisualElement> { { ContainersUserInputType.ConnectionPortRangeInput, _containerPortRangeInput }, { ContainersUserInputType.ContainerImageTagInput, _containerImageTagInput }, { ContainersUserInputType.DockerImageInput, _dockerImageIDInput }, { ContainersUserInputType.EcrImageDropdown, _selectECRImageDropdownContainer }, { ContainersUserInputType.EcrRepositoryDropdown, _selectECRRepositoryDropdownContainer }, { ContainersUserInputType.GameNameInput, _containerGameNameInput }, { ContainersUserInputType.GameServerExecutableInput, _containerGameServerExecutableInput }, { ContainersUserInputType.GameServerFolderInput, _containerGameServerBuildInput }, { ContainersUserInputType.MemoryLimitInput, _containerTotalMemoryInput }, { ContainersUserInputType.VcpuLimitInput, _containerTotalVcpuInput } }; return inputMappings; } protected sealed override void UpdateGUI() { PopulateDeploymentInputs(); } private void TriggerValidation() { OnValidationEvent?.Invoke(); } public void SetEnabled(bool value) { _containerServerBuildInputRow.SetEnabled(value); _containerServerExecutableInputRow.SetEnabled(value); _selectECRRepositoryDropdownContainer.SetEnabled(value); _selectECRImageDropdownContainer.SetEnabled(value); _selectECRRepositoryDropdownRow.SetEnabled(value); _containerECRImageDropdownRow.SetEnabled(value); _dockerImageIDInputRow.SetEnabled(value); _imageTagInputRow.SetEnabled(value); _deploymentScenarioInput.SetEnabled(value); _containerGameNameInput.SetEnabled(value); _containerTotalVcpuInput.SetEnabled(value); _containerTotalMemoryInput.SetEnabled(value); _containerPortRangeInput.SetEnabled(value); _imageTagInputRow.SetEnabled(value); } private void HideAll() { Hide(_containerServerBuildInputRow); Hide(_containerServerExecutableInputRow); Hide(_selectECRRepositoryDropdownRow); Hide(_containerECRImageDropdownRow); Hide(_dockerImageIDInputRow); Hide(_imageTagInputRow); Hide(_invalidECRImageLabel); Hide(_invalidContainerImageTagLabel); Hide(_invalidPortRangeLabel); Hide(_invalidMemoryLimitLabel); Hide(_invalidVcpuLimitLabel); Hide(_invalidGameNameLabel); Hide(_invalidGameServerBuildLabel); Hide(_invalidGameServerExecutableLabel); Hide(_invalidECRRepoLabel); Hide(_invalidDockerImageIDLabel); } private void PopulateDeploymentInputs() { var deploymentScenario = _stateManager.ContainerQuestionnaireScenario; HideAll(); List<ContainersUserInputType> activeInputs = new List<ContainersUserInputType> { ContainersUserInputType.VcpuLimitInput, ContainersUserInputType.MemoryLimitInput, ContainersUserInputType.GameNameInput, ContainersUserInputType.ConnectionPortRangeInput, }; switch (deploymentScenario) { case ContainerScenarios.NoContainerImageNoExistingEcrRepo: Show(_containerServerBuildInputRow); Show(_containerServerExecutableInputRow); Show(_imageTagInputRow); activeInputs.Add(ContainersUserInputType.GameServerFolderInput); activeInputs.Add(ContainersUserInputType.GameServerExecutableInput); activeInputs.Add(ContainersUserInputType.ContainerImageTagInput); break; case ContainerScenarios.NoContainerImageUseExistingEcrRepo: Show(_containerServerBuildInputRow); Show(_containerServerExecutableInputRow); Show(_selectECRRepositoryDropdownRow); Show(_imageTagInputRow); activeInputs.Add(ContainersUserInputType.GameServerFolderInput); activeInputs.Add(ContainersUserInputType.GameServerExecutableInput); activeInputs.Add(ContainersUserInputType.ContainerImageTagInput); activeInputs.Add(ContainersUserInputType.EcrRepositoryDropdown); PopulateECRRepositoriesDropdown(); break; case ContainerScenarios.HaveContainerImageInDocker: Show(_dockerImageIDInputRow); Show(_imageTagInputRow); activeInputs.Add(ContainersUserInputType.ContainerImageTagInput); activeInputs.Add(ContainersUserInputType.DockerImageInput); break; case ContainerScenarios.HaveContainerImageInEcr: Show(_selectECRRepositoryDropdownRow); Show(_containerECRImageDropdownRow); activeInputs.Add(ContainersUserInputType.EcrRepositoryDropdown); activeInputs.Add(ContainersUserInputType.EcrImageDropdown); PopulateECRRepositoriesDropdown(); PopulateECRImagesDropdown(_stateManager.ContainerECRRepositoryName); break; } _inputValidator.SetActiveInputs(activeInputs); } private void PopulateECRImagesDropdown(string repositoryName) { if (_stateManager.IsBootstrapped() && _stateManager.IsInContainersRegion()) { if (!string.IsNullOrEmpty(repositoryName)) { var images = _coreApi.ListECRImages(_stateManager.ProfileName, _stateManager.Region, repositoryName); List<string> choices = images.ECRImages.Select(image => string.IsNullOrEmpty(image.ImageTag) ? image.ImageDigest : image.ImageTag).ToList(); _selectECRImageDropdownContainer.choices = choices; if (!string.IsNullOrEmpty(_stateManager.ContainerECRImageId) && choices.Contains(_stateManager.ContainerECRImageId)) { _selectECRImageDropdownContainer.value = _stateManager.ContainerECRImageId; return; } } } _selectECRImageDropdownContainer.value = null; _stateManager.ContainerECRImageId = null; } private void PopulateECRRepositoriesDropdown() { if (_stateManager.IsBootstrapped() && _stateManager.IsInContainersRegion()) { _ecrRepositories = _coreApi.DescribeECRRepositories(_stateManager.ProfileName, _stateManager.Region); if (_ecrRepositories != null && _ecrRepositories.ECRRepositories != null) { List<string> choices = _ecrRepositories.ECRRepositories.Select(repository => repository.RepositoryName).ToList(); _selectECRRepositoryDropdownContainer.choices = choices; foreach (Repository repo in _ecrRepositories.ECRRepositories) { if (!_ecrRepoNameUriMap.ContainsKey(repo.RepositoryName)) { _ecrRepoNameUriMap.Add(repo.RepositoryName, repo.RepositoryUri); } } if (!string.IsNullOrEmpty(_stateManager.ContainerECRRepositoryName) && choices.Contains(_stateManager.ContainerECRRepositoryName)) { _selectECRRepositoryDropdownContainer.value = _stateManager.ContainerECRRepositoryName; _stateManager.ContainerECRRepositoryUri = _ecrRepoNameUriMap[_stateManager.ContainerECRRepositoryName]; return; } } } _selectECRRepositoryDropdownContainer.value = null; _stateManager.ContainerECRRepositoryUri = null; _stateManager.ContainerECRRepositoryName = null; } public void SetupInputsValues() { _containerGameServerBuildInput.value = _stateManager.ContainerGameServerBuildPath; _containerGameServerExecutableInput.value = _stateManager.ContainerGameServerExecutable; _dockerImageIDInput.value = _stateManager.ContainerDockerImageId; _containerPortRangeInput.value = string.IsNullOrEmpty(_stateManager.ContainerPortRange) ? ContainersUserInputValidation.DEFAULT_PORT_RANGE : _stateManager.ContainerPortRange; _containerTotalMemoryInput.value = string.IsNullOrEmpty(_stateManager.ContainerTotalMemory) ? ContainersUserInputValidation.DEFAULT_MEMORY_LIMIT : _stateManager.ContainerTotalMemory; _containerTotalVcpuInput.value = string.IsNullOrEmpty(_stateManager.ContainerTotalVcpu) ? ContainersUserInputValidation.DEFAULT_VCPU_LIMIT : _stateManager.ContainerTotalVcpu; _containerImageTagInput.value = string.IsNullOrEmpty(_stateManager.ContainerImageTag) ? ContainersUserInputValidation.DEFAULT_IMAGE_TAG : _stateManager.ContainerImageTag; _containerGameNameInput.value = string.IsNullOrEmpty(_stateManager.ContainerGameName) ? ContainersUserInputValidation.DEFAULT_GAME_NAME : _stateManager.ContainerGameName; } public void PopulateContent() { SetupInputsValues(); PopulateDeploymentInputs(); _deploymentScenarioInput.PopulateContent(); } public void SaveValues() { _stateManager.ContainerPortRange = _containerPortRangeInput.value; _stateManager.ContainerTotalMemory = _containerTotalMemoryInput.value; _stateManager.ContainerTotalVcpu = _containerTotalVcpuInput.value; _stateManager.ContainerGameName = _containerGameNameInput.value; switch (_stateManager.ContainerQuestionnaireScenario) { case ContainerScenarios.NoContainerImageNoExistingEcrRepo: _stateManager.ContainerImageTag = _containerImageTagInput.value; _stateManager.ContainerGameServerBuildPath = _containerGameServerBuildInput.value; _stateManager.ContainerGameServerExecutable = _containerGameServerExecutableInput.value; break; case ContainerScenarios.NoContainerImageUseExistingEcrRepo: _stateManager.ContainerImageTag = _containerImageTagInput.value; _stateManager.ContainerGameServerBuildPath = _containerGameServerBuildInput.value; _stateManager.ContainerGameServerExecutable = _containerGameServerExecutableInput.value; _stateManager.ContainerECRRepositoryName = _selectECRRepositoryDropdownContainer.value; break; case ContainerScenarios.HaveContainerImageInDocker: _stateManager.ContainerDockerImageId = _dockerImageIDInput.value; _stateManager.ContainerImageTag = _containerImageTagInput.value; break; case ContainerScenarios.HaveContainerImageInEcr: _stateManager.ContainerECRRepositoryName = _selectECRRepositoryDropdownContainer.value; _stateManager.ContainerECRImageId = _selectECRImageDropdownContainer.value; break; } } public bool AllInputsValid() { return _inputValidator.AllInputsValid(); } private void LocalizeText() { var l = new ElementLocalizer(_container); l.SetElementText("ContainerGameServerBuildLabel", Strings.ContainerGameServerBuildLabel); l.SetElementText("ContainerGameServerExecutableLabel", Strings.ContainerGameServerExecutableLabel); l.SetElementText("SelectECRRepositoryLabel", Strings.SelectECRRepositoryLabel); l.SetElementText("ContainerSelectImageLabel", Strings.ContainerSelectImageLabel); l.SetElementText("DockerImageIDLabel", Strings.DockerImageIDLabel); l.SetElementText("DefaultSettingsFoldout", Strings.DefaultSettings); l.SetElementText("DefaultSettingsDescription", Strings.DefaultSettingsDescription); l.SetElementText("ContainerConnectionPortRangeLabel", Strings.ContainerConnectionPortRangeLabel); l.SetElementText("ContainerTotalMemoryLabel", Strings.ContainerTotalMemoryLabel); l.SetElementText("ContainerTotalVcpuLabel", Strings.ContainerTotalVcpuLabel); l.SetElementText("ContainerImageTagLabel", Strings.ContainerImageTagLabel); } } }