Skip to content

Commit

Permalink
Merge pull request openshift#12686 from Lucifergene/ODC-7274-prepare-…
Browse files Browse the repository at this point in the history
…a-page-and-modal-to-invoke-a-serverless-function

ODC-7274: Prepare a page and modal to invoke a Serverless function
  • Loading branch information
openshift-merge-robot authored Apr 5, 2023
2 parents 59fd0b1 + 4437717 commit 1539a8b
Show file tree
Hide file tree
Showing 25 changed files with 923 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ export type SelfSubjectAccessReviewKind = {

export type YAMLEditorProps = {
value?: string;
language?: string;
options?: object;
minHeight?: string | number;
showShortcuts?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const YAMLEditor = React.forwardRef<MonacoEditor, YAMLEditorProps>((props, ref)
minHeight,
onChange,
onSave,
language,
} = props;

const [usesValue] = React.useState<boolean>(value !== undefined);
Expand All @@ -40,7 +41,7 @@ const YAMLEditor = React.forwardRef<MonacoEditor, YAMLEditorProps>((props, ref)
<div className="ocs-yaml-editor__wrapper">
<MonacoEditor
ref={ref}
language="yaml"
language={language ?? 'yaml'}
theme="console"
height={contentRect.bounds.height}
width={contentRect.bounds.width}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ const YAMLEditorField: React.FC<YAMLEditorFieldProps> = ({
model,
schema,
showSamples,
showShortcuts,
minHeight,
onSave,
language,
}) => {
const [field] = useField(name);
const { setFieldValue } = useFormikContext<FormikValues>();
Expand Down Expand Up @@ -82,10 +85,11 @@ const YAMLEditorField: React.FC<YAMLEditorFieldProps> = ({
loader={() => import('../editor/YAMLEditor').then((c) => c.default)}
forwardRef={editorRef}
value={field.value}
minHeight="200px"
minHeight={minHeight ?? '200px'}
onChange={(yaml: string) => setFieldValue(name, yaml)}
onSave={onSave}
showShortcuts
showShortcuts={showShortcuts}
language={language}
toolbarLinks={
!sidebarOpen &&
hasSidebarContent && [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,11 @@ export interface MultiColumnFieldProps extends FieldProps {

export interface YAMLEditorFieldProps extends FieldProps {
model?: K8sKind;
minHeight?: string;
language?: string;
schema?: JSONSchema7;
showSamples: boolean;
showShortcuts?: boolean;
onSave?: () => void;
}

Expand Down
16 changes: 16 additions & 0 deletions frontend/packages/knative-plugin/locales/en/knative-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"Move sink": "Move sink",
"Delete Revision": "Delete Revision",
"Edit URI": "Edit URI",
"Test Serverless Function": "Test Serverless Function",
"Make Serverless": "Make Serverless",
"A KafkaSink takes a CloudEvent, and sends it to an Apache Kafka Topic. Events can be specified in either Structured or Binary mode.": "A KafkaSink takes a CloudEvent, and sends it to an Apache Kafka Topic. Events can be specified in either Structured or Binary mode.",
"Supported": "Supported",
Expand Down Expand Up @@ -244,6 +245,21 @@
"Select a sink": "Select a sink",
"Save": "Save",
"Editing this URI will affect all associated Event Sources.": "Editing this URI will affect all associated Event Sources.",
"Request": "Request",
"Response": "Response",
"Body": "Body",
"Options": "Options",
"Info": "Info",
"CloudEvent": "CloudEvent",
"HTTP": "HTTP",
"Format": "Format",
"Content-Type": "Content-Type",
"Add headers": "Add headers",
"Add optional headers": "Add optional headers",
"Status": "Status",
"Response Header": "Response Header",
"Invoke": "Invoke",
"Invokes the function by sending a test request to the currently running function instance": "Invokes the function by sending a test request to the currently running function instance",
"Add Revision": "Add Revision",
"Split": "Split",
"Tag": "Tag",
Expand Down
11 changes: 11 additions & 0 deletions frontend/packages/knative-plugin/src/actions/creators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
setTrafficDistributionModal,
editSinkUriModal,
setSinkSourceModal,
testServerlessFunctionModal,
} from '../components/modals';
import { addPubSubConnectionModal } from '../components/pub-sub/PubSubModalLauncher';
import { EventingSubscriptionModel, EventingTriggerModel } from '../models';
Expand Down Expand Up @@ -151,3 +152,13 @@ export const editSinkUri = (
verb: 'update',
},
});

export const testServerlessFunction = (model: K8sKind, obj: K8sResourceKind): Action => ({
id: 'test-serverless-function',
label: i18next.t('knative-plugin~Test Serverless Function'),
cta: () =>
testServerlessFunctionModal({
obj,
}),
insertBefore: 'create-service-binding',
});
11 changes: 11 additions & 0 deletions frontend/packages/knative-plugin/src/actions/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
EVENT_SINK_CATALOG_TYPE_ID,
EVENT_SOURCE_ACTION_ID,
EVENT_SOURCE_CATALOG_TYPE_ID,
KNATIVE_SERVERLESS_FUNCTION_TEST,
} from '../const';
import { RevisionModel, EventingBrokerModel, ServiceModel } from '../models';
import {
Expand Down Expand Up @@ -63,6 +64,7 @@ import {
editKnativeService,
setTrafficDistribution,
moveSinkSource,
testServerlessFunction,
} from './creators';
import { hideKnatifyAction, MakeServerless } from './knatify';

Expand All @@ -86,6 +88,11 @@ export const useSinkPubSubActionProvider = (resource: K8sResourceKind) => {
};

export const useKnativeServiceActionsProvider = (resource: K8sResourceKind) => {
/* For testing purpose only */
if (localStorage.getItem(KNATIVE_SERVERLESS_FUNCTION_TEST) === null) {
localStorage.setItem(KNATIVE_SERVERLESS_FUNCTION_TEST, 'false');
}

const [kindObj, inFlight] = useK8sModel(referenceFor(resource));
const actions = React.useMemo(() => {
return [
Expand All @@ -99,6 +106,10 @@ export const useKnativeServiceActionsProvider = (resource: K8sResourceKind) => {
...(resource.metadata.annotations?.['openshift.io/generated-by'] === 'OpenShiftWebConsole'
? [DeleteResourceAction(kindObj, resource)]
: [CommonActionFactory.Delete(kindObj, resource)]),
...(resource?.metadata?.labels?.['function.knative.dev'] === 'true' &&
localStorage.getItem(KNATIVE_SERVERLESS_FUNCTION_TEST) === 'true'
? [testServerlessFunction(kindObj, resource)]
: []),
];
}, [kindObj, resource]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ export const editSinkUriModal = (props) =>
import('../sink-uri/SinkUriController' /* webpackChunkName: "sink-uri" */).then((m) =>
m.sinkModalLauncher(props),
);

export const testServerlessFunctionModal = (props) =>
import(
'../test-function/TestFunctionController' /* webpackChunkName: "test-serverless-function" */
).then((m) => m.testFunctionModalLauncher(props));
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import * as React from 'react';
import { Formik, FormikValues, FormikHelpers } from 'formik';
import { ServiceKind } from '../../types';
import TestFunctionModal from './TestFunctionModal';
import { InvokeFormat } from './types';

export interface TestFunctionProps {
service: ServiceKind;
cancel?: () => void;
close?: () => void;
}

export type TestFunctionFormikValues = {
request: {
format: InvokeFormat;
contentType: string;
type: string;
source: string;
customHeaders: string[][];
body: {
data: string;
};
};
response: {
url: string;
status: string;
statusCode: number;
headers: Record<string, string[]>;
body: string;
};
endpoint: {
url: URL | string;
};
};

const TestFunction: React.FC<TestFunctionProps> = ({ service, cancel, close }) => {
const initialValues: TestFunctionFormikValues = {
request: {
format: InvokeFormat.CloudEvent,
contentType: 'application/json',
type: '',
source: '',
customHeaders: [[]],
body: {
data: '{"message": "Hello World!"}',
},
},
response: {
url: '',
status: '',
statusCode: 0,
headers: {
'content-type': ['application/json'],
'ce-type': ['boson.fn'],
'ce-source': ['/boson/fn'],
'ce-hello': ['World', 'sds'],
'ce-lorem': ['Ipsum'],
},
body: '{"message": "Response Data!"}',
},
endpoint: {
url: '',
},
};

const handleSubmit = (values: FormikValues, action: FormikHelpers<FormikValues>) => {
// eslint-disable-next-line no-console
console.log('!!!Invoking Function!!!');
action.setStatus({ error: '' });
};
return (
<Formik
initialValues={initialValues}
onSubmit={handleSubmit}
onReset={cancel}
initialStatus={{ error: '' }}
>
{(formikProps) => (
<TestFunctionModal {...formikProps} cancel={cancel} service={service} close={close} />
)}
</Formik>
);
};
export default TestFunction;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from 'react';
import { createModalLauncher, ModalComponentProps } from '@console/internal/components/factory';
import { Firehose } from '@console/internal/components/utils';
import { ServiceModel } from '../../models';
import { ServiceKind } from '../../types';
import TestFunction from './TestFunction';

type ControllerProps = {
loaded?: boolean;
obj: ServiceKind;
};

const Controller: React.FC<ControllerProps> = (props) => {
const { loaded, obj } = props;
return loaded ? <TestFunction {...props} service={obj} /> : null;
};

type TestFunctionControllerProps = {
obj: ServiceKind;
};

const TestFunctionController: React.FC<TestFunctionControllerProps> = (props) => {
const { obj } = props;

const serverlessResources = [
{
kind: ServiceModel.kind,
isList: false,
prop: `obj`,
namespace: obj.metadata.namespace,
name: obj.metadata.name,
},
];

return (
<Firehose resources={serverlessResources}>
<Controller {...props} />
</Firehose>
);
};

type Props = TestFunctionControllerProps & ModalComponentProps;

export const testFunctionModalLauncher = createModalLauncher<Props>(TestFunctionController);

export default TestFunctionController;
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
@import '../../../../../public/style/vars';

.kn-test-sf-modal__size {
height: 90vh;
width: 80vw;
}

.kn-test-sf-modal {
@media (max-width: $pf-global--breakpoint--md) {
&__split {
display: none;
}
}
@media (min-width: $pf-global--breakpoint--md) {
&__tabbed {
display: none;
}
}
}

.kn-test-sf-modal__title {
padding: 0.5rem 0.5rem 1.5rem 0.5rem;

&__icon {
margin-right: 8px;
color: #0468ce;
}

&__badge {
vertical-align: 2px;
}
}

.kn-test-sf-modal__body {
padding: 0 0.5rem 0 0.5rem;

&__description {
margin-bottom: 1.25rem;
}
}

.kn-test-sf-modal__footer {
margin-right: 1rem;
margin-left: 0.5rem;
margin-bottom: 0.5rem;
}

.kn-test-sf-modal__splitItem {
max-width: 49%;
}

@media (max-width: $pf-global--breakpoint--md) {
.kn-test-sf-modal__editor {
margin-top: 1.5rem;
margin-left: 2rem;
margin-right: 2rem;
}
}

.kn-test-sf-modal-request-pane--options__size {
margin-top: 1rem;
margin-left: 1.4rem;
margin-right: 10rem;
}

.kn-test-sf-modal-request-pane--options__custom-headers {
margin-top: 3rem;
margin-right: -4rem;
}

.kn-test-sf-modal-response-pane--info__size {
margin-left: 1rem;
}

.kn-test-sf-modal-response-pane--info__status {
display: flex;
flex-direction: row;

&__label {
padding-right: 0.5rem;
padding-top: 0.2rem;
}

&__code {
font-weight: bold !important;
}
}
Loading

0 comments on commit 1539a8b

Please sign in to comment.