Skip to content

Commit

Permalink
1458 [Transactions] Edit & Delete implementation for Transactions (#1459
Browse files Browse the repository at this point in the history
)

* 1458 adding transactions edit and delete features for the transaction run page

* 1458 fixing drag & drop for transactions

* 1458 removing console log 🥴
  • Loading branch information
xoscar committed Nov 7, 2022
1 parent 1939e19 commit 7c3ac8c
Show file tree
Hide file tree
Showing 34 changed files with 627 additions and 153 deletions.
27 changes: 27 additions & 0 deletions web/src/components/EditTransaction/EditTransaction.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {Typography} from 'antd';
import styled from 'styled-components';

export const Title = styled(Typography.Title)`
&& {
font-size: ${({theme}) => theme.size.lg};
margin-bottom: 25px;
font-weight: 700;
}
`;

export const Wrapper = styled.div`
display: flex;
flex-direction: column;
height: 100%;
`;

export const FormContainer = styled.div`
padding: 24px;
`;

export const ButtonsContainer = styled.div`
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 23px;
`;
52 changes: 52 additions & 0 deletions web/src/components/EditTransaction/EditTransaction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {Button, Form} from 'antd';
import {useCallback, useState} from 'react';
import {TDraftTransaction, TTransaction} from 'types/Transaction.types';
import {useTransaction} from 'providers/Transaction/Transaction.provider';
import useValidateTransactionDraft from 'hooks/useValidateTransactionDraft';

import * as S from './EditTransaction.styled';
import EditTransactionForm from '../EditTransactionForm';

interface IProps {
transaction: TTransaction;
}

const EditTransaction = ({transaction}: IProps) => {
const [form] = Form.useForm<TDraftTransaction>();
const {onEdit, isEditLoading} = useTransaction();
const [isFormValid, setIsFormValid] = useState(true);

const onChange = useValidateTransactionDraft({setIsValid: setIsFormValid});

const handleOnSubmit = useCallback(
async (values: TDraftTransaction) => {
onEdit(values);
},
[onEdit]
);

return (
<S.Wrapper data-cy="edit-transaction-form">
<S.FormContainer>
<S.Title>Edit Transaction</S.Title>
<EditTransactionForm form={form} transaction={transaction} onSubmit={handleOnSubmit} onValidation={onChange} />
<S.ButtonsContainer>
<Button data-cy="edit-transaction-reset" onClick={() => form.resetFields()}>
Reset
</Button>
<Button
data-cy="edit-transaction-submit"
loading={isEditLoading}
disabled={!isFormValid}
type="primary"
onClick={() => form.submit()}
>
Save & Run
</Button>
</S.ButtonsContainer>
</S.FormContainer>
</S.Wrapper>
);
};

export default EditTransaction;
2 changes: 2 additions & 0 deletions web/src/components/EditTransaction/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export {default} from './EditTransaction';
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from 'styled-components';

export const FormContainer = styled.div`
display: flex;
flex-direction: column;
gap: 23px;
.ant-form-item {
margin: 0;
}
`;
37 changes: 37 additions & 0 deletions web/src/components/EditTransactionForm/EditTransactionForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {Form} from 'antd';
import {TDraftTransaction, TDraftTransactionForm, TTransaction} from 'types/Transaction.types';
import BasicDetailsForm from '../CreateTestPlugins/Default/steps/BasicDetails/BasicDetailsForm';
import TestsSelectionForm from '../TransactionPlugin/steps/TestsSelection/TestsSelectionForm';
import * as S from './EditTransactionForm.styled';

export const FORM_ID = 'edit-test';

interface IProps {
form: TDraftTransactionForm;
transaction: TTransaction;
onSubmit(values: TDraftTransaction): Promise<void>;
onValidation(allValues: any, values: TDraftTransaction): void;
}

