Skip to content

Commit

Permalink
Feature Availability Zone (#614)
Browse files Browse the repository at this point in the history
* WIP: Add selector and info display for availability zones

* further attempts at getting the availability zone to post

* Push for Spencer

* default the availability zone in the hosting environment card itself

* Remove commented out code that didn't work

* Update hosting env snapshot

* add support to pull version manifest without token. remove ability to fetch and engagement by customer / project in path.

* feature map availability zone

* remove console.log

Co-authored-by: Jacob See <[email protected]>
  • Loading branch information
mcanoy and jacobsee authored Jun 23, 2022
1 parent c310e9a commit 31d647c
Show file tree
Hide file tree
Showing 22 changed files with 125 additions and 74 deletions.
8 changes: 7 additions & 1 deletion src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext } from 'react';
import React, { useContext, useEffect } from 'react';
import '@patternfly/react-core/dist/styles/base.css';
import { BrowserRouter as Router, useLocation } from 'react-router-dom';
import qs from 'query-string';
Expand Down Expand Up @@ -107,6 +107,12 @@ export const App = ({ config }: { config: Config }) => {
const FeatureProvider = ({ children }) => {
const location = useLocation();
const versionContext = useContext(VersionContext);
useEffect(() => {
if (!versionContext.versions) {
versionContext?.fetchVersions();
}
}, [versionContext]);

const { appConfig } = useConfig();
let version = versionContext.versions?.mainVersion?.value;
if (appConfig?.allowVersionOverride) {
Expand Down
3 changes: 2 additions & 1 deletion src/common/app_features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export const APP_FEATURES = {
engagementCardIcons: 'engagementCardIcons',
dashboardDateSelector: 'dashboard-date-selector',
engagementWriter: 'engagementWriter',
copyFrom: 'copyFrom'
copyFrom: 'copyFrom',
availabilityZone: 'availabilityZone',
};

export type AppFeature = keyof typeof APP_FEATURES;
1 change: 1 addition & 0 deletions src/common/human_readable_engagement_field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function getHumanReadableFieldName(field: string): string {
location: `Location`,
ocp_cloud_provider_name: 'Cloud Provider Name',
ocp_cloud_provider_region: 'Cloud Provider Region',
ocp_cloud_provider_availability_zone: 'Cloud Provider Availability Zone',
ocp_cluster_size: 'Cluster Size',
ocp_persistent_storage_size: `Persistent Storage Size`,
ocp_sub_domain: 'Subdomain',
Expand Down
4 changes: 3 additions & 1 deletion src/common/version_feature_factory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ export type FeatureVersionMap = {
[key in AppFeature]?: string;
};

export const FEATURE_VERSION_MAP: FeatureVersionMap = {};
export const FEATURE_VERSION_MAP: FeatureVersionMap = {
availabilityZone: 'v1.3.40',
};

const getSemverFromVersionString = (version: string = ''): string => {
return semver.clean(version);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import { InfoCircleIcon } from '@patternfly/react-icons';
import { Tooltip, TooltipPosition } from '@patternfly/react-core';
import { EngagementFormConfig } from '../../../schemas/engagement_config';
import { useEngagement } from '../../../context/engagement_context/engagement_hook';

export function AvailabilityZoneTooltip() {
const { engagementFormConfig } = useEngagement();

function createTooltipText(engagementFormConfig: EngagementFormConfig) {
let text = [<div key={'tooltipText'} />];
(engagementFormConfig?.cloud_options?.availability_zones?.options ?? []).map(
(option: any, index: number) => {
return text.push(<div key={index}>{descriptionText(option)}</div>);
}
);
return text;
}

function descriptionText(option?: any) {
return (
<>
<b style={{ color: '#73BCF7' }}> {option.label} </b>
<br /> {option.description}
<br />
</>
);
}

return (
<>
<Tooltip
content={createTooltipText(engagementFormConfig)}
entryDelay={0}
exitDelay={10}
maxWidth={'45rem'}
isContentLeftAligned={true}
position={TooltipPosition.top}
>
<InfoCircleIcon style={{ fontSize: 'small', marginLeft: '1rem' }} />
</Tooltip>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,14 @@ export function HostingEnvironmentCard() {
const onSave = () => {
saveEngagement({
...(currentChanges as Engagement),
hosting_environments: hostingEnvironments,
hosting_environments: hostingEnvironments.map(he => ({
...he,
ocp_cloud_provider_availability_zone:
he.ocp_cloud_provider_availability_zone ??
engagementFormConfig?.cloud_options?.availability_zones?.options?.find(
element => element.default
).value,
})),
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ Object {
>
<select
aria-invalid="false"
aria-label="Hosting Type"
class="pf-c-form-control"
data-ouia-component-id="OUIA-Generated-FormSelect-default-1"
data-ouia-component-type="PF4/FormSelect"
Expand Down Expand Up @@ -288,6 +289,7 @@ Object {
</div>
</div>
<div
class="pf-c-form__group"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { useFeatures } from '../../context/feature_context/feature_hook';
import { APP_FEATURES } from '../../common/app_features';
import { useSubdomainUniqueness } from '../../hooks/subdomain_checker';
import { hasRequiredFields } from '../../common/validate_hosting_environment';
import { AvailabilityZoneTooltip } from '../engagement_data_cards/hosting_environment_card/availability_zone_tooltip';

export interface OpenShiftClusterEditModalProps {
hostingEnvironment: Partial<HostingEnvironment>;
isOpen: boolean;
Expand Down Expand Up @@ -59,7 +61,14 @@ export function OpenShiftClusterEditModal({
hostingEnvironment
);

const onSave = () => {
const onSave = async () => {
if (hostingEnvironment.ocp_cloud_provider_availability_zone === undefined) {
await setHostingEnvironment({
...hostingEnvironment,
ocp_cloud_provider_availability_zone: engagementFormConfig?.cloud_options?.availability_zones?.options?.find(element => element.default).value,
} as HostingEnvironment);
hostingEnvironment.ocp_cloud_provider_availability_zone = engagementFormConfig?.cloud_options?.availability_zones?.options?.find(element => element.default).value;
}
propsOnSave(hostingEnvironment);
onClose();
};
Expand Down Expand Up @@ -127,6 +136,7 @@ export function OpenShiftClusterEditModal({
hostingEnvironment={hostingEnvironment}
/>
<SelectFormField
arial-label="Provider Region"
label="Provider Region"
isDisabled={
availableProviderRegionOptions?.length === 0 ||
Expand All @@ -144,7 +154,29 @@ export function OpenShiftClusterEditModal({
onChange={value => onChange('ocp_cloud_provider_region', value)}
value={hostingEnvironment?.ocp_cloud_provider_region}
/>
{hasFeature(APP_FEATURES.availabilityZone) ?
<SelectFormField
aria-label='Availability Zone'
label={<>Availability Zone
<AvailabilityZoneTooltip /></>}
isDisabled={
engagementFormConfig?.cloud_options?.availability_zones?.options?.length === 0 ||
!hasFeature(APP_FEATURES.writer)
}
testId="provider-availability-zone-select"
emptyValue={{
label: "Select an availability zone configuration"
}}
options={engagementFormConfig?.cloud_options?.availability_zones?.options?.map?.(
v => ({ label: v.label, disabled: v.disabled, value: v.value })
)}
onChange={value => onChange('ocp_cloud_provider_availability_zone', value)}
value={hostingEnvironment?.ocp_cloud_provider_availability_zone ?? engagementFormConfig?.cloud_options?.availability_zones?.options?.find(element => element.default).value}
/>

: ''}
<SelectFormField
aria-label='OpenShift version'
value={hostingEnvironment?.ocp_version || ''}
testId="oc_version_select"
emptyValue={{ label: 'Select a version' }}
Expand All @@ -170,6 +202,7 @@ export function OpenShiftClusterEditModal({
<SelectFormField
value={hostingEnvironment?.ocp_persistent_storage_size}
testId="persistent-storage-select"
aria-label='Persistent Storage Needs'
label="Persistent Storage Needs"
options={engagementFormConfig?.openshift_options?.persistent_storage?.options?.map?.(
v => ({ label: v.label, disabled: v.disabled, value: v.value })
Expand All @@ -189,6 +222,7 @@ export function OpenShiftClusterEditModal({
value={hostingEnvironment?.ocp_cluster_size || ''}
emptyValue={{ label: 'Select cluster size' }}
label="Cluster Size"
aria-label="Cluster Size"
isDisabled={!hasFeature(APP_FEATURES.writer)}
onChange={value => onChange('ocp_cluster_size', value)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ Object {
>
<select
aria-invalid="false"
aria-label="Hosting Type"
class="pf-c-form-control"
data-ouia-component-id="OUIA-Generated-FormSelect-default-1"
data-ouia-component-type="PF4/FormSelect"
Expand Down Expand Up @@ -264,6 +265,7 @@ Object {
>
<select
aria-invalid="false"
aria-label="Hosting Type"
class="pf-c-form-control"
data-ouia-component-id="OUIA-Generated-FormSelect-default-1"
data-ouia-component-type="PF4/FormSelect"
Expand Down
2 changes: 1 addition & 1 deletion src/components/engagement_form_fields/cloud_provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function CloudProviderFormField({
return (
<>
<FormGroup fieldId="Hosting Platform" label="Hosting Type">
<FormSelect isRequired isDisabled={true}>
<FormSelect isRequired isDisabled={true} aria-label="Hosting Type">
<FormSelectOption label={'OpenShift Container Platform'} aria-label="Hosting Platform"/>
</FormSelect>
</FormGroup>
Expand Down
1 change: 1 addition & 0 deletions src/components/launch_alert_banner/launch_alert_banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const ENGAGEMENT_FIELD_MAP = {
hosting_environments: 'oc_summary_card',
ocp_cloud_provider_name: 'oc_summary_card',
ocp_cloud_provider_region: 'oc_summary_card',
ocp_cloud_provider_availability_zone: 'oc_summary_card',
ocp_version: 'oc_summary_card',
ocp_sub_domain: 'oc_summary_card',
ocp_persistent_storage_size: { hash: 'oc_summary_card' },
Expand Down
27 changes: 4 additions & 23 deletions src/context/engagement_context/engagement_context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -225,33 +225,14 @@ export const EngagementProvider = ({
);

const getEngagement = useCallback(
async (customerName?: string, projectName?: string, uuid?: string) => {
if (!(customerName && projectName) && !uuid) {
async (uuid: string) => {
if (!uuid) {
throw new Error(
'Either projectName and customerName or uuid must not be empty'
'UUID must not be empty'
);
}
try {
let availableEngagements = [];
let cachedEngagement = availableEngagements?.find(
engagement =>
engagement?.customer_name === customerName &&
engagement?.project_name === projectName
);
if (cachedEngagement !== null) {
setCurrentEngagement(cachedEngagement);
}
let fetchedEngagement: Engagement;
if (!!uuid) {
fetchedEngagement = await engagementService.getEngagementById(uuid);
} else {
//This is probably not used anymore. Check backend logs for "Deprecated get method used"
//Delete this and engagementService.getEngagementByCustomerAndProjectName if none by 03/17/2022
fetchedEngagement = await engagementService.getEngagementByCustomerAndProjectName(
customerName,
projectName
);
}
let fetchedEngagement: Engagement = await engagementService.getEngagementById(uuid);
setCurrentEngagement(fetchedEngagement);
return fetchedEngagement;
} catch (e) {
Expand Down
11 changes: 4 additions & 7 deletions src/context/engagement_context/engagement_hook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,24 @@ export interface EngagementHookUuid {
uuid: string;
}
export interface EngagementHookProjectCustomerName {
projectName?: string;
customerName?: string;
uuid?: string;
}
export const useEngagement = (
params: EngagementHookProjectCustomerName = {}
) => {
const engagementContext = useContext(EngagementContext);
const { getEngagement, setCurrentEngagement } = engagementContext;
const { customerName, projectName, uuid } = params;
const { uuid } = params;
useEffect(() => {
if (!(!!customerName && !!projectName) && !uuid) {
if (!uuid) {
return;
}
getEngagement(customerName, projectName, uuid).then(engagement => {
getEngagement(uuid).then(engagement => {
if (engagement) {
setCurrentEngagement(engagement);
} else {
}
});
}, [customerName, projectName, getEngagement, setCurrentEngagement, uuid]);
}, [getEngagement, setCurrentEngagement, uuid]);

return engagementContext;
};
21 changes: 0 additions & 21 deletions src/packages/api_v1_sdk/apiv1_engagement_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,25 +258,4 @@ export class Apiv1EngagementService implements EngagementService {
}
}
}

async getEngagementByCustomerAndProjectName(
customer_name: string,
project_name: string
): Promise<Engagement> {
try {
const { data } = await this.axios.get(
`/engagements/customers/${customer_name}/projects/${project_name}`
);
const deserializedEngagement = Apiv1EngagementService.engagementSerializer.deserialize(
data
);
return deserializedEngagement;
} catch (e) {
if (e.isAxiosError) {
handleAxiosResponseErrors(e);
} else {
throw e;
}
}
}
}
2 changes: 1 addition & 1 deletion src/packages/api_v1_sdk/apiv1_version_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getApiV1HttpClient } from './client';
export class Apiv1VersionService implements VersionService {
private static versionSerializer = new VersionJsonSerializer();
private get axios() {
return getApiV1HttpClient();
return getApiV1HttpClient(false);
}

async fetchVersion(): Promise<AppVersion> {
Expand Down
6 changes: 4 additions & 2 deletions src/packages/api_v1_sdk/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import { ApiV1 } from './apiv1';
import { Token } from './token';

export function getApiV1HttpClient(): AxiosInstance {
export function getApiV1HttpClient(useAuth = true): AxiosInstance {
ApiV1.validateConfig();
const client = axios.create({ baseURL: ApiV1.config.backendUrl });
client.interceptors.request.use((request: AxiosRequestConfig) => {
request.headers.Authorization = `Bearer ${Token.token?.accessToken}`;
if(useAuth) {
request.headers.Authorization = `Bearer ${Token.token?.accessToken}`;
}
return request;
});
client.interceptors.response.use(
Expand Down
1 change: 1 addition & 0 deletions src/routes/create_new_engagement/create_new_engagement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export function CreateNewEngagementForm() {
ocp_persistent_storage_size:
hosting_env.ocp_persistent_storage_size,
ocp_version: hosting_env.ocp_version,
ocp_cloud_provider_availability_zone: hosting_env.ocp_cloud_provider_availability_zone,
};
}
),
Expand Down
9 changes: 0 additions & 9 deletions src/routes/dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import { useEngagementFormConfig } from '../../context/engagement_config_context
import { useHistory, useLocation } from 'react-router';
import { useServiceProviders } from '../../context/service_provider_context/service_provider_context';
import { useSummaryCount } from '../../hooks/use_summary_count';
import { useVersion } from '../../context/version_context/version_context';
import { withArtifacts } from '../../hocs/with_artifacts';
import { withUseCases } from '../../hocs/with_use_cases';

Expand All @@ -52,14 +51,6 @@ export interface DashboardFilter {
}

export function Dashboard() {
const versionContext = useVersion();

useEffect(() => {
if (!versionContext.versions) {
versionContext?.fetchVersions();
}
}, [versionContext]);

const history = useHistory();
const location = useLocation();

Expand Down
Loading

0 comments on commit 31d647c

Please sign in to comment.