-
Notifications
You must be signed in to change notification settings - Fork 15
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
Adds proposal table, proposal status container, fixes theme toggle and dropdown issue #1525
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
786c60a
chore: add proposal table
devpavan04 087f14c
chore: code format
devpavan04 11a476c
chore: add proposal status and update batched proposal query
devpavan04 23b9693
fix: dropdown close on click issue
devpavan04 8695624
Merge branch 'develop' into PS/stats-proposal-table
devpavan04 c4a1093
chore: review comments changes
devpavan04 e5db989
chore: code format
devpavan04 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
306 changes: 305 additions & 1 deletion
306
apps/stats-dapp/src/containers/ProposalsTable/ProposalsTable.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,307 @@ | ||
import { | ||
ColumnDef, | ||
createColumnHelper, | ||
getCoreRowModel, | ||
getPaginationRowModel, | ||
PaginationState, | ||
Table as RTTable, | ||
useReactTable, | ||
} from '@tanstack/react-table'; | ||
import { ChainConfig, chainsConfig } from '@webb-tools/dapp-config'; | ||
import { getChipColorByProposalType, mapChainNameToLogo } from '../../utils'; | ||
import { | ||
Accordion, | ||
AccordionButton, | ||
AccordionContent, | ||
AccordionItem, | ||
CardTable, | ||
CheckBoxMenuGroup, | ||
Chip, | ||
Filter, | ||
Table, | ||
Divider, | ||
ProposalsBadgeGroup, | ||
} from '@webb-tools/webb-ui-components/components'; | ||
import { fuzzyFilter } from '@webb-tools/webb-ui-components/components/Filter/utils'; | ||
import { ChainIcon, Spinner } from '@webb-tools/icons'; | ||
import React, { useMemo, useState } from 'react'; | ||
import { Link } from 'react-router-dom'; | ||
import { | ||
ProposalBatchStatus, | ||
ProposalType, | ||
ProposalBatchesOrderBy, | ||
} from '../../generated/graphql'; | ||
import { | ||
ProposalBatch, | ||
BatchedProposalsQuery, | ||
useBatchedProposals, | ||
} from '../../provider/hooks'; | ||
import { | ||
mapProposalStatusToChipColor, | ||
PROPOSAL_STATUS, | ||
PROPOSAL_TYPES, | ||
} from './utils'; | ||
|
||
const columnHelper = createColumnHelper<ProposalBatch>(); | ||
|
||
const columns: ColumnDef<ProposalBatch, any>[] = [ | ||
columnHelper.accessor('status', { | ||
header: 'Status', | ||
cell: (props) => ( | ||
<StatusChip status={props.getValue<ProposalBatchStatus>()} /> | ||
), | ||
}), | ||
|
||
columnHelper.accessor('height', { | ||
header: 'Height', | ||
cell: (props) => props.getValue<string>(), | ||
}), | ||
|
||
columnHelper.accessor('proposals', { | ||
header: 'Proposal(s)', | ||
cell: (props) => { | ||
const proposalTypes = props.getValue().map((proposal: any) => { | ||
return proposal.type; | ||
}); | ||
return proposalTypes.length > 0 ? ( | ||
<ProposalsBadgeGroup proposals={proposalTypes} /> | ||
) : ( | ||
'--' | ||
); | ||
}, | ||
}), | ||
|
||
columnHelper.accessor('chain', { | ||
header: 'Chain', | ||
cell: (props) => { | ||
const logoName = mapChainNameToLogo(props.getValue()); | ||
return <ChainIcon name={logoName} size="lg" />; | ||
}, | ||
}), | ||
|
||
// columnHelper.accessor('id', { | ||
// header: '', | ||
// cell: (props) => ( | ||
// <Button variant="link" size="sm"> | ||
// <Link to={`drawer/${props.getValue<string>()}`}>Details</Link> | ||
// </Button> | ||
// ), | ||
// }), | ||
]; | ||
|
||
export const ProposalsTable = () => { | ||
return <div>Proposal Table</div>; | ||
const [{ pageIndex, pageSize }, setPagination] = useState<PaginationState>({ | ||
pageIndex: 0, | ||
pageSize: 10, | ||
}); | ||
|
||
const pagination = useMemo( | ||
() => ({ | ||
pageIndex, | ||
pageSize, | ||
}), | ||
[pageIndex, pageSize] | ||
); | ||
|
||
const chains = useMemo<Array<[string, ChainConfig]>>( | ||
() => | ||
Object.keys(chainsConfig).map((key: any) => [ | ||
String(key), | ||
chainsConfig[key], | ||
]), | ||
[] | ||
); | ||
|
||
const [globalFilter, setGlobalFilter] = useState(''); | ||
const [selectedProposalsStatuses, setSelectedProposalStatuses] = useState< | ||
'all' | ProposalBatchStatus[] | ||
>('all'); | ||
const [selectedProposalTypes, setSelectedProposalTypes] = useState< | ||
'all' | ProposalType[] | ||
>('all'); | ||
const [selectedChains, setSelectedChains] = useState< | ||
'all' | [string, ChainConfig][] | ||
>('all'); | ||
|
||
const pageQuery: BatchedProposalsQuery = useMemo( | ||
() => ({ | ||
offset: pagination.pageIndex * pageSize, | ||
perPage: pagination.pageSize, | ||
orderBy: ProposalBatchesOrderBy.IdDesc, | ||
filter: null, | ||
}), | ||
[ | ||
pageSize, | ||
pagination.pageIndex, | ||
pagination.pageSize, | ||
selectedProposalTypes, | ||
selectedProposalsStatuses, | ||
selectedChains, | ||
] | ||
); | ||
|
||
const batchedProposals = useBatchedProposals(pageQuery); | ||
|
||
const totalItems = useMemo(() => { | ||
if (batchedProposals.val) { | ||
return batchedProposals.val.pageInfo.count; | ||
} | ||
return 0; | ||
}, [batchedProposals]); | ||
|
||
const pageCount = useMemo( | ||
() => Math.ceil(totalItems / pageSize), | ||
[pageSize, totalItems] | ||
); | ||
|
||
const data = useMemo(() => { | ||
if (batchedProposals.val) { | ||
return batchedProposals.val.items; | ||
} | ||
|
||
return [] as ProposalBatch[]; | ||
}, [batchedProposals]); | ||
|
||
const table = useReactTable<ProposalBatch>({ | ||
columns, | ||
data: data, | ||
pageCount: pageCount, | ||
getCoreRowModel: getCoreRowModel(), | ||
state: { | ||
pagination, | ||
}, | ||
onPaginationChange: setPagination, | ||
manualPagination: true, | ||
getPaginationRowModel: getPaginationRowModel(), | ||
filterFns: { | ||
fuzzy: fuzzyFilter, | ||
}, | ||
}); | ||
|
||
return ( | ||
<CardTable | ||
titleProps={{ | ||
title: 'All Proposals', | ||
info: 'All proposals', | ||
variant: 'h5', | ||
}} | ||
leftTitle={ | ||
<Filter | ||
searchPlaceholder={'Search proposals'} | ||
searchText={globalFilter} | ||
onSearchChange={(nextValue: string | number) => { | ||
setGlobalFilter(nextValue.toString()); | ||
}} | ||
clearAllFilters={() => { | ||
table.setColumnFilters([]); | ||
table.setGlobalFilter(''); | ||
setSelectedProposalTypes('all'); | ||
setSelectedProposalStatuses('all'); | ||
setSelectedChains('all'); | ||
}} | ||
> | ||
<Accordion type={'single'} collapsible> | ||
<AccordionItem className={'p-0 py-0'} value={'proposal-type'}> | ||
<AccordionButton>Type</AccordionButton> | ||
<Divider className="bg-mono-40 dark:bg-mono-140" /> | ||
<AccordionContent className="p-0"> | ||
<div | ||
className={ | ||
'max-w-[300px] max-h-[300px] overflow-x-hidden overflow-y-auto' | ||
} | ||
> | ||
<CheckBoxMenuGroup | ||
value={selectedProposalTypes} | ||
options={PROPOSAL_TYPES} | ||
onChange={(v) => { | ||
setSelectedProposalTypes(v); | ||
}} | ||
labelGetter={(proposalType) => ( | ||
<span className={'text-xs'}>{proposalType}</span> | ||
)} | ||
keyGetter={(proposalType) => | ||
`Filter_proposals${proposalType}` | ||
} | ||
/> | ||
</div> | ||
</AccordionContent> | ||
</AccordionItem> | ||
<AccordionItem className={'p-0 py-0'} value={'proposal-status'}> | ||
<AccordionButton>Status</AccordionButton> | ||
<Divider className="bg-mono-40 dark:bg-mono-140" /> | ||
<AccordionContent className="p-0"> | ||
<div | ||
className={ | ||
'max-w-[300px] max-h-[300px] overflow-x-hidden overflow-y-auto' | ||
} | ||
> | ||
<CheckBoxMenuGroup | ||
value={selectedProposalsStatuses} | ||
options={PROPOSAL_STATUS} | ||
onChange={(v) => { | ||
setSelectedProposalStatuses(v); | ||
}} | ||
labelGetter={(proposalStatus) => ( | ||
<Chip | ||
color={mapProposalStatusToChipColor(proposalStatus)} | ||
> | ||
{proposalStatus} | ||
</Chip> | ||
)} | ||
keyGetter={(proposalStatus) => | ||
`Filter_proposals${proposalStatus}` | ||
} | ||
/> | ||
</div> | ||
</AccordionContent> | ||
</AccordionItem> | ||
|
||
<AccordionItem className={'p-0'} value={'chain'}> | ||
<AccordionButton>Chain</AccordionButton> | ||
<AccordionContent className="p-2"> | ||
<div className="max-w-[300px] max-h-[300px] overflow-x-hidden overflow-y-auto"> | ||
<CheckBoxMenuGroup | ||
value={selectedChains} | ||
options={chains} | ||
onChange={(v) => { | ||
setSelectedChains(v); | ||
}} | ||
iconGetter={([_key, chainConfig]) => ( | ||
<div className="max-w-[20px] max-h-[20px] overflow-hidden "> | ||
{/* {<chainConfig.logo />} */} | ||
</div> | ||
)} | ||
labelGetter={([_, chain]) => chain.name} | ||
keyGetter={([chainId]) => `Filter_proposals${chainId}`} | ||
/> | ||
</div> | ||
</AccordionContent> | ||
</AccordionItem> | ||
</Accordion> | ||
</Filter> | ||
} | ||
className="h-[800px]" | ||
> | ||
{data.length > 0 ? ( | ||
<Table | ||
tableProps={table as RTTable<unknown>} | ||
isPaginated | ||
totalRecords={totalItems} | ||
title="Proposals" | ||
/> | ||
) : ( | ||
<div className="h-[800px] flex items-center flex-col justify-center"> | ||
<Spinner size="xl" /> | ||
</div> | ||
)} | ||
</CardTable> | ||
); | ||
}; | ||
|
||
interface StatusChipProps { | ||
status: ProposalBatchStatus; | ||
} | ||
|
||
const StatusChip: React.FC<StatusChipProps> = ({ status }) => { | ||
return <Chip color={getChipColorByProposalType(status)}>{status}</Chip>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export * from './ProposalsTable'; | ||
export * from './utils'; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please consider relocating the utility functions and constants to a separate file to decrease the size of the current file. A suitable location could be
apps/stats-dapp/src/containers/ProposalsTable/utils.ts
.