const EditTransactionForm = ({form, onSubmit, transaction, onValidation}: IProps) => {
return (
<Form<TDraftTransaction>
autoComplete="off"
data-cy="edit-test-modal"
form={form}
layout="vertical"
name={FORM_ID}
onFinish={onSubmit}
onValuesChange={onValidation}
initialValues={transaction}
>
<S.FormContainer>
<BasicDetailsForm isEditing />

<TestsSelectionForm />
</S.FormContainer>
</Form>
);
};

export default EditTransactionForm;
2 changes: 2 additions & 0 deletions web/src/components/EditTransactionForm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export {default} from './EditTransactionForm';
9 changes: 4 additions & 5 deletions web/src/components/TransactionHeader/TransactionHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import TestCardActions from 'components/TestCard/TestCardActions';
import {noop} from 'lodash';
import {useTransaction} from 'providers/TransactionRunDetail/TransactionRunDetailProvider';
import {useTransaction} from 'providers/Transaction/Transaction.provider';
import * as S from './TransactionHeader.styled';

interface IProps {
onBack(): void;
}

const TransactionHeader = ({onBack}: IProps) => {
const {transaction} = useTransaction();
const {transaction, onDelete} = useTransaction();

return (
<S.Container>
<S.Section>
<S.BackIcon data-cy="transaction-header-back-button" onClick={onBack} />
<div>
<S.Title data-cy="transaction-details-name">
{transaction?.name} (v{transaction?.version})
{transaction?.name} ({transaction.version})
</S.Title>
<S.Text>{transaction?.description}</S.Text>
</div>
</S.Section>
<S.Section>
<TestCardActions testId={transaction?.id || ''} onDelete={noop} />
<TestCardActions testId={transaction?.id || ''} onDelete={() => onDelete(transaction.id, transaction.name)} />
</S.Section>
</S.Container>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import * as S from './TestsSelectionInput.styled';

interface IProps {
test: TTest;
sortableId: string;
onDelete(testId: string): void;
}

const TestItem = ({test, onDelete}: IProps) => {
const {attributes, listeners, setNodeRef, transform, transition} = useSortable({id: test.id});
const TestItem = ({test, onDelete, sortableId}: IProps) => {
const {attributes, listeners, setNodeRef, transform, transition} = useSortable({id: sortableId});

const style = {
transform: CSS.Transform.toString(transform),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {Col, Row} from 'antd';
import {TTest} from 'types/Test.types';
import TestItem from './TestItem';
import {ISortableTest} from './TestsSelectionInput';
import * as S from './TestsSelectionInput.styled';

interface IProps {
items: TTest[];
items: ISortableTest[];
onDelete(testId: string): void;
}

Expand All @@ -13,9 +13,8 @@ const TestItemList = ({items, onDelete}: IProps) => {
<Row gutter={12}>
<Col span={18}>
<S.ItemListContainer>
{items.map((test, index) => (
// eslint-disable-next-line react/no-array-index-key
<TestItem key={`${test.id}-${index}`} test={test} onDelete={onDelete} />
{items.map(({id, test}) => (
<TestItem key={id} test={test} sortableId={id} onDelete={onDelete} />
))}
</S.ItemListContainer>
</Col>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {closestCenter, DndContext, KeyboardSensor, PointerSensor, useSensor, use
import {arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy} from '@dnd-kit/sortable';
import {Col, Row, Select} from 'antd';
import {noop} from 'lodash';
import {useCallback, useState} from 'react';
import {useCallback, useEffect, useState} from 'react';
import {TTest} from 'types/Test.types';
import TestItemList from './TestItemList';

Expand All @@ -12,16 +12,35 @@ interface IProps {
onChange?(tests: string[]): void;
}

export interface ISortableTest {
id: string;
test: TTest;
}

const TestsSelectionInput = ({value = [], onChange = noop, testList}: IProps) => {
const [selectedTestList, setSelectedTestList] = useState<TTest[]>([]);
const [selectedTestList, setSelectedTestList] = useState<ISortableTest[]>([]);
const onSelectedTest = useCallback(
(testId: string) => {
onChange([...value, testId]);
setSelectedTestList([...selectedTestList, testList.find(test => test.id === testId)!]);
},
[onChange, selectedTestList, testList, value]
[onChange, value]
);

useEffect(() => {
if (testList.length) {
setSelectedTestList(
value.map((testId, index) => {
const test = testList.find(({id}) => id === testId)!;

return {
test,
id: `${test.id}-${index}`,
};
})
);
}
}, [testList, value]);

const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, {
Expand All @@ -37,7 +56,7 @@ const TestsSelectionInput = ({value = [], onChange = noop, testList}: IProps) =>
const updatedList = arrayMove(selectedTestList, oldIndex, newIndex);

setSelectedTestList(updatedList);
onChange(updatedList.map((test: any) => test.id));
onChange(updatedList.map(({test}) => test.id));
}
},
[onChange, selectedTestList]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import {Typography} from 'antd';
import emptyStateIcon from 'assets/SpanAssertionsEmptyState.svg';
import styled from 'styled-components';

export const TestDetailsHeader = styled.div`
display: flex;
width: 100%;
justify-content: space-between;
margin: 32px 0 24px;
`;

export const Wrapper = styled.div<{detail?: boolean}>`
display: flex;
flex-grow: 1;
flex-direction: column;
background: ${({theme}) => theme.color.white};
`;

export const EmptyStateIcon = styled.img.attrs({
src: emptyStateIcon,
})``;

export const EmptyStateContainer = styled.div`
align-items: center;
display: flex;
flex-direction: column;
gap: 14px;
justify-content: center;
margin: 100px 0;
`;

export const Container = styled.div`
display: flex;
height: 100%;
width: 100%;
`;

export const Text = styled(Typography.Title).attrs({level: 3})<{opacity?: number}>`
&& {
font-size: 12px;
color: ${({opacity}) => `rgba(3, 24, 73, ${opacity || 1})`};
margin: 0 !important;
}
`;

export const TagContainer = styled.div`
display: flex;
white-space: nowrap;
overflow: auto;
`;

export const Title = styled(Typography.Title).attrs({level: 3})`
&& {
margin: 0;
}
`;

export const Stack = styled.div`
display: flex;
justify-content: space-between;
flex-direction: column;
`;

export const Info = styled.div`
flex: 1;
`;

export const Section = styled.div`
flex: 1;
`;

export const SectionLeft = styled.div`
background-color: ${({theme}) => theme.color.white};
overflow-y: auto;
z-index: 1;
flex-basis: 50%;
`;

export const SectionRight = styled.div`
background-color: ${({theme}) => theme.color.white};
border-left: 1px solid rgba(3, 24, 73, 0.1);
overflow-y: auto;
z-index: 2;
padding: 24px;
flex-basis: 50%;
`;
33 changes: 33 additions & 0 deletions web/src/components/TransactionRunLayout/TransactionRunLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {useNavigate} from 'react-router-dom';
import TransactionHeader from 'components/TransactionHeader';
import {TTransaction, TTransactionRun} from 'types/Transaction.types';
import * as S from './TransactionRunLayout.styled';
import EditTransaction from '../EditTransaction';
import TransactionRunResult from '../TransactionRunResult/TransactionRunResult';

interface IProps {
transaction: TTransaction;
transactionRun: TTransactionRun;
}

const TransactionRunDetailLayout = ({transaction, transaction: {id: transactionId}, transactionRun}: IProps) => {
const navigate = useNavigate();

return (
<>
<TransactionHeader onBack={() => navigate(`/transaction/${transactionId}`)} />
<S.Wrapper>
<S.Container>
<S.SectionLeft>
<EditTransaction transaction={transaction} />
</S.SectionLeft>
<S.SectionRight>
<TransactionRunResult transactionRun={transactionRun} />
</S.SectionRight>
</S.Container>
</S.Wrapper>
</>
);
};

export default TransactionRunDetailLayout;
2 changes: 2 additions & 0 deletions web/src/components/TransactionRunLayout/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-restricted-exports
export {default} from './TransactionRunLayout';

0 comments on commit 7c3ac8c

Please sign in to comment.