Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: render bindings in relevant sections #259

Merged
merged 16 commits into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions library/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export const ONE_OF_FOLLOWING_MESSAGES_SUBSCRIBE_TEXT =
'You can subscribe to one of the following messages:';
export const ONE_OF_FOLLOWING_MESSAGES_SUBSCRIBE_SINGLE_TEXT =
'You can subscribe to the following message:';
export const RAW_MESSAGE_SUBSCRIBE_TEXT =
'You can subscribe to the following message:';
export const RAW_MESSAGE_PUBLISH_TEXT = 'You can send the following message:';

export const CONTACT_TEXT = 'Contact';
export const NAM_TEXTE = 'Name';
Expand Down Expand Up @@ -55,6 +58,13 @@ export const MESSAGE_PAYLOAD_TEXT = 'Message Payload';
export const PAYLOAD_EXAMPLE_TEXT = 'Example of payload';
export const SCHEMA_EXAMPLE_TEXT = 'Example';

export const SERVER_BINDINGS_TEXT = 'Server Bindings';
export const CHANNEL_BINDINGS_TEXT = 'Channel Bindings';
export const OPERATION_BINDINGS_TEXT = 'Operation Bindings';
export const MESSAGE_BINDINGS_TEXT = 'Message Bindings';

export const BINDINGS_SCHEMA_OBJECT_TEXT = 'Schema Object';

export const NONE_TEXT = 'None';
export const ANY_TEXT = 'Any';
export const ERROR_TEXT = 'Error';
Expand Down
45 changes: 45 additions & 0 deletions library/src/containers/Bindings/Binding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';

import { bemClasses } from '../../helpers';

import { BindingFieldComponent } from './BindingField';

const className = `binding`;
interface Props {
name: string;
binding: any;
}

export const BindingComponent: React.FunctionComponent<Props> = ({
name,
binding,
}) => {
if (!binding) {
return null;
}

return (
<section>
<div>
<div className="flex py-2">
<div
className={bemClasses.concatenate([
bemClasses.element(`${className}-protocol`),
bemClasses.element(`badge`),
])}
>
{name}
</div>
</div>
</div>
{Object.entries(binding).map(([key, value]) => (
<BindingFieldComponent
value={value}
context={key}
bindingType={name}
key={key}
/>
))}
</section>
);
};
78 changes: 78 additions & 0 deletions library/src/containers/Bindings/BindingField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React from 'react';

import { bemClasses, bindingsHelper } from '../../helpers';
import { SchemaComponent } from '../Schemas/Schema';
import { BINDINGS_SCHEMA_OBJECT_TEXT } from '../../constants';

const className = `binding-field`;
interface Props {
value: any;
context: string;
bindingType: string;
}

export const BindingFieldComponent: React.FunctionComponent<Props> = ({
value,
context,
bindingType,
}) => {
if (value === null || value === undefined) {
return null;
}

// three cases - simple value (need to render boolean correctly), nested object or SchemaObject
const isObject: boolean = bindingsHelper.isObject(value);
const isSchemaObject: boolean = bindingsHelper.isSchemaObject(
context,
bindingType,
);

if (isSchemaObject) {
return (
<>
<div className="flex py-2">
<div className="flex-1">
<div className={bemClasses.element(`${className}-name`)}>
{context}
</div>
</div>
<div className="flex-1">{BINDINGS_SCHEMA_OBJECT_TEXT}</div>
</div>
<div className={bemClasses.element(`${className}-schema`)}>
<SchemaComponent name={context} schema={value} hideTitle={true} />
</div>
</>
);
}

if (isObject) {
return (
<>
{Object.entries(value).map(([key, val]) => (
<BindingFieldComponent
value={val}
context={`${context}.${key}`}
bindingType={bindingType}
key={key}
/>
))}
</>
);
}

// simple value is the default return
return (
<div>
<div className="flex py-2">
<div className="flex-1">
<div className={bemClasses.element(`${className}-name`)}>
{context}
</div>
</div>
<div className="flex-1">
{typeof value === 'boolean' ? JSON.stringify(value) : value}
</div>
</div>
</div>
);
};
37 changes: 37 additions & 0 deletions library/src/containers/Bindings/Bindings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';

import { bemClasses } from '../../helpers';
import { BaseBindings } from '../../types';
import { BindingComponent } from './Binding';

const className = `bindings`;
interface Props {
bindings?: BaseBindings;
title?: string;
}

export const BindingsComponent: React.FunctionComponent<Props> = ({
bindings,
title,
}) => {
if (!bindings || Object.keys(bindings).length === 0) {
return null;
}
const content = (
<div className={`${bemClasses.element(`${className}-table`)} p-4`}>
{Object.entries(bindings).map(([name, binding]) => (
<BindingComponent name={name} binding={binding} key={name} />
))}
</div>
);
return (
<section className={bemClasses.element(className)}>
<div className={bemClasses.element(`${className}-header`)}>
<h4>{title}</h4>
<div className={bemClasses.element(`${className}-description`)}>
{content}
</div>
</div>
</section>
);
};
34 changes: 13 additions & 21 deletions library/src/containers/Channels/Channel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import React from 'react';

