Skip to content

Commit

Permalink
feat(frontend): indicate tabs with info in trigger (#3565)
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgeepc committed Jan 26, 2024
1 parent b8395ef commit 075bf47
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 51 deletions.
54 changes: 25 additions & 29 deletions web/src/components/TestHeader/TestHeader.tsx
@@ -1,46 +1,42 @@
import ResourceCardActions from 'components/ResourceCard/ResourceCardActions';
import {useDashboard} from 'providers/Dashboard/Dashboard.provider';
import * as S from './TestHeader.styled';
import VariableSetSelector from '../VariableSetSelector/VariableSetSelector';

interface IProps {
description: string;
id: string;
shouldEdit: boolean;
onBack(): void;
onEdit(): void;
onDelete(): void;
onDuplicate(): void;
title: string;
runButton: React.ReactNode;
}

const TestHeader = ({description, id, shouldEdit, onEdit, onDelete, onDuplicate, title, runButton}: IProps) => {
const {navigate} = useDashboard();

return (
<S.Container $isWhite>
<S.Section>
<a onClick={() => navigate(-1)} data-cy="test-header-back-button">
<S.BackIcon />
</a>
<div>
<S.Title data-cy="test-details-name">{title}</S.Title>
<S.Text>{description}</S.Text>
</div>
</S.Section>
<S.Section>
<VariableSetSelector />
{runButton}
<ResourceCardActions
id={id}
onDuplicate={onDuplicate}
onDelete={onDelete}
onEdit={onEdit}
shouldEdit={shouldEdit}
/>
</S.Section>
</S.Container>
);
};
const TestHeader = ({description, id, shouldEdit, onBack, onEdit, onDelete, onDuplicate, title, runButton}: IProps) => (
<S.Container $isWhite>
<S.Section>
<a onClick={onBack} data-cy="test-header-back-button">
<S.BackIcon />
</a>
<div>
<S.Title data-cy="test-details-name">{title}</S.Title>
<S.Text>{description}</S.Text>
</div>
</S.Section>
<S.Section>
<VariableSetSelector />
{runButton}
<ResourceCardActions
id={id}
onDuplicate={onDuplicate}
onDelete={onDelete}
onEdit={onEdit}
shouldEdit={shouldEdit}
/>
</S.Section>
</S.Container>
);

export default TestHeader;
2 changes: 2 additions & 0 deletions web/src/components/TestHeader/__tests__/TestHeader.test.tsx
Expand Up @@ -5,6 +5,7 @@ import TestHeader from '../TestHeader';
test('SpanAttributesTable', () => {
const test = TestMock.model();

const onBack = jest.fn;
const onDelete = jest.fn;
const onEdit = jest.fn;
const shouldEdit = true;
Expand All @@ -14,6 +15,7 @@ test('SpanAttributesTable', () => {
description={test.description}
id={test.id}
shouldEdit={shouldEdit}
onBack={onBack}
onEdit={onEdit}
onDelete={onDelete}
title={test.name}
Expand Down
5 changes: 0 additions & 5 deletions web/src/components/TestPlugins/FormFactory.tsx
Expand Up @@ -2,7 +2,6 @@ import Rest from 'components/TestPlugins/Forms/Rest';
import Grpc from 'components/TestPlugins/Forms/Grpc';
import Kafka from 'components/TestPlugins/Forms/Kafka';
import {TriggerTypes} from 'constants/Test.constants';
import {TDraftTestForm} from 'types/Test.types';

const FormFactoryMap = {
[TriggerTypes.http]: Rest,
Expand All @@ -13,10 +12,6 @@ const FormFactoryMap = {
[TriggerTypes.playwright]: () => null,
};

export interface IFormProps {
form: TDraftTestForm;
}

interface IProps {
type: TriggerTypes;
}
Expand Down
22 changes: 16 additions & 6 deletions web/src/components/TestPlugins/Forms/Grpc/Grpc.tsx
Expand Up @@ -4,12 +4,18 @@ import GrpcService from 'services/Triggers/Grpc.service';
import {SupportedEditors} from 'constants/Editor.constants';
import {Editor, FileUpload} from 'components/Inputs';
import {Auth, Metadata, SkipTraceCollection} from 'components/Fields';
import TriggerTab from 'components/TriggerTab';
import useQueryTabs from 'hooks/useQueryTabs';
import {TDraftTest} from 'types/Test.types';

const RequestDetailsForm = () => {
const [methodList, setMethodList] = useState<string[]>([]);
const form = Form.useFormInstance();
const form = Form.useFormInstance<TDraftTest>();
const protoFile = Form.useWatch('protoFile', form);
const authType = Form.useWatch(['auth', 'type'], form);
const message = Form.useWatch('message', form);
const metadata = Form.useWatch('metadata', form);
const skipTraceCollection = Form.useWatch('skipTraceCollection', form);

useEffect(() => {
const getMethodList = async () => {
Expand All @@ -30,7 +36,11 @@ const RequestDetailsForm = () => {

return (
<Tabs defaultActiveKey={activeKey} onChange={setActiveKey} activeKey={activeKey}>
<Tabs.TabPane forceRender tab="Service definition" key="service-definition">
<Tabs.TabPane
forceRender
tab={<TriggerTab hasContent={!!protoFile} label="Service definition" />}
key="service-definition"
>
<Form.Item data-cy="protoFile" name="protoFile" label="Upload Protobuf File">
<FileUpload />
</Form.Item>
Expand All @@ -46,11 +56,11 @@ const RequestDetailsForm = () => {
</Form.Item>
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Auth" key="auth">
<Tabs.TabPane forceRender tab={<TriggerTab hasContent={!!authType} label="Auth" />} key="auth">
<Auth />
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Message" key="message">
<Tabs.TabPane forceRender tab={<TriggerTab hasContent={!!message} label="Message" />} key="message">
<Form.Item data-cy="message" name="message" style={{marginBottom: 0}}>
<Editor
type={SupportedEditors.Interpolation}
Expand All @@ -61,11 +71,11 @@ const RequestDetailsForm = () => {
</Form.Item>
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Metadata" key="metadata">
<Tabs.TabPane forceRender tab={<TriggerTab totalItems={metadata?.length} label="Metadata" />} key="metadata">
<Metadata />
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Settings" key="settings">
<Tabs.TabPane forceRender tab={<TriggerTab hasContent={!!skipTraceCollection} label="Settings" />} key="settings">
<SkipTraceCollection />
</Tabs.TabPane>
</Tabs>
Expand Down
23 changes: 18 additions & 5 deletions web/src/components/TestPlugins/Forms/Kafka/Kafka.tsx
@@ -1,20 +1,29 @@
import {Form, Tabs} from 'antd';
import {KeyValueList, PlainAuth, SSL, SkipTraceCollection} from 'components/Fields';
import {Editor} from 'components/Inputs';
import TriggerTab from 'components/TriggerTab';
import useQueryTabs from 'hooks/useQueryTabs';
import {SupportedEditors} from 'constants/Editor.constants';
import {TDraftTest} from 'types/Test.types';
import * as S from './Kafka.styled';

const Kafka = () => {
const [activeKey, setActiveKey] = useQueryTabs('auth', 'triggerTab');
const form = Form.useFormInstance<TDraftTest>();
const authType = Form.useWatch(['authentication', 'type'], form);
const messageValue = Form.useWatch('messageValue', form);
const topic = Form.useWatch('topic', form);
const headers = Form.useWatch('headers', form);
const sslVerification = Form.useWatch('sslVerification', form);
const skipTraceCollection = Form.useWatch('skipTraceCollection', form);

return (
<Tabs defaultActiveKey={activeKey} onChange={setActiveKey} activeKey={activeKey}>
<Tabs.TabPane forceRender tab="Auth" key="auth">
<Tabs.TabPane forceRender tab={<TriggerTab hasContent={!!authType} label="Auth" />} key="auth">
<PlainAuth />
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Message" key="message">
<Tabs.TabPane forceRender tab={<TriggerTab hasContent={!!messageValue} label="Message" />} key="message">
<Form.Item label="Key" data-cy="message-key" name="messageKey">
<Editor type={SupportedEditors.Interpolation} placeholder="my-message-name" />
</Form.Item>
Expand All @@ -29,13 +38,13 @@ const Kafka = () => {
</Form.Item>
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Topic" key="topic">
<Tabs.TabPane forceRender tab={<TriggerTab hasContent={!!topic} label="Topic" />} key="topic">
<Form.Item data-cy="topic" name="topic" rules={[{required: true, message: 'Please enter a topic'}]}>
<Editor type={SupportedEditors.Interpolation} placeholder="my-topic" />
</Form.Item>
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Headers" key="headers">
<Tabs.TabPane forceRender tab={<TriggerTab totalItems={headers?.length} label="Headers" />} key="headers">
<KeyValueList
name="headers"
label=""
Expand All @@ -46,7 +55,11 @@ const Kafka = () => {
/>
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Settings" key="settings">
<Tabs.TabPane
forceRender
tab={<TriggerTab hasContent={!!sslVerification || !!skipTraceCollection} label="Settings" />}
key="settings"
>
<S.SettingsContainer>
<SSL formID="kafka" />
<SkipTraceCollection />
Expand Down
20 changes: 16 additions & 4 deletions web/src/components/TestPlugins/Forms/Rest/Rest.tsx
@@ -1,26 +1,34 @@
import {Form, Tabs} from 'antd';
import {DEFAULT_HEADERS} from 'constants/Test.constants';
import {Body} from 'components/Inputs';
import TriggerTab from 'components/TriggerTab';
import useQueryTabs from 'hooks/useQueryTabs';
import {Auth, SSL, KeyValueList, SkipTraceCollection} from 'components/Fields';
import {TDraftTest} from 'types/Test.types';
import * as S from './Rest.styled';

const Rest = () => {
const [activeKey, setActiveKey] = useQueryTabs('auth', 'triggerTab');
const form = Form.useFormInstance<TDraftTest>();
const authType = Form.useWatch(['auth', 'type'], form);
const body = Form.useWatch('body', form);
const headers = Form.useWatch('headers', form);
const sslVerification = Form.useWatch('sslVerification', form);
const skipTraceCollection = Form.useWatch('skipTraceCollection', form);

return (
<Tabs defaultActiveKey={activeKey} activeKey={activeKey} onChange={setActiveKey}>
<Tabs.TabPane forceRender tab="Auth" key="auth">
<Tabs.TabPane forceRender tab={<TriggerTab hasContent={!!authType} label="Auth" />} key="auth">
<Auth />
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Body" key="body">
<Tabs.TabPane forceRender tab={<TriggerTab hasContent={!!body} label="Body" />} key="body">
<Form.Item name="body" noStyle>
<Body />
</Form.Item>
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Headers" key="headers">
<Tabs.TabPane forceRender tab={<TriggerTab totalItems={headers?.length} label="Headers" />} key="headers">
<KeyValueList
name="headers"
label=""
Expand All @@ -31,7 +39,11 @@ const Rest = () => {
/>
</Tabs.TabPane>

<Tabs.TabPane forceRender tab="Settings" key="settings">
<Tabs.TabPane
forceRender
tab={<TriggerTab hasContent={!!sslVerification || !!skipTraceCollection} label="Settings" />}
key="settings"
>
<S.SettingsContainer>
<SSL formID="rest" />
<SkipTraceCollection />
Expand Down
12 changes: 12 additions & 0 deletions web/src/components/TriggerTab/TriggerTab.styled.ts
@@ -0,0 +1,12 @@
import {Badge as AntdBadge, Typography} from 'antd';
import styled from 'styled-components';

export const Badge = styled(AntdBadge)`
.ant-badge-status-text {
margin-left: 0;
}
`;

export const Text = styled(Typography.Text)`
color: ${({theme}) => theme.color.primary};
`;
24 changes: 24 additions & 0 deletions web/src/components/TriggerTab/TriggerTab.tsx
@@ -0,0 +1,24 @@
import {useTheme} from 'styled-components';
import * as S from './TriggerTab.styled';

interface IProps {
hasContent?: boolean;
label: string;
totalItems?: number;
}

const TriggerTab = ({hasContent, label, totalItems}: IProps) => {
const {
color: {primary},
} = useTheme();

return (
<div>
{`${label} `}
{!!totalItems && <S.Text>({totalItems})</S.Text>}
{hasContent && <S.Badge color={primary} />}
</div>
);
};

export default TriggerTab;
2 changes: 2 additions & 0 deletions web/src/components/TriggerTab/index.ts
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export {default} from './TriggerTab';
1 change: 1 addition & 0 deletions web/src/pages/Test/Content.tsx
Expand Up @@ -46,6 +46,7 @@ const Content = () => {
test.trigger.entryPoint
}`}
id={test.id}
onBack={() => navigate('/tests')}
onDelete={() => onDeleteResource(test.id, test.name, ResourceType.Test)}
onEdit={onEdit}
onDuplicate={handleOnDuplicate}
Expand Down
1 change: 1 addition & 0 deletions web/src/pages/TestSuite/Content.tsx
Expand Up @@ -45,6 +45,7 @@ const Content = () => {
<TestHeader
description={testSuite.description}
id={testSuite.id}
onBack={() => navigate('/testsuites')}
onDelete={() => onDelete(testSuite.id, testSuite.name)}
onEdit={onEdit}
onDuplicate={handleOnDuplicate}
Expand Down
2 changes: 1 addition & 1 deletion web/src/redux/Router.middleware.ts
Expand Up @@ -53,7 +53,7 @@ const RouterMiddleware = () => ({
const prevPathname = prevLocation?.pathname ?? '';

if (!prevPathname.match(runUrlRegex) && !prevPathname.includes('/create')) {
const defaultPath = currLocation?.pathname?.includes('testsuite') ? '/testsuites' : '/';
const defaultPath = currLocation?.pathname?.includes('testsuite') ? '/testsuites' : '/tests';
dispatch(runOriginPathAdded(prevLocation?.pathname ?? defaultPath));
}
},
Expand Down
2 changes: 1 addition & 1 deletion web/src/redux/slices/User.slice.ts
Expand Up @@ -4,7 +4,7 @@ import {IUserState, TUserPreferenceKey, TUserPreferenceValue} from 'types/User.t

export const initialState: IUserState = {
preferences: UserPreferencesService.get(),
runOriginPath: '/',
runOriginPath: '/tests',
};

interface ISetUserPreferencesProps {
Expand Down

0 comments on commit 075bf47

Please sign in to comment.