Fix colouring issue when filtering (#6166)

* WIP - fix coloring

* Fix row coloring

* Remove unnecessary test

* Apply review suggestions

* Update yarn lock file

* Apply review suggestion

* Restore row coloring in Extensions.tsx

* Remove unused field index in class Row

Co-authored-by: MiZiet <michalzietalak@o2.pl>
This commit is contained in:
Ewa Kowalska 2021-09-22 15:52:14 +02:00 committed by GitHub
parent a0b8d7ff43
commit 93091ba434
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 61 additions and 102 deletions

View File

@ -25,7 +25,7 @@
"@polkadot/util-crypto": "^7.4.1",
"@polkadot/wasm-crypto": "^4.2.1",
"babel-core": "^7.0.0-bridge.0",
"styled-components": "^5.2.0",
"styled-components": "^5.3.1",
"typescript": "^4.4.3"
},
"scripts": {

View File

@ -47,7 +47,6 @@ interface Props {
proxy?: [ProxyDefinition[], BN];
setBalance: (address: string, value: AccountBalance) => void;
toggleFavorite: (address: string) => void;
isEven: boolean;
}
interface DemocracyUnlockable {
@ -100,7 +99,7 @@ const transformRecovery = {
transform: (opt: Option<RecoveryConfig>) => opt.unwrapOr(null)
};
function Account ({ account: { address, meta }, className = '', delegation, filter, isEven, isFavorite, proxy, setBalance, toggleFavorite }: Props): React.ReactElement<Props> | null {
function Account ({ account: { address, meta }, className = '', delegation, filter, isFavorite, proxy, setBalance, toggleFavorite }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const [isExpanded, toggleIsExpanded] = useToggle(false);
const { theme } = useContext<ThemeDef>(ThemeContext);
@ -402,7 +401,7 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
return (
<>
<tr className={`${className}${isExpanded ? ' noBorder' : ''} ${isEven ? 'isEven' : 'isOdd'}`}>
<tr className={`${className}${isExpanded ? ' noBorder' : ''}`}>
<td className='favorite'>
<Icon
color={isFavorite ? 'orange' : 'gray'}
@ -666,7 +665,7 @@ function Account ({ account: { address, meta }, className = '', delegation, filt
</div>
</td>
</tr>
<tr className={`${className} ${isExpanded ? 'isExpanded' : 'isCollapsed'} ${isEven ? 'isEven' : 'isOdd'}`}>
<tr className={`${className} ${isExpanded ? 'isExpanded' : 'isCollapsed'}`}>
<td colSpan={2} />
<td>
<div

View File

@ -151,13 +151,6 @@ describe('Accounts page', () => {
await rows[0].assertTags('my tagSuper Tag');
});
it('account details rows keep colouring from their primary rows', async () => {
accountsPage.renderDefaultAccounts(3);
const accountsTable = await accountsPage.getTable();
await accountsTable.assertColoring();
});
it('account details rows toggled on icon toggle click', async () => {
accountsPage.renderDefaultAccounts(1);
const row = (await accountsPage.getAccountRows())[0];
@ -286,7 +279,7 @@ describe('Accounts page', () => {
const accountsTable = await accountsPage.getTable();
await accountsTable.assertRowsOrderAndColoring([3, 1, 2]);
await accountsTable.assertRowsOrder([3, 1, 2]);
});
describe('when sorting is used', () => {
@ -316,52 +309,51 @@ describe('Accounts page', () => {
it('sorts by parent if asked', async () => {
await accountsPage.sortBy('parent');
await accountsTable.assertRowsOrderAndColoring([3, 1, 2]);
await accountsTable.assertRowsOrder([3, 1, 2]);
});
it('sorts by name if asked', async () => {
await accountsPage.sortBy('name');
await accountsTable.assertRowsOrderAndColoring([3, 2, 1]);
await accountsTable.assertRowsOrder([3, 2, 1]);
});
it('sorts by date if asked', async () => {
await accountsPage.sortBy('date');
await accountsTable.assertRowsOrderAndColoring([3, 1, 2]);
await accountsTable.assertRowsOrder([3, 1, 2]);
});
it('sorts by balances if asked', async () => {
await accountsPage.sortBy('balances');
await accountsTable.assertRowsOrderAndColoring([1, 2, 3]);
await accountsTable.assertRowsOrder([1, 2, 3]);
});
it('sorts by type if asked', async () => {
await accountsPage.sortBy('type');
await accountsTable.assertRowsOrderAndColoring([3, 1, 2]);
await accountsTable.assertRowsOrder([3, 1, 2]);
});
it('implements stable sort', async () => {
// Notice that sorting by 'type' results in different order
// depending on the previous state.
await accountsPage.sortBy('name');
await accountsTable.assertRowsOrderAndColoring([3, 2, 1]);
await accountsTable.assertRowsOrder([3, 2, 1]);
await accountsPage.sortBy('type');
await accountsTable.assertRowsOrderAndColoring([3, 1, 2]);
await accountsTable.assertRowsOrder([3, 1, 2]);
await accountsPage.sortBy('balances');
await accountsTable.assertRowsOrderAndColoring([1, 2, 3]);
await accountsTable.assertRowsOrder([1, 2, 3]);
await accountsPage.sortBy('type');
await accountsTable.assertRowsOrderAndColoring([1, 3, 2]);
await accountsTable.assertColoring();
await accountsTable.assertRowsOrder([1, 3, 2]);
});
it('respects reverse button', async () => {
await accountsPage.sortBy('name');
await accountsTable.assertRowsOrderAndColoring([3, 2, 1]);
await accountsTable.assertRowsOrder([3, 2, 1]);
await accountsPage.sortBy('balances');
await accountsTable.assertRowsOrderAndColoring([1, 2, 3]);
await accountsTable.assertRowsOrder([1, 2, 3]);
await accountsPage.reverseSortingOrder();
await accountsTable.assertRowsOrderAndColoring([3, 2, 1]);
await accountsTable.assertRowsOrder([3, 2, 1]);
await accountsPage.sortBy('name');
await accountsTable.assertRowsOrderAndColoring([1, 2, 3]);
await accountsTable.assertRowsOrder([1, 2, 3]);
});
});
});

View File

@ -6,7 +6,7 @@ import type { ActionStatus } from '@polkadot/react-components/Status/types';
import type { AccountId, ProxyDefinition, ProxyType, Voting } from '@polkadot/types/interfaces';
import type { AccountBalance, Delegation, SortedAccount } from '../types';
import React, { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components';
import { Button, FilterInput, SortDropdown, SummaryBox, Table } from '@polkadot/react-components';
@ -279,13 +279,10 @@ function Overview ({ className = '', onStatusChange }: Props): React.ReactElemen
<Table
empty={!isLoading && sortedAccounts && t<string>("You don't have any accounts. Some features are currently hidden and will only become available once you have accounts.")}
header={header.current}
withCollapsibleRows
>
{!isLoading &&
sortedAccounts.map(({ address }, index) => {
const account = accountComponents[address];
return account && React.cloneElement(account as ReactElement, { isEven: !!(index % 2) });
})
sortedAccounts.map(({ address }) => accountComponents[address])
}
</Table>
</div>

View File

@ -21,7 +21,7 @@ export class AccountsPage extends Page {
const table = await this.getTable();
const rows = await table.getRows();
return rows.map((row) => new AccountRow(row.primaryRow, row.detailsRow, row.rowIndex));
return rows.map((row) => new AccountRow(row.primaryRow, row.detailsRow));
}
async reverseSortingOrder (): Promise<void> {

View File

@ -21,14 +21,13 @@ interface Props {
address: string;
className?: string;
filter: string;
isEven: boolean;
isFavorite: boolean;
toggleFavorite: (address: string) => void;
}
const isEditable = true;
function Address ({ address, className = '', filter, isEven, isFavorite, toggleFavorite }: Props): React.ReactElement<Props> | null {
function Address ({ address, className = '', filter, isFavorite, toggleFavorite }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { theme } = useContext<ThemeDef>(ThemeContext);
const api = useApi();
@ -165,7 +164,7 @@ function Address ({ address, className = '', filter, isEven, isFavorite, toggleF
return (
<>
<tr className={`${className}${isExpanded ? ' noBorder' : ''} ${isEven ? 'isEven' : 'isOdd'}`}>
<tr className={`${className}${isExpanded ? ' noBorder' : ''}`}>
<td className='favorite'>
<Icon
color={isFavorite ? 'orange' : 'gray'}
@ -246,7 +245,7 @@ function Address ({ address, className = '', filter, isEven, isFavorite, toggleF
</div>
</td>
</tr>
<tr className={`${className} ${isExpanded ? 'isExpanded' : 'isCollapsed'} ${isEven ? 'isEven' : 'isOdd'}`}>
<tr className={`${className} ${isExpanded ? 'isExpanded' : 'isCollapsed'}`}>
<td />
<td>
<div

View File

@ -114,13 +114,6 @@ describe('Addresses page', () => {
await rows[0].assertTags('Super Tagmy tag');
});
it('details rows keep colouring from their primary rows', async () => {
addressesPage.renderDefaultContacts(3);
const addressesTable = await addressesPage.getTable();
await addressesTable.assertColoring();
});
it('contact details rows toggled on icon toggle click', async () => {
addressesPage.renderDefaultContacts(1);
const row = (await addressesPage.getAddressesRows())[0];

View File

@ -75,12 +75,12 @@ function Overview ({ className = '', onStatusChange }: Props): React.ReactElemen
<Table
empty={!isLoading && sortedAddresses && t<string>('no addresses saved yet, add any existing address')}
header={headerRef.current}
withCollapsibleRows
>
{!isLoading && sortedAddresses?.map(({ address, isFavorite }, index): React.ReactNode => (
{!isLoading && sortedAddresses?.map(({ address, isFavorite }): React.ReactNode => (
<Address
address={address}
filter={filterOn}
isEven={!!(index % 2) }
isFavorite={isFavorite}
key={address}
toggleFavorite={toggleFavorite}

View File

@ -37,17 +37,17 @@ function Bounties ({ className }: Props): React.ReactElement {
className='bounties-table-wrapper'
empty={bounties && t<string>('No open bounties')}
header={headerRef.current}
withCollapsibleRows
>
{bounties && bestNumber &&
bounties
.sort((a, b) => b.index.cmp(a.index))
.map(({ bounty, description, index, proposals }, count) => (
.map(({ bounty, description, index, proposals }) => (
<Bounty
bestNumber={bestNumber}
bounty={bounty}
description={description}
index={index}
isEven={!!(count % 2)}
key={index.toNumber()}
proposals={proposals}
/>

View File

@ -29,13 +29,12 @@ interface Props {
className?: string;
description: string;
index: BountyIndex;
isEven: boolean;
proposals?: DeriveCollectiveProposal[];
}
const EMPTY_CELL = '-';
function Bounty ({ bestNumber, bounty, className = '', description, index, isEven, proposals }: Props): React.ReactElement<Props> {
function Bounty ({ bestNumber, bounty, className = '', description, index, proposals }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const [isExpanded, setIsExpanded] = useState(false);
@ -64,7 +63,7 @@ function Bounty ({ bestNumber, bounty, className = '', description, index, isEve
return (
<>
<tr className={`${className}${isExpanded ? ' noBorder' : ''} ${isEven ? 'isEven' : 'isOdd'}`}>
<tr className={`${className}${isExpanded ? ' noBorder' : ''}`}>
<td className='number'><h1>{formatNumber(index)}</h1></td>
<td
className='description-column'
@ -148,7 +147,7 @@ function Bounty ({ bestNumber, bounty, className = '', description, index, isEve
</div>
</td>
</tr>
<tr className={`${className} ${isExpanded ? 'isExpanded' : 'isCollapsed'} ${isEven ? 'isEven' : 'isOdd'}`}>
<tr className={`${className} ${isExpanded ? 'isExpanded' : 'isCollapsed'}`}>
<td colSpan={2}>
<div className='label-column-left'>
<div className='label'>{t('Proposer')}</div>

View File

@ -20,7 +20,6 @@ interface Props {
bestHash?: string;
bestNumber?: BN;
className?: string;
isOdd?: boolean;
isOngoing?: boolean;
leasePeriod?: LeasePeriod;
value: Campaign;
@ -31,7 +30,7 @@ interface LastChange {
prevLength: number;
}
function Fund ({ bestHash, bestNumber, className, isOdd, isOngoing, leasePeriod, value: { info: { cap, depositor, end, firstPeriod, lastPeriod, raised, verifier }, isCapped, isEnded, isWinner, paraId } }: Props): React.ReactElement<Props> {
function Fund ({ bestHash, bestNumber, className = '', isOngoing, leasePeriod, value: { info: { cap, depositor, end, firstPeriod, lastPeriod, raised, verifier }, isCapped, isEnded, isWinner, paraId } }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { isAccount } = useAccounts();
@ -79,7 +78,7 @@ function Fund ({ bestHash, bestNumber, className, isOdd, isOngoing, leasePeriod,
}, [contributorsHex, blockHash]);
return (
<tr className={`${className || ''} ${isOdd ? 'isOdd' : 'isEven'}`}>
<tr className={className}>
<td className='number'><h1>{formatNumber(paraId)}</h1></td>
<td className='badge'><ParaLink id={paraId} /></td>
<td className='media--800'>

View File

@ -94,11 +94,10 @@ function Funds ({ bestNumber, className, leasePeriod, value }: Props): React.Rea
empty={value && activeSorted && t<string>('No active campaigns found')}
header={headerActiveRef.current}
>
{activeSorted?.map((fund, index) => (
{activeSorted?.map((fund) => (
<Fund
bestHash={bestHash}
bestNumber={bestNumber}
isOdd={!(index % 2)}
isOngoing
key={fund.accountId}
value={fund}
@ -110,10 +109,9 @@ function Funds ({ bestNumber, className, leasePeriod, value }: Props): React.Rea
empty={value && endedSorted && t<string>('No completed campaigns found')}
header={headedEndedRef.current}
>
{endedSorted?.map((fund, index) => (
{endedSorted?.map((fund) => (
<Fund
bestNumber={bestNumber}
isOdd={!(index % 2)}
key={fund.accountId}
leasePeriod={leasePeriod}
value={fund}

View File

@ -68,7 +68,7 @@ function Extensions ({ chainInfo, className }: Props): React.ReactElement<Props>
</td>
</tr>
<tr className='isOdd'>
<tr className='hasOddRowColoring'>
<td>
<Button.Group>
<Button

View File

@ -19,6 +19,7 @@ interface TableProps {
isFixed?: boolean;
legend?: React.ReactNode;
noBodyTag?: boolean;
withCollapsibleRows: boolean;
}
function extractBodyChildren (children: React.ReactNode): [boolean, React.ReactNode] {
@ -32,13 +33,13 @@ function extractBodyChildren (children: React.ReactNode): [boolean, React.ReactN
return [isEmpty, isEmpty ? null : kids];
}
function Table ({ children, className = '', empty, emptySpinner, filter, footer, header, isFixed, legend, noBodyTag }: TableProps): React.ReactElement<TableProps> {
function Table ({ children, className = '', empty, emptySpinner, filter, footer, header, isFixed, legend, noBodyTag, withCollapsibleRows = false }: TableProps): React.ReactElement<TableProps> {
const [isEmpty, bodyChildren] = extractBodyChildren(children);
return (
<div className={`ui--Table ${className}`}>
{legend}
<table className={`${(isFixed && !isEmpty) ? 'isFixed' : 'isNotFixed'} highlight--bg-faint`}>
<table className={`${(isFixed && !isEmpty) ? 'isFixed' : 'isNotFixed'} highlight--bg-faint${withCollapsibleRows ? ' withCollapsibleRows' : ''}`}>
<Head
filter={filter}
header={header}
@ -104,6 +105,14 @@ export default React.memo(styled(Table)`
}
}
}
&.withCollapsibleRows tbody tr {
background-color: unset;
&:nth-child(4n - 2),
&:nth-child(4n - 3) {
background-color: var(--bg-table);
}
}
}
tbody {
@ -178,7 +187,7 @@ export default React.memo(styled(Table)`
text-align: right;
}
.ui--Expander+.ui--Expander {
.ui--Expander + .ui--Expander {
margin-top: 0.375rem;
}
}
@ -262,8 +271,8 @@ export default React.memo(styled(Table)`
}
tr {
&:nth-child(odd):not(.isEven),
&:nth-child(even).isOdd {
&.hasOddRowColoring,
&:nth-child(odd) {
background: var(--bg-table);
}
@ -313,8 +322,8 @@ export default React.memo(styled(Table)`
box-shadow: none !important;
}
.ui.toggle.checkbox input:checked~.box:before,
.ui.toggle.checkbox input:checked~label:before {
.ui.toggle.checkbox input:checked ~ .box:before,
.ui.toggle.checkbox input:checked ~ label:before {
background-color: #eee !important;
}
}

View File

@ -12,12 +12,10 @@ import { format } from '../utils/balance';
export class Row {
public primaryRow: HTMLElement;
public detailsRow: HTMLElement;
public rowIndex: number;
constructor (primaryRow: HTMLElement, detailsRow: HTMLElement, rowIndex: number) {
constructor (primaryRow: HTMLElement, detailsRow: HTMLElement) {
this.primaryRow = primaryRow;
this.detailsRow = detailsRow;
this.rowIndex = rowIndex;
}
async assertBalancesTotal (expectedTotalBalance: Balance): Promise<void> {
@ -55,13 +53,6 @@ export class Row {
expect(actualShortAddress).toHaveTextContent(expectedShortAddress);
}
assertColoring (): void {
const expectedColorClass = this.getExpectedColorClass();
expect(this.primaryRow).toHaveClass(expectedColorClass);
expect(this.detailsRow).toHaveClass(expectedColorClass);
}
async expand (): Promise<void> {
const toggle = await within(this.primaryRow).findByTestId('row-toggle');
@ -92,8 +83,4 @@ export class Row {
private getAccountName (): Promise<HTMLElement> {
return within(this.primaryRow).findByTestId('account-name');
}
private getExpectedColorClass (): string {
return this.rowIndex % 2 ? 'isEven' : 'isOdd';
}
}

View File

@ -12,11 +12,6 @@ export class Table {
this.rowClassName = rowClassName;
}
async assertRowsOrderAndColoring (order: number[]): Promise<void> {
await this.assertRowsOrder(order);
await this.assertColoring();
}
async assertRowsOrder (balancesExpectedOrder: number[]): Promise<void> {
const orderedRows = await this.getRows();
@ -28,14 +23,6 @@ export class Table {
}
}
async assertColoring (): Promise<void> {
const collapsibleRows = await this.getRows();
for (const collapsibleRow of collapsibleRows) {
collapsibleRow.assertColoring();
}
}
async getRows (): Promise<Row[]> {
const htmlRows = await this.getFilteredHtmlRows();
const collapsibleRows: Row[] = [];
@ -44,7 +31,7 @@ export class Table {
const primaryRow = htmlRows[rowIdx];
const detailsRow = htmlRows[rowIdx + 1];
collapsibleRows.push(new Row(primaryRow, detailsRow, rowIdx / 2));
collapsibleRows.push(new Row(primaryRow, detailsRow));
}
return collapsibleRows;

View File

@ -5987,7 +5987,7 @@ __metadata:
languageName: node
linkType: hard
"babel-plugin-styled-components@npm:>= 1, babel-plugin-styled-components@npm:^1.13.2":
"babel-plugin-styled-components@npm:>= 1.12.0, babel-plugin-styled-components@npm:^1.13.2":
version: 1.13.2
resolution: "babel-plugin-styled-components@npm:1.13.2"
dependencies:
@ -19510,16 +19510,16 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"styled-components@npm:^5.2.0":
version: 5.2.1
resolution: "styled-components@npm:5.2.1"
"styled-components@npm:^5.3.1":
version: 5.3.1
resolution: "styled-components@npm:5.3.1"
dependencies:
"@babel/helper-module-imports": ^7.0.0
"@babel/traverse": ^7.4.5
"@emotion/is-prop-valid": ^0.8.8
"@emotion/stylis": ^0.8.4
"@emotion/unitless": ^0.7.4
babel-plugin-styled-components: ">= 1"
babel-plugin-styled-components: ">= 1.12.0"
css-to-react-native: ^3.0.0
hoist-non-react-statics: ^3.0.0
shallowequal: ^1.1.0
@ -19528,7 +19528,7 @@ resolve@^2.0.0-next.3:
react: ">= 16.8.0"
react-dom: ">= 16.8.0"
react-is: ">= 16.8.0"
checksum: e1fa699bad203e5acde6a62c7a9d511629de5b066345799c458415434a716b93253ddbba3fbc197c16362ba8532a59f85024878d6cc2de67655e0438d6620e0f
checksum: 2d833d573c039f4af5c422ce33f06212dfa51a821994ec1d7a697355752b422cad6e92eeff712dbd9c0339aade8eb5bce10c30dfecb3c8e707530b6dda7dda10
languageName: node
linkType: hard