import { OperationComponent } from './Operation';
import { Parameters as ParametersComponent } from './Parameters';
import { BindingsComponent } from '../Bindings/Bindings';

import { Badge, BadgeType, Markdown, Toggle } from '../../components';
import { bemClasses, removeSpecialChars } from '../../helpers';
import { MESSAGE_TEXT, ITEM_LABELS, CONTAINER_LABELS } from '../../constants';
import { Channel, RawMessage, isRawMessage, PayloadType } from '../../types';
import {
ITEM_LABELS,
CONTAINER_LABELS,
CHANNEL_BINDINGS_TEXT,
} from '../../constants';
import { Channel, isRawMessage, PayloadType } from '../../types';

interface Props {
name: string;
Expand All @@ -26,10 +31,6 @@ export const ChannelComponent: React.FunctionComponent<Props> = ({
removeSpecialChars(name),
]);

const message =
(channel.publish && channel.publish.message) ||
(channel.subscribe && channel.subscribe.message);

const oneOfPublish =
channel.publish &&
channel.publish.message &&
Expand All @@ -40,8 +41,6 @@ export const ChannelComponent: React.FunctionComponent<Props> = ({
channel.subscribe.message &&
!isRawMessage(channel.subscribe.message);

const oneOfExists = Boolean(oneOfPublish || oneOfSubscribe);

const header = (
<h3>
<ul className={bemClasses.element(`${className}-header-badges`)}>
Expand Down Expand Up @@ -95,20 +94,13 @@ export const ChannelComponent: React.FunctionComponent<Props> = ({
'parameters',
])}
/>
{channel.bindings && (
<BindingsComponent
bindings={channel.bindings}
title={CHANNEL_BINDINGS_TEXT}
/>
)}
<div className={bemClasses.element(`${className}-operations`)}>
{oneOfExists ? null : (
<header
className={bemClasses.element(`${className}-operations-header`)}
>
<h4>
<span>
{(message as RawMessage)?.title ||
(message as RawMessage)?.name ||
MESSAGE_TEXT}
</span>
</h4>
</header>
)}
<ul className={bemClasses.element(`${className}-operations-list`)}>
{channel.subscribe && (
<li
Expand Down
44 changes: 43 additions & 1 deletion library/src/containers/Channels/Operation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import React from 'react';

import { MessagesComponent } from '../Messages/Messages';
import { MessageComponent } from '../Messages/Message';
import { BindingsComponent } from '../Bindings/Bindings';

import { bemClasses } from '../../helpers';
import { Badge, BadgeType, Markdown } from '../../components';
import { Operation, PayloadType, Message, isRawMessage } from '../../types';
import {
ONE_OF_FOLLOWING_MESSAGES_PUBLISH_TEXT,
ONE_OF_FOLLOWING_MESSAGES_SUBSCRIBE_TEXT,
RAW_MESSAGE_PUBLISH_TEXT,
RAW_MESSAGE_SUBSCRIBE_TEXT,
OPERATION_BINDINGS_TEXT,
} from '../../constants';

interface Props {
Expand Down Expand Up @@ -72,23 +76,61 @@ export const OperationComponent: React.FunctionComponent<Props> = ({
</span>
</h4>
</header>
{operation.summary && (
<div className={bemClasses.element(`${className}-description`)}>
<Markdown>{operation.summary}</Markdown>
</div>
)}
{operation.description && (
<div className={bemClasses.element(`${className}-description`)}>
<Markdown>{operation.description}</Markdown>
</div>
)}
{operation.bindings && (
<BindingsComponent
bindings={operation.bindings}
title={OPERATION_BINDINGS_TEXT}
/>
)}
<MessagesComponent messages={messages} inChannel={true} />
</section>
);
}

const operationTitle = operation.summary
? operation.summary
: payloadType === PayloadType.PUBLISH
? RAW_MESSAGE_PUBLISH_TEXT
: RAW_MESSAGE_SUBSCRIBE_TEXT;

return (
<section className={bemClasses.element(className)}>
<section className={bemClasses.element(`${className}-message`)}>
<header className={bemClasses.element(`${className}-message-header`)}>
<h4>
{isPublish && isSubscribe ? (
<Badge
type={
payloadType === PayloadType.PUBLISH
? BadgeType.PUBLISH
: BadgeType.SUBSCRIBE
}
/>
) : null}
{operationTitle}
</h4>
</header>

{operation.description && (
<div className={bemClasses.element(`${className}-description`)}>
<Markdown>{operation.description}</Markdown>
</div>
)}
{operation.bindings && (
<BindingsComponent
bindings={operation.bindings}
title={OPERATION_BINDINGS_TEXT}
/>
)}
<MessageComponent message={operation.message} inChannel={true} />
</section>
);
Expand Down
Loading