Skip to content

Commit

Permalink
Do not render create page if CRD model is missing
Browse files Browse the repository at this point in the history
  • Loading branch information
rawagner committed Aug 3, 2021
1 parent 10788fd commit 2198228
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
"The console plugin provided by this operator will be disabled and removed._plural": "The console plugins provided by this operator will be disabled and removed.",
"Message from Operator developer": "Message from Operator developer",
"Uninstall": "Uninstall",
"The server doesn't have a resource type {{kind}}. Try refreshing the page if it was recently added.": "The server doesn't have a resource type {{kind}}. Try refreshing the page if it was recently added.",
"Create by completing the form. Default values may be provided by the Operator authors.": "Create by completing the form. Default values may be provided by the Operator authors.",
"Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.": "Create by manually entering YAML or JSON definitions, or by dragging and dropping a file into the editor.",
"Create {{item}}": "Create {{item}}",
Expand All @@ -185,7 +186,6 @@
"No provided APIs defined": "No provided APIs defined",
"This application was not properly installed or configured.": "This application was not properly installed or configured.",
"Create new": "Create new",
"The server doesn't have a resource type {{kind}}. Try refreshing the page if it was recently added.": "The server doesn't have a resource type {{kind}}. Try refreshing the page if it was recently added.",
"{{kind}} overview": "{{kind}} overview",
"The Operator Lifecycle Manager will not watch this Namespace because it is not configured with an OperatorGroup.": "The Operator Lifecycle Manager will not watch this Namespace because it is not configured with an OperatorGroup.",
"Create one here.": "Create one here.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
resourceObjPath,
KebabAction,
openshiftHelpBase,
Page,
} from '@console/internal/components/utils';
import { getBreadcrumbPath } from '@console/internal/components/utils/breadcrumbs';
import {
Expand Down Expand Up @@ -107,7 +108,7 @@ import {
upgradeRequiresApproval,
} from '../utils';
import { createUninstallOperatorModal } from './modals/uninstall-operator-modal';
import { ProvidedAPIsPage, ProvidedAPIPage } from './operand';
import { ProvidedAPIsPage, ProvidedAPIPage, ProvidedAPIPageProps } from './operand';
import { operatorGroupFor, operatorNamespaceFor } from './operator-group';
import { CreateInitializationResourceButton } from './operator-install-page';
import {
Expand Down Expand Up @@ -1251,7 +1252,7 @@ export const ClusterServiceVersionsDetailsPage: React.FC<ClusterServiceVersionsD
},
]
: []),
...providedAPIs.map((api: CRDDescription) => ({
...providedAPIs.map<Page<ProvidedAPIPageProps>>((api: CRDDescription) => ({
href: referenceForProvidedAPI(api),
name: ['Details', 'YAML', 'Subscription', 'Events'].includes(api.displayName)
? `${api.displayName} Operand`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { ErrorPage404 } from '@console/internal/components/error';
import { LoadingBox } from '@console/internal/components/utils';
import { GroupVersionKind, kindForReference } from '@console/internal/module/k8s';
import { useK8sModel } from '@console/shared/src/hooks/useK8sModel';

type ModelStatusBoxProps = {
groupVersionKind: GroupVersionKind;
};

const ModelStatusBox: React.FC<ModelStatusBoxProps> = ({ groupVersionKind, children }) => {
const { t } = useTranslation();
const [model, modelsLoading] = useK8sModel(groupVersionKind);
return modelsLoading ? (
<LoadingBox />
) : model ? (
<>{children}</>
) : (
<ErrorPage404
message={t(
"olm~The server doesn't have a resource type {{kind}}. Try refreshing the page if it was recently added.",
{ kind: kindForReference(groupVersionKind) },
)}
/>
);
};

export default ModelStatusBox;
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { useK8sModel } from '@console/shared/src/hooks/useK8sModel';
import { exampleForModel, providedAPIForModel } from '..';
import { ClusterServiceVersionModel } from '../../models';
import { ClusterServiceVersionKind, ProvidedAPI } from '../../types';
import ModelStatusBox from '../model-status-box';
import { DEFAULT_K8S_SCHEMA } from './const';
// eslint-disable-next-line @typescript-eslint/camelcase
import { DEPRECATED_CreateOperandForm } from './DEPRECATED_operand-form';
Expand Down Expand Up @@ -168,40 +169,42 @@ const CreateOperandPage: React.FC<CreateOperandPageProps> = ({ match }) => {
<Helmet>
<title>{t('olm~Create {{item}}', { item: kindForReference(match.params.plural) })}</title>
</Helmet>
{loaded && !_.isEmpty(csv) && model && (
<div className="co-create-operand__breadcrumbs">
<BreadCrumbs
breadcrumbs={[
{
name: csv.spec.displayName,
path: resourcePathFromModel(
ClusterServiceVersionModel,
csv.metadata.name,
csv.metadata.namespace,
),
},
{
name: t('olm~Create {{item}}', { item: model.label }),
path: window.location.pathname,
},
]}
<ModelStatusBox groupVersionKind={match.params.plural}>
{loaded && !_.isEmpty(csv) && (
<div className="co-create-operand__breadcrumbs">
<BreadCrumbs
breadcrumbs={[
{
name: csv.spec.displayName,
path: resourcePathFromModel(
ClusterServiceVersionModel,
csv.metadata.name,
csv.metadata.namespace,
),
},
{
name: t('olm~Create {{item}}', { item: model?.label }),
path: window.location.pathname,
},
]}
/>
</div>
)}
{createResourceExtension ? (
<AsyncComponent
loader={createResourceExtension.properties.component}
namespace={match.params.ns}
/>
</div>
)}
{createResourceExtension ? (
<AsyncComponent
loader={createResourceExtension.properties.component}
namespace={match.params.ns}
/>
) : (
<CreateOperand
match={match}
initialEditorType={EditorType.Form}
csv={csv}
loaded={loaded}
loadError={loadError}
/>
)}
) : (
<CreateOperand
match={match}
initialEditorType={EditorType.Form}
csv={csv}
loaded={loaded}
loadError={loadError}
/>
)}
</ModelStatusBox>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ import {
OperandStatusProps,
} from '.';

const readonlyModel = _.cloneDeep(testModel);
readonlyModel.verbs = ['get'];
readonlyModel.kind = 'TestResourceRO';

jest.mock('react-i18next', () => {
const reactI18next = require.requireActual('react-i18next');
return {
Expand Down Expand Up @@ -74,19 +78,8 @@ jest.mock('@console/shared/src/hooks/useK8sModels', () => ({
}));

jest.mock('@console/shared/src/hooks/useK8sModel', () => ({
useK8sModel: () => [
{
abbr: 'TR',
apiGroup: 'testapp.coreos.com',
apiVersion: 'v1alpha1',
crd: true,
kind: 'TestResource',
label: 'Test Resource',
labelPlural: 'Test Resources',
namespaced: true,
plural: 'testresources',
verbs: ['create'],
},
useK8sModel: (groupVersionKind) => [
groupVersionKind === readonlyModel.kind ? readonlyModel : testModel,
false,
null,
],
Expand Down Expand Up @@ -588,13 +581,11 @@ describe(ProvidedAPIPage.displayName, () => {
let wrapper: ShallowWrapper<ProvidedAPIPageProps>;

it('does not allow creation if "create" not included in the verbs for the model', () => {
const readonlyModel = _.cloneDeep(testModel);
readonlyModel.verbs = ['get'];
wrapper = shallow(
<ProvidedAPIPage.WrappedComponent
kindObj={readonlyModel}
<ProvidedAPIPage
kind={k8sModels.referenceForModel(readonlyModel)}
csv={testClusterServiceVersion}
namespace="foo"
/>,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
Kebab,
KebabAction,
LabelList,
LoadingBox,
MsgBox,
ResourceKebab,
ResourceSummary,
Expand Down Expand Up @@ -69,6 +68,7 @@ import { DescriptorType, StatusCapability, StatusDescriptor } from '../descripto
import { isMainStatusDescriptor } from '../descriptors/utils';
import { providedAPIsForCSV, referenceForProvidedAPI } from '../index';
import { Resources } from '../k8s-resource';
import ModelStatusBox from '../model-status-box';
import { csvNameFromWindow, OperandLink } from './operand-link';

export const getOperandActions = (
Expand Down Expand Up @@ -426,34 +426,24 @@ export const ProvidedAPIsPage = (props: ProvidedAPIsPageProps) => {
);
};

export const ProvidedAPIPage = connectToModel((props: ProvidedAPIPageProps) => {
const { t } = useTranslation();
const { namespace, kind, kindsInFlight, kindObj, csv } = props;
if (!kindObj) {
return kindsInFlight ? (
<LoadingBox />
) : (
<ErrorPage404
message={t(
"olm~The server doesn't have a resource type {{kind}}. Try refreshing the page if it was recently added.",
{ kind: kindForReference(kind) },
)}
/>
);
}

export const ProvidedAPIPage: React.FC<ProvidedAPIPageProps> = (props) => {
const { namespace, kind, csv } = props;
const to = `/k8s/ns/${csv.metadata.namespace}/${ClusterServiceVersionModel.plural}/${csv.metadata.name}/${kind}/~new`;

const [model] = useK8sModel(kind);
return (
<ListPage
kind={kind}
ListComponent={OperandList}
canCreate={kindObj?.verbs?.includes('create')}
createProps={{ to }}
namespace={kindObj.namespaced ? namespace : null}
badge={getBadgeFromType(kindObj.badge)}
/>
<ModelStatusBox groupVersionKind={kind}>
<ListPage
kind={kind}
ListComponent={OperandList}
canCreate={model?.verbs?.includes('create')}
createProps={{ to }}
namespace={model?.namespaced ? namespace : null}
badge={getBadgeFromType(model?.badge)}
/>
</ModelStatusBox>
);
});
};

const OperandDetailsSection: React.FC = ({ children }) => (
<div className="co-operand-details__section co-operand-details__section--info">{children}</div>
Expand Down Expand Up @@ -707,9 +697,7 @@ export type ProvidedAPIsPageProps = {

export type ProvidedAPIPageProps = {
csv: ClusterServiceVersionKind;
kindsInFlight?: boolean;
kind: GroupVersionKind;
kindObj: K8sKind;
namespace: string;
};

Expand Down
6 changes: 3 additions & 3 deletions frontend/public/components/utils/horizontal-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ export class PodsComponent extends React.PureComponent<PodsComponentProps> {
}
}

export type Page = {
export type Page<D = any> = {
href?: string;
path?: string;
name?: string;
nameKey?: string;
component?: React.ComponentType<PageComponentProps>;
component?: React.ComponentType<PageComponentProps & D>;
badge?: React.ReactNode;
pageData?: any;
pageData?: D;
};

type NavFactory = { [name: string]: (c?: React.ComponentType<any>) => Page };
Expand Down

0 comments on commit 2198228

Please sign in to comment.