// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
// with the License. A copy of the License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "LICENSE.txt" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
// OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions and
// limitations under the License.
import React, {useMemo} from 'react'
import i18next from 'i18next'
import {Trans, useTranslation} from 'react-i18next'
import {useState, setState, getState, clearState} from '../../store'
import {loadTemplate} from './util'
import {findFirst} from '../../util'
import {GetConfiguration} from '../../model'
// @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'js-y... Remove this comment to see the full error message
import jsyaml from 'js-yaml'
// UI Elements
import {
Box,
Container,
FormField,
Header,
Input,
RadioGroup,
Select,
SpaceBetween,
} from '@cloudscape-design/components'
// Components
import {HiddenUploader} from '../../components/FileChooser'
import Loading from '../../components/Loading'
// Types
import {ClusterInfoSummary, ClusterStatus} from '../../types/clusters'
import {useHelpPanel} from '../../components/help-panel/HelpPanel'
import TitleDescriptionHelpPanel from '../../components/help-panel/TitleDescriptionHelpPanel'
import InfoLink from '../../components/InfoLink'
// Constants
const sourcePath = ['app', 'wizard', 'source']
const sourceErrorsPath = ['app', 'wizard', 'errors', 'source']
function copyFrom(sourceClusterName: any) {
const loadingPath = ['app', 'wizard', 'source', 'loading']
GetConfiguration(sourceClusterName, (configuration: any) => {
loadTemplate(jsyaml.load(configuration), () => setState(loadingPath, false))
})
}
function sourceValidate(suppressUpload = false) {
let clusterName = getState(['app', 'wizard', 'clusterName'])
const clusters = getState(['clusters', 'list']) || []
let clusterNames = new Set(clusters.map((c: any) => c.clusterName))
let sourceClusterName = getState([
'app',
'wizard',
'source',
'selectedCluster',
])
let upload = getState([...sourcePath, 'upload'])
let source = getState([...sourcePath, 'type'])
let valid = true
const loadingPath = ['app', 'wizard', 'source', 'loading']
setState([...sourceErrorsPath, 'validated'], true)
if (!clusterName || clusterName === '') {
setState(
[...sourceErrorsPath, 'clusterName'],
i18next.t('wizard.source.validation.cannotBeBlank'),
)
valid = false
} else if (clusterNames.has(clusterName)) {
setState(
[...sourceErrorsPath, 'clusterName'],
i18next.t('wizard.source.validation.alreadyExists', {
clusterName: clusterName,
}),
)
valid = false
} else if (!/^[a-zA-Z][a-zA-Z0-9-]+$/.test(clusterName)) {
setState(
[...sourceErrorsPath, 'clusterName'],
i18next.t('wizard.source.validation.doesntMatchRegex', {
clusterName: clusterName,
}),
)
valid = false
} else {
clearState([...sourceErrorsPath, 'clusterName'])
}
if (
source === 'cluster' &&
(!sourceClusterName || sourceClusterName === '')
) {
setState(
[...sourceErrorsPath, 'sourceClusterName'],
i18next.t('wizard.source.validation.specifySourceCopy'),
)
valid = false
} else {
clearState([...sourceErrorsPath, 'sourceClusterName'])
}
// Returning false here tells the wizard not to advance
// which allows us to explicitly control the page if the
// user selects a file (or stay here if they do not)
if (valid && source === 'template' && !suppressUpload) {
upload()
return false
}
if (valid && source === 'cluster' && !suppressUpload) {
setState(loadingPath, true)
copyFrom(sourceClusterName)
return false
}
return valid
}
function checkMinorVersion(v1: string, v2: string) {
return v1.split('.', 2).join('.') === v2.split('.', 2).join('.')
}
function ClusterSelect() {
const selectedPath = ['app', 'wizard', 'source', 'selectedCluster']
const apiVersion = useState(['app', 'version', 'full'])
const clusters = useState(['clusters', 'list']) || []
const selectableClusters = clusters
.filter(
(cluster: ClusterInfoSummary) =>
cluster.clusterStatus != ClusterStatus.DeleteInProgress,
)
.filter((cluster: ClusterInfoSummary) =>
checkMinorVersion(cluster.version, apiVersion),
)
const selected = useState(selectedPath)
const errors = useState([...sourceErrorsPath, 'sourceClusterName'])
let source = useState([...sourcePath, 'type'])
let validated = useState([...sourceErrorsPath, 'validated'])
const itemToOption = (item: ClusterInfoSummary) => ({
label: item.clusterName,
value: item.clusterName,
})
return (