Skip to content

Commit

Permalink
feat(release): add bug to release
Browse files Browse the repository at this point in the history
  • Loading branch information
abhinandan13jan committed Mar 11, 2024
1 parent d0f1c31 commit 22428e7
Show file tree
Hide file tree
Showing 13 changed files with 553 additions and 190 deletions.
14 changes: 14 additions & 0 deletions config/remotePlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,19 @@ const routeExtensions = [
required: ['SIGNUP'],
},
},
{
type: 'core.page/route',
properties: {
path: '/application-pipeline/release/workspaces/:workspaceName/release-plan/trigger',
exact: true,
component: {
$codeRef: 'TriggerReleasePlan',
},
},
flags: {
required: ['SIGNUP'],
},
},
{
type: 'core.page/route',
properties: {
Expand Down Expand Up @@ -761,6 +774,7 @@ module.exports = {
CreateEnvironment: resolve(__dirname, '../src/pages/CreateEnvironmentPage'),
ReleaseListPage: resolve(__dirname, '../src/pages/ReleaseServicesListPage'),
CreateReleasePlan: resolve(__dirname, '../src/pages/CreateReleasePlanPage'),
TriggerReleasePlan: resolve(__dirname, '../src/pages/TriggerReleasePlanPage'),
EditReleasePlan: resolve(__dirname, '../src/pages/EditReleasePlanPage'),
WorkspaceContext: resolve(__dirname, '../src/utils/workspace-context-utils'),
WorkspacedPage: resolve(__dirname, '../src/pages/WorkspacedPage'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import * as React from 'react';
import {
Button,
ButtonType,
DatePicker,
Form,
InputGroup,
InputGroupItem,
ModalVariant,
Stack,
StackItem,
Text,
TextContent,
TextVariants,
} from '@patternfly/react-core';
import { Formik, useFormikContext, useField } from 'formik';
import { InputField, TextAreaField, DropdownField } from '../../../../../shared';
import { ComponentProps, createModalLauncher } from '../../../../modal/createModalLauncher';

type AddBugModalProps = ComponentProps & {
obj?: any;
bugArrayHelper: (values) => void;
};

type AddBugFormValues = {
issueKey: string;
url: string;
uploadDate: string;
status: string;
};

const dropdownItems = [
{ key: 'inProgress', value: 'In progress' },
{ key: 'closed', value: 'Closed' },
{ key: 'resolved', value: 'Resolved' },
];

type StatusDropdownProps = Omit<
React.ComponentProps<typeof DropdownField>,
'items' | 'label' | 'placeholder'
>;

export const StatusDropdown: React.FC<React.PropsWithChildren<StatusDropdownProps>> = (props) => {
const [, , { setValue }] = useField<string>(props.name);

return (
<DropdownField
{...props}
label="Release plan"
placeholder="Select status of bug"
items={dropdownItems}
onChange={(app: string) => setValue(app)}
/>
);
};

const BugFormModal = () => {
const { handleSubmit, isSubmitting } = useFormikContext<AddBugFormValues>();
const formRef = React.useRef<HTMLDivElement>();

return (
<Form>
<div ref={formRef}>
<Stack hasGutter>
<StackItem>
<TextContent>
<Text component={TextVariants.p}>
Provide information about a Bug that has already been resolved.
</Text>
</TextContent>
</StackItem>
<StackItem>
<InputField label="Bug issue key" name="issueKey" required />
</StackItem>
<StackItem>
<InputField label="URL" name="url" required />
</StackItem>
<StackItem>
<InputGroup>
<InputGroupItem>
<DatePicker appendTo={formRef.current} />
</InputGroupItem>
</InputGroup>
</StackItem>
<StackItem>
<StatusDropdown name="status" />
</StackItem>
<StackItem>
<TextAreaField name="summary" label="Summary" />
</StackItem>
<StackItem>
<Button
type={ButtonType.submit}
isLoading={isSubmitting}
data-testid="update-resource"
onClick={(e) => {
e.preventDefault(), handleSubmit();
}}
>
Add Bug
</Button>
</StackItem>
</Stack>
</div>
</Form>
);
};

export const AddBugModal: React.FC<React.PropsWithChildren<AddBugModalProps>> = ({
onClose,
bugArrayHelper,
}) => {
const setValues = React.useCallback(
(fields) => {
bugArrayHelper(fields);
onClose();
},
[onClose, bugArrayHelper],
);

return (
<Formik
onSubmit={setValues}
initialValues={{ issueKey: '', url: '', summary: '', uploadDate: '' }}
>
<BugFormModal />
</Formik>
);
};

export const createAddBugModal = createModalLauncher(AddBugModal, {
'data-testid': `trigger-release-modal`,
variant: ModalVariant.medium,
title: `Add bug modal`,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import * as React from 'react';
import {
Button,
EmptyState,
EmptyStateBody,
SearchInput,
Toolbar,
ToolbarContent,
ToolbarGroup,
ToolbarItem,
} from '@patternfly/react-core';
import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { FieldArray, useField } from 'formik';
import { debounce } from 'lodash-es';
import { useModalLauncher } from '../../../../../components/modal/ModalProvider';
import { useSearchParam } from '../../../../../hooks/useSearchParam';
import ActionMenu from '../../../../../shared/components/action-menu/ActionMenu';
import FilteredEmptyState from '../../../../../shared/components/empty-state/FilteredEmptyState';
import { createAddBugModal } from './AddBugModal';

interface AddBugSectionProps {
field: string;
}

export interface BugsObject {
issueKey: string;
summary: string;
url?: string;
last_updated?: string;
status?: string;
}

const AddBugSection: React.FC<React.PropsWithChildren<AddBugSectionProps>> = ({ field }) => {
const [nameFilter, setNameFilter] = useSearchParam('name', '');
const [{ value: issues }, ,] = useField<BugsObject[]>(field);
const showModal = useModalLauncher();

const [onLoadName, setOnLoadName] = React.useState(nameFilter);
React.useEffect(() => {
if (nameFilter) {
setOnLoadName(nameFilter);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const filteredBugs = issues?.filter(
(bug) => !nameFilter || bug.issueKey.indexOf(nameFilter) >= 0,
);

const onClearFilters = () => {
onLoadName.length && setOnLoadName('');
setNameFilter('');
};
const onNameInput = debounce((n: string) => {
n.length === 0 && onLoadName.length && setOnLoadName('');

setNameFilter(n);
}, 600);

const EmptyMsg = () =>
nameFilter ? (
<FilteredEmptyState onClearFilters={onClearFilters} />
) : (
<EmptyState>
<EmptyStateBody>No Bugs found</EmptyStateBody>
</EmptyState>
);

return (
<FieldArray
name="issues"
render={(arrayHelper) => {
const addNewBug = (bug) => {
arrayHelper.push(bug);
};

return (
<>
<Toolbar
data-test="pipelinerun-list-toolbar"
clearAllFilters={onClearFilters}
className="pf-v5-u-mb-0 pf-v5-u-pb-0 pf-v5-u-pl-0"
>
<ToolbarContent>
<ToolbarGroup align={{ default: 'alignLeft' }}>
<ToolbarItem className="pf-v5-u-ml-0">
<SearchInput
name="nameInput"
data-test="name-input-filter"
type="search"
aria-label="name filter"
placeholder="Filter by name..."
onChange={(e, n) => onNameInput(n)}
value={nameFilter}
/>
</ToolbarItem>
<ToolbarItem>
<Button
onClick={() => showModal(createAddBugModal({ bugArrayHelper: addNewBug }))}
data-test="edit-param-button"
>
Add a Bug
</Button>
</ToolbarItem>
</ToolbarGroup>
</ToolbarContent>
</Toolbar>
<Table
aria-label="Simple table"
variant="compact"
borders
className="pf-v5-u-mt-0 pf-v5-u-pt-0"
>
<Thead>
<Tr>
<Th>Bug issue key</Th>
<Th>URL</Th>
<Th>Summary</Th>
<Th>Last updated</Th>
<Th>Status</Th>
</Tr>
</Thead>
<Tbody>
{Array.isArray(filteredBugs) && filteredBugs.length > 0
? filteredBugs.map((bug, i) => (
<Tr key={bug.issueKey}>
<Td>{bug.issueKey}</Td>
<Td>{bug.url}</Td>
<Td>{bug.summary}</Td>
<Td>{bug.last_updated}</Td>
<Td>{bug.status}</Td>
<Td>
<ActionMenu
actions={[
{
cta: () => arrayHelper.remove(i),
id: 'delete-bug',
label: 'Delete bug',
},
]}
/>
</Td>
</Tr>
))
: EmptyMsg()}
</Tbody>
</Table>
</>
);
}}
/>
);
};

export default AddBugSection;
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ export const ReleasePlanDropdown: React.FC<React.PropsWithChildren<ReleasePlanDr
props,
) => {
const { namespace } = useWorkspaceInfo();
const [applications, loaded] = useReleasePlans(namespace);
const [releasePlans, loaded] = useReleasePlans(namespace);
const [, , { setValue }] = useField<string>(props.name);

const dropdownItems = React.useMemo(
() => applications.map((a) => ({ key: a.metadata.name, value: a.metadata.name })),
[applications],
() => releasePlans.map((a) => ({ key: a.metadata.name, value: a.metadata.name })),
[releasePlans],
);

return (
Expand Down
Loading

0 comments on commit 22428e7

Please sign in to comment.