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

Collection management #2908

Merged
merged 37 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
7b0ab2f
checkout
akanshaaa19 May 20, 2024
f59bc73
Merge branch 'master' of github.com-akanshaaa19:glific/glific-fronten…
akanshaaa19 May 21, 2024
9291639
changed logic for adding colections
akanshaaa19 May 21, 2024
c06ccd7
remove/add functionality
akanshaaa19 Jun 3, 2024
e4ea56f
fixed bug
akanshaaa19 Jun 3, 2024
a38dc22
fixed test case
akanshaaa19 Jun 3, 2024
dd9f029
Merge branch 'master' into collection-management
akanshaaa19 Jun 5, 2024
8678c2b
fixed cypress test cases
akanshaaa19 Jun 5, 2024
9fd5eb7
added support in groups
akanshaaa19 Jun 5, 2024
a930fd7
update select placholder based on groups
kurund Jun 5, 2024
4c5f4e2
resolved comments
akanshaaa19 Jun 6, 2024
a82b3e0
fixed a small bug
akanshaaa19 Jun 8, 2024
f9fee79
fixed deepscan issues
akanshaaa19 Jun 9, 2024
82f15cd
resolved comments
akanshaaa19 Jun 10, 2024
35be145
merge conflicts
akanshaaa19 Jun 10, 2024
6d2dc72
refactoring
akanshaaa19 Jun 10, 2024
8c8d3b1
Merge branch 'master' of github.com-akanshaaa19:glific/glific-fronten…
akanshaaa19 Jun 11, 2024
c8da851
Merge branch 'master' of github.com-akanshaaa19:glific/glific-fronten…
akanshaaa19 Jun 13, 2024
2665cb3
api changes
akanshaaa19 Jun 19, 2024
1439a0b
api changes and test case fixes
akanshaaa19 Jun 22, 2024
02bb6bf
fixed deepscan issues
akanshaaa19 Jun 22, 2024
3afb3b2
api change in wagroups
akanshaaa19 Jun 24, 2024
f49e430
Merge branch 'master' into collection-management
akanshaaa19 Jun 24, 2024
8601ec7
cleanup and test cases
akanshaaa19 Jun 24, 2024
ed5a9ef
Merge branch 'master' of github.com-akanshaaa19:glific/glific-fronten…
akanshaaa19 Jun 24, 2024
13b007d
Merge branch 'collection-management' of github.com-akanshaaa19:glific…
akanshaaa19 Jun 24, 2024
fbc778e
added missing mock
akanshaaa19 Jun 24, 2024
cb0733f
Merge branch 'master' into collection-management
akanshaaa19 Jun 27, 2024
bd11d05
Merge branch 'master' of github.com-akanshaaa19:glific/glific-fronten…
akanshaaa19 Jul 1, 2024
7181974
added test cases
akanshaaa19 Jul 1, 2024
4435143
Merge branch 'collection-management' of github.com-akanshaaa19:glific…
akanshaaa19 Jul 1, 2024
6469ec9
Merge branch 'master' into collection-management
akanshaaa19 Jul 2, 2024
4e6178a
Merge branch 'master' into collection-management
kurund Jul 3, 2024
18b362b
Merge branch 'master' into collection-management
kurund Jul 8, 2024
f252670
updated messages and localization
kurund Jul 8, 2024
84b3115
more message updates
kurund Jul 8, 2024
3d716d4
Merge remote-tracking branch 'origin/master' into collection-management
kurund Jul 8, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/cypress-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
git clone https://github.com/glific/cypress-testing.git
echo done. go to dir.
cd cypress-testing
git checkout main
git checkout collections-management
cd ..
cp -r cypress-testing/cypress cypress
yarn add cypress@13.6.2
Expand Down
4 changes: 4 additions & 0 deletions src/assets/images/icons/AddGroupIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/components/UI/DialogBox/DialogBox.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
width: 474px;
}

.FullWidth {
width: 600px !important;
}

