diff --git a/frontend/packages/console-shared/src/constants/common.ts b/frontend/packages/console-shared/src/constants/common.ts index c4d07ca7bca..58df54d8c36 100644 --- a/frontend/packages/console-shared/src/constants/common.ts +++ b/frontend/packages/console-shared/src/constants/common.ts @@ -99,3 +99,6 @@ export enum REQUESTER_FILTER { USER = 'user', SYSTEM = 'system', } + +export const CLUSTER_VERSION_DEFAULT_UPSTREAM_SERVER_URL_PLACEHOLDER = + 'https://api.openshift.com/api/upgrades_info/v1/graph'; diff --git a/frontend/public/components/cluster-settings/cluster-settings.tsx b/frontend/public/components/cluster-settings/cluster-settings.tsx index 76443ac3560..1b283acab2f 100644 --- a/frontend/public/components/cluster-settings/cluster-settings.tsx +++ b/frontend/public/components/cluster-settings/cluster-settings.tsx @@ -89,6 +89,7 @@ import { SectionHeading, Timestamp, truncateMiddle, + UpstreamConfigDetailsItem, useAccessReview, } from '../utils'; import { @@ -1001,6 +1002,7 @@ export const ClusterVersionDetailsTable: React.FC + {autoscalers && ( <>
{t('public~Cluster autoscaler')}
diff --git a/frontend/public/components/cluster-settings/cluster-version.tsx b/frontend/public/components/cluster-settings/cluster-version.tsx index bbdd6829e70..ddd9103db09 100644 --- a/frontend/public/components/cluster-settings/cluster-version.tsx +++ b/frontend/public/components/cluster-settings/cluster-version.tsx @@ -6,7 +6,7 @@ import { ClusterVersionModel } from '../../models'; import { DetailsPage } from '../factory'; import { Conditions } from '../conditions'; import { ClusterVersionKind, K8sResourceKindReference, referenceForModel } from '../../module/k8s'; -import { navFactory, ResourceSummary, SectionHeading } from '../utils'; +import { navFactory, ResourceSummary, SectionHeading, UpstreamConfigDetailsItem } from '../utils'; import { breadcrumbsForGlobalConfig } from './global-config'; const clusterVersionReference: K8sResourceKindReference = referenceForModel(ClusterVersionModel); @@ -18,7 +18,9 @@ const ClusterVersionDetails: React.FC = ({ obj }) => <>
- + + +
diff --git a/frontend/public/components/modals/configure-cluster-upstream-modal.tsx b/frontend/public/components/modals/configure-cluster-upstream-modal.tsx new file mode 100644 index 00000000000..c35fd83046e --- /dev/null +++ b/frontend/public/components/modals/configure-cluster-upstream-modal.tsx @@ -0,0 +1,129 @@ +import * as React from 'react'; + +import { ClusterVersionModel } from '../../models'; +import { ClusterVersionKind, k8sPatch } from '../../module/k8s'; +import { + ModalBody, + ModalComponentProps, + ModalSubmitFooter, + ModalTitle, + createModalLauncher, +} from '../factory/modal'; +import { ExternalLink, HandlePromiseProps, withHandlePromise } from '../utils'; +import { useTranslation } from 'react-i18next'; +import { TFunction } from 'i18next'; +import { RadioInput } from '../radio'; +import { CLUSTER_VERSION_DEFAULT_UPSTREAM_SERVER_URL_PLACEHOLDER } from '@console/shared/src/constants'; +import { TextInput } from '@patternfly/react-core'; +import { openshiftHelpBase } from '@console/internal/components/utils'; + +export const ConfigureClusterUpstreamModal = withHandlePromise( + (props: ConfigureClusterUpstreamModalProps) => { + const { cv, handlePromise, close } = props; + const currentUpstream = cv?.spec?.upstream; + + const [customSelected, setCustomSelected] = React.useState(!!currentUpstream); + const [customURL, setCustomURL] = React.useState(currentUpstream); + const [invalidCustomURL, setInvalidCustomURL] = React.useState(false); + + const submit: React.FormEventHandler = (e) => { + e.preventDefault(); + if (customSelected) { + if (!customURL) { + setInvalidCustomURL(true); + return; + } else if (customURL === currentUpstream) { + return handlePromise(Promise.resolve(), close); + } + } else if (!currentUpstream) { + return handlePromise(Promise.resolve(), close); + } + const value = customSelected ? customURL : null; + const patch = [{ op: 'add', path: '/spec/upstream', value }]; + return handlePromise(k8sPatch(ClusterVersionModel, cv, patch), close); + }; + const { t } = useTranslation(); + + return ( +
+ {t('public~Edit upstream configuration')} + +

+ {t( + 'public~Select a configuration to receive updates. Updates can be configured to receive information from Red Hat or a custom update service.', + )} +

+

+ +

+
+
+ + { + setCustomSelected(false); + setInvalidCustomURL(false); + }} + checked={!customSelected} + title={t('public~Default. Receive update information from Red Hat.')} + > + + + setCustomSelected(true)} + checked={customSelected} + title={t('public~Custom update service.')} + > + { + setCustomSelected(true); + setCustomURL(text); + setInvalidCustomURL(false); + }} + validated={invalidCustomURL ? 'error' : 'default'} + /> + {invalidCustomURL && ( +
+
+ {t('public~Please enter a URL')} +
+
+ )} +
+
+
+
+ + + ); + }, +); + +export const configureClusterUpstreamModal = createModalLauncher(ConfigureClusterUpstreamModal); + +export type ConfigureClusterUpstreamModalProps = { + cv: ClusterVersionKind; + t: TFunction; +} & ModalComponentProps & + HandlePromiseProps; diff --git a/frontend/public/components/modals/index.ts b/frontend/public/components/modals/index.ts index bab8e7c2aaf..2274c752b00 100644 --- a/frontend/public/components/modals/index.ts +++ b/frontend/public/components/modals/index.ts @@ -109,6 +109,11 @@ export const removeVolumeModal = (props) => m.removeVolumeModal(props), ); +export const configureClusterUpstreamModal = (props) => + import( + './configure-cluster-upstream-modal' /* webpackChunkName: "configure-cluster-upstream-modal" */ + ).then((m) => m.configureClusterUpstreamModal(props)); + export const configureMachineAutoscalerModal = (props) => import( './configure-machine-autoscaler-modal' /* webpackChunkName: "configure-machine-autoscaler-modal" */ diff --git a/frontend/public/components/utils/details-page.tsx b/frontend/public/components/utils/details-page.tsx index 37041724db2..091684a476a 100644 --- a/frontend/public/components/utils/details-page.tsx +++ b/frontend/public/components/utils/details-page.tsx @@ -19,7 +19,8 @@ import { referenceFor, Toleration, } from '../../module/k8s'; -import { labelsModal } from '../modals'; +import { configureClusterUpstreamModal, labelsModal } from '../modals'; +import { ClusterVersionModel } from '../../models'; const editLabelsModal = (e, props) => { e.preventDefault(); @@ -193,6 +194,43 @@ export const RuntimeClass: React.FC = ({ obj, path }) => { ); }; +export const UpstreamConfigDetailsItem: React.SFC = ({ + resource, +}) => { + const { t } = useTranslation(); + // TODO this specific RBAC is duplicated across several modals and pages + const clusterVersionIsEditable = + useAccessReview({ + group: ClusterVersionModel.apiGroup, + resource: ClusterVersionModel.plural, + verb: 'patch', + name: resource?.metadata?.name, + }) && window.SERVER_FLAGS.branding !== 'dedicated'; + return ( + +
+ +
+
+ ); +}; + export type ResourceSummaryProps = { resource: K8sResourceKind; showPodSelector?: boolean; @@ -211,6 +249,10 @@ export type ResourcePodCountProps = { resource: K8sResourceKind; }; +export type UpstreamConfigDetailsItemProps = { + resource: K8sResourceKind; +}; + export type RuntimeClassProps = { obj: K8sResourceCommon; path?: string; diff --git a/frontend/public/locales/en/public.json b/frontend/public/locales/en/public.json index 9caf6674b72..5a70a44ee49 100644 --- a/frontend/public/locales/en/public.json +++ b/frontend/public/locales/en/public.json @@ -705,6 +705,12 @@ "Additional columns": "Additional columns", "Additional column list": "Additional column list", "Restore default columns": "Restore default columns", + "Edit upstream configuration": "Edit upstream configuration", + "Select a configuration to receive updates. Updates can be configured to receive information from Red Hat or a custom update service.": "Select a configuration to receive updates. Updates can be configured to receive information from Red Hat or a custom update service.", + "Learn more about OpenShift local update services.": "Learn more about OpenShift local update services.", + "Default. Receive update information from Red Hat.": "Default. Receive update information from Red Hat.", + "Custom update service.": "Custom update service.", + "Please enter a URL": "Please enter a URL", "Edit Pod count": "Edit Pod count", "{{resourceKinds}} maintain the desired number of healthy pods.": "{{resourceKinds}} maintain the desired number of healthy pods.", "{{resourceKinds}} create one or more pods and ensure that a specified number of them successfully terminate. When the specified number of completions is successfully reached, the job is complete.": "{{resourceKinds}} create one or more pods and ensure that a specified number of them successfully terminate. When the specified number of completions is successfully reached, the job is complete.", @@ -1515,6 +1521,8 @@ "{{count}} annotation": "{{count}} annotation", "{{count}} annotation_plural": "{{count}} annotations", "Runtime class": "Runtime class", + "Upstream configuration": "Upstream configuration", + "Default update server": "Default update server", "Remove bookmark {{content}}": "Remove bookmark {{content}}", "Add bookmark {{content}}": "Add bookmark {{content}}", "Remove favorite {{content}}": "Remove favorite {{content}}",