.ScrollPaper {
align-items: unset !important;
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/UI/DialogBox/DialogBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface DialogProps {
buttonMiddle?: string | null;
additionalTitleStyles?: string | null;
buttonOkLoading?: boolean;
fullWidth?: boolean;
}

export const DialogBox = ({
Expand All @@ -48,6 +49,7 @@ export const DialogBox = ({
alwaysOntop = false,
buttonMiddle,
buttonOkLoading = false,
fullWidth = false,
}: DialogProps) => {
let cancelButtonDisplay = null;
if (!skipCancel) {
Expand Down Expand Up @@ -124,7 +126,7 @@ export const DialogBox = ({
open={open}
classes={{
container: styles.Dialogbox,
paper: styles.DialogboxPaper,
paper: `${styles.DialogboxPaper} ${fullWidth && styles.FullWidth}`,
scrollPaper: styles.ScrollPaper,
root: alwaysOntop ? styles.DialogboxRoot : '',
}}
Expand Down
7 changes: 4 additions & 3 deletions src/components/UI/Form/AutoComplete/AutoComplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface AutocompleteProps {
hasCreateOption?: boolean;
handleCreateItem?: any;
isFilterType?: boolean;
showTags?: boolean;
}

export const AutoComplete = ({
Expand Down Expand Up @@ -82,6 +83,7 @@ export const AutoComplete = ({
handleCreateItem = () => {},
placeholder = '',
isFilterType = false,
showTags = true,
}: AutocompleteProps) => {
const errorText = getIn(errors, field.name);
const touchedVal = getIn(touched, field.name);
Expand Down Expand Up @@ -125,6 +127,7 @@ export const AutoComplete = ({
};

const getRenderTags = (value: Array<any>, getTagProps: any) => {
if (!showTags) return null;
let tagsToRender = value;

/**
Expand Down Expand Up @@ -196,8 +199,6 @@ export const AutoComplete = ({
onChange={(_event, value: any) => {
if (asyncSearch && value.length > 0) {
asyncValues.setValue([...value]);
setSearchTerm('');
onChange('');
} else if (asyncSearch && value.length === 0) {
asyncValues.setValue([]);
}
Expand Down Expand Up @@ -225,7 +226,7 @@ export const AutoComplete = ({
disableCloseOnSelect={multiple}
renderTags={getRenderTags}
renderOption={(props, option, { selected }) => (
<li {...props}>
<li key={option.id} {...props}>
{multiple && (
<Checkbox
icon={icon}
Expand Down
25 changes: 25 additions & 0 deletions src/components/UI/Pager/Pager.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,28 @@
.Skeleton {
margin: 10px;
}

.SelectedItems {
composes: RowHeadStyle;
font-weight: 700;
text-align: left;
}

.Icon {
composes: RowHeadStyle;
}

.Icon span {
background-color: #fff;
border-radius: 100%;
padding: 8px;
display: flex;
align-items: center;
width: 30px;
margin-left: auto;
cursor: pointer;
}

.Checkbox {
padding: 1rem;
}
104 changes: 70 additions & 34 deletions src/components/UI/Pager/Pager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
collapseRow: string | undefined;
noItemsText?: any;
showPagination?: boolean;
checkboxSupport?: { action: any; icon: any; selectedItems: any };
}

// TODO: cleanup the translations code
Expand Down Expand Up @@ -120,41 +121,68 @@
columnNames: Array<any>,
columnStyles: any,
tableVals: any,
handleTableChange: Function
handleTableChange: Function,
totalRows: number,
checkboxSupport?: { action: any; icon: any; selectedItems: any }
) => {
const headerRow = (
<TableRow className={styles.TableHeadRow}>
{columnNames.map((field: any, i: number) => (
<TableCell
key={field.label}
className={`${columnStyles && columnStyles[i]} ${styles.RowHeadStyle}`}
>
{i !== columnNames.length - 1 && field.name ? (
<TableSortLabel
active={field.name === tableVals.sortCol}
direction={tableVals.sortDirection}
onClick={() => {
if (field.name !== tableVals.sortCol) {
handleTableChange('sortCol', field.name);
} else {
handleTableChange('sortCol', field.name);
handleTableChange(
'sortDirection',
tableVals.sortDirection === 'asc' ? 'desc' : 'asc'
);
}
}}
className={styles.HeaderColor}
>
{field.label}
</TableSortLabel>
) : (
field.label
)}
let headerRow;

if (checkboxSupport?.selectedItems && checkboxSupport?.selectedItems.length > 0) {
headerRow = (
<TableRow className={styles.TableHeadRow}>
<TableCell className={`${styles.Checkbox} ${styles.RowHeadStyle}`}>
{columnNames[0].label}
</TableCell>
))}
</TableRow>
);
<TableCell className={styles.SelectedItems}>
{checkboxSupport?.selectedItems.length} of {totalRows} selected
</TableCell>
<TableCell colSpan={3} className={styles.Icon}>
<span
onClick={() => {
checkboxSupport?.action();
}}
>
{checkboxSupport?.icon}
</span>
</TableCell>
</TableRow>
);
} else {
headerRow = (
<TableRow className={styles.TableHeadRow}>
{columnNames.map((field: any, i: number) => (
<TableCell
key={field.label}
className={`${columnStyles && columnStyles[i]} ${styles.RowHeadStyle}`}
>
{i !== columnNames.length - 1 && field.name ? (
<TableSortLabel
active={field.name === tableVals.sortCol}
direction={tableVals.sortDirection}
onClick={() => {
if (field.name !== tableVals.sortCol) {
handleTableChange('sortCol', field.name);
} else {
handleTableChange('sortCol', field.name);
handleTableChange(

Check warning on line 167 in src/components/UI/Pager/Pager.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/UI/Pager/Pager.tsx#L166-L167

Added lines #L166 - L167 were not covered by tests
'sortDirection',
tableVals.sortDirection === 'asc' ? 'desc' : 'asc'
);
}
}}
className={styles.HeaderColor}
>
{field.label}
</TableSortLabel>
) : (
field.label
)}
</TableCell>
))}
</TableRow>
);
}

return headerRow;
};

Expand Down Expand Up @@ -193,9 +221,17 @@
loadingList = false,
noItemsText,
showPagination = true,
checkboxSupport,
}: PagerProps) => {
const rows = createRows(data, columnStyles, collapseRow, collapseOpen);
const tableHead = tableHeadColumns(columnNames, columnStyles, tableVals, handleTableChange);
const tableHead = tableHeadColumns(
columnNames,
columnStyles,
tableVals,
handleTableChange,
totalRows,
checkboxSupport
);
const tablePagination = pagination(columnNames, totalRows, handleTableChange, tableVals);

return (
Expand Down
45 changes: 20 additions & 25 deletions src/components/UI/SearchDialogBox/SearchDialogBox.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { render, fireEvent } from '@testing-library/react';
import { render, fireEvent, screen, waitFor } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import { vi } from 'vitest';

import { SearchDialogBox } from './SearchDialogBox';
import * as AutoComplete from '../Form/AutoComplete/AutoComplete';

const mockHandleOk = vi.fn();
const mockHandleCancel = vi.fn();
Expand All @@ -15,6 +14,7 @@ const defaultProps: any = {
onChange: mockHandleChange,
options: [{ id: '1', label: 'something' }],
selectedOptions: ['1'],
multiple: false,
};

const asyncSearchProps = {
Expand All @@ -37,9 +37,16 @@ test('it should render the title correctly', () => {
expect(getByTestId('dialogTitle')).toHaveTextContent('Search Box');
});

test('it should contain the selected option', () => {
const { getByTestId } = render(searchDialog());
expect(getByTestId('searchChip').querySelector('span')).toHaveTextContent('something');
test('it should contain the selected option', async () => {
const { getByRole } = render(searchDialog());
const [interactiveType] = screen.getAllByTestId('autocomplete-element');
interactiveType.focus();
fireEvent.keyDown(interactiveType, { key: 'ArrowDown' });
fireEvent.keyDown(interactiveType, { key: 'Enter' });

await waitFor(() => {
expect(getByRole('option')).toHaveTextContent('something');
});
});

test('save with normal props', () => {
Expand All @@ -54,26 +61,14 @@ test('save with async prop', () => {
// need assertions here
});

test('change value in dialog box', () => {
const spy = vi.spyOn(AutoComplete, 'AutoComplete');
spy.mockImplementation((props: any) => {
const { form, onChange } = props;
test('change value in dialog box', async () => {
render(searchDialog(defaultProps));
const [interactiveType] = screen.getAllByTestId('autocomplete-element');
interactiveType.focus();
fireEvent.keyDown(interactiveType, { key: 'ArrowDown' });
fireEvent.keyDown(interactiveType, { key: 'Enter' });

return (
<div data-testid="searchDialogBox">
<input
onChange={(value) => {
onChange(value);
form.setFieldValue(value);
}}
/>
</div>
);
await waitFor(() => {
expect(screen.getByRole('option')).toHaveTextContent('something');
});
const { getByTestId } = render(searchDialog(defaultProps));
fireEvent.change(getByTestId('searchDialogBox').querySelector('input') as Element, {
target: { value: 'change' },
});

// need assertions here
});
23 changes: 22 additions & 1 deletion src/components/UI/SearchDialogBox/SearchDialogBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export interface SearchDialogBoxProps {
buttonOk?: string;
description?: string;
colorOk?: string;
fullWidth?: boolean;
placeholder?: string;
showTags?: boolean;
}

export const SearchDialogBox = (props: SearchDialogBoxProps) => {
Expand All @@ -45,10 +48,18 @@ export const SearchDialogBox = (props: SearchDialogBoxProps) => {
buttonOk = 'Save',
description = '',
colorOk,
fullWidth = false,
showTags = true,
placeholder,
} = props;

const [selectedOption, setSelectedOptions] = useState<any>(multiple ? [] : null);
const [asyncSelectedOptions, setAsyncSelectedOptions] = useState<Array<any>>([]);
const [optionsData, setOptionsData] = useState<any>(options);

useEffect(() => {
setOptionsData(options);
}, [options]);

useEffect(() => {
if (!asyncSearch) {
Expand All @@ -68,6 +79,13 @@ export const SearchDialogBox = (props: SearchDialogBoxProps) => {

const changeValue = (event: any, value: any) => {
setSelectedOptions(value);
if (multiple) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we are duplicating the code here (line 66)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the useEffect is for when options are loaded for the first time and the function is for when option is selected

const selectedIds = value.map((option: any) => option.id);
setOptionsData([
...value,
...options.filter((option: any) => !selectedIds.includes(option.id)),
]);
}
};

const selectedOptionsIds = multiple
Expand All @@ -86,14 +104,15 @@ export const SearchDialogBox = (props: SearchDialogBoxProps) => {
titleAlign="left"
colorOk={colorOk}
buttonOk={buttonOk}
fullWidth={fullWidth}
>
<div>
<FormControl fullWidth>
<AutoComplete
disableClearable={disableClearable}
asyncSearch={asyncSearch}
asyncValues={{ value: asyncSelectedOptions, setValue: setAsyncSelectedOptions }}
options={options}
options={optionsData}
optionLabel={optionLabel || 'label'}
additionalOptionLabel={additionalOptionLabel}
field={{ value: selectedOption }}
Expand All @@ -111,6 +130,8 @@ export const SearchDialogBox = (props: SearchDialogBoxProps) => {
renderTags={renderTags}
selectedOptionsIds={selectedOptionsIds}
multiple={multiple}
placeholder={placeholder}
showTags={showTags}
/>
</FormControl>
<div className={styles.Description} data-testid="description">
Expand Down
Loading
Loading