From 520a1f398f48ddb9c951e004a7dcafc91d3293a5 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Thu, 18 Jan 2024 15:15:31 +0700 Subject: [PATCH 001/531] feat(components): add proposal detail page structure --- CHANGELOG.md | 1 + .../components/ProposalDetailsBody.tsx | 90 +++++++++++++++ .../components/ProposalOverview.tsx | 79 +++++++++++++ .../components/ProposalTop.tsx | 5 + .../components/VoteDetail.tsx | 36 ++++++ .../components/VoteDetailTab.tsx | 105 ++++++++++++++++++ src/lib/pages/proposal-details/index.tsx | 11 ++ src/lib/pages/proposal-details/type.ts | 9 ++ src/pages/[network]/proposals/[id]/[tab].tsx | 3 + src/pages/[network]/proposals/[id]/index.tsx | 3 + src/pages/proposals/[id]/[tab].tsx | 3 + src/pages/proposals/[id]/index.tsx | 3 + 12 files changed, 348 insertions(+) create mode 100644 src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx create mode 100644 src/lib/pages/proposal-details/components/ProposalOverview.tsx create mode 100644 src/lib/pages/proposal-details/components/ProposalTop.tsx create mode 100644 src/lib/pages/proposal-details/components/VoteDetail.tsx create mode 100644 src/lib/pages/proposal-details/components/VoteDetailTab.tsx create mode 100644 src/lib/pages/proposal-details/index.tsx create mode 100644 src/lib/pages/proposal-details/type.ts create mode 100644 src/pages/[network]/proposals/[id]/[tab].tsx create mode 100644 src/pages/[network]/proposals/[id]/index.tsx create mode 100644 src/pages/proposals/[id]/[tab].tsx create mode 100644 src/pages/proposals/[id]/index.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 85623c166..6d9e2e153 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#731](https://github.com/alleslabs/celatone-frontend/pull/731) Add proposal detail page structure - [#727](https://github.com/alleslabs/celatone-frontend/pull/727) Add amp nft pages - [#720](https://github.com/alleslabs/celatone-frontend/pull/720) Add delegations for contract detail - [#684](https://github.com/alleslabs/celatone-frontend/pull/684) Add nft page diff --git a/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx b/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx new file mode 100644 index 000000000..b68da0414 --- /dev/null +++ b/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx @@ -0,0 +1,90 @@ +import { TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"; +import { useRouter } from "next/router"; +import { useCallback, useEffect } from "react"; + +import { TabIndex } from "../type"; +import { useInternalNavigate } from "lib/app-provider"; +import { CustomTab } from "lib/components/CustomTab"; +import { getFirstQueryParam } from "lib/utils"; + +import { ProposalOverview } from "./ProposalOverview"; +import { ProposalTop } from "./ProposalTop"; +import { VoteDetail } from "./VoteDetail"; + +interface ProposalDetailBodyProps { + id?: number; +} +export const ProposalDetailBody = ({ id = 123 }: ProposalDetailBodyProps) => { + const router = useRouter(); + const navigate = useInternalNavigate(); + + const tab = getFirstQueryParam(router.query.tab) as TabIndex; + + const handleTabChange = useCallback( + (nextTab: TabIndex) => () => { + if (nextTab === tab) return; + navigate({ + pathname: "/proposals/[id]/[tab]", + query: { + // To get from route + id, + tab: nextTab, + }, + options: { + shallow: true, + }, + }); + }, + [id, tab, navigate] + ); + + useEffect(() => { + if (router.isReady && (!tab || !Object.values(TabIndex).includes(tab))) { + navigate({ + replace: true, + pathname: "/proposals/[id]/[tab]", + query: { + id, + tab: TabIndex.Overview, + }, + options: { + shallow: true, + }, + }); + } + }, [router.isReady, tab, navigate, id]); + + return ( + <> + + + + + Proposal Overview + + + Vote Detail + + + + + + + + + + + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/ProposalOverview.tsx b/src/lib/pages/proposal-details/components/ProposalOverview.tsx new file mode 100644 index 000000000..98af6f30f --- /dev/null +++ b/src/lib/pages/proposal-details/components/ProposalOverview.tsx @@ -0,0 +1,79 @@ +import { Flex, Grid, GridItem, Heading, Text } from "@chakra-ui/react"; + +const ProposalStatus = () => { + return ( + + Current Status component + + ); +}; +export const ProposalOverview = () => { + return ( + + + + + + + Proposal Description + + + This is a proposal to give the address + osmo1raa4kyx5ypz75qqk3566c6slx2mw3qzsu6rymw permission to upload + CosmWasm contracts to Osmosis without seeking governance approval + for subsequent uploads. Deploying this contract will allow Skip to + leverage Osmosis swap hooks to build a service that simplifies + cross-chain transfers, swaps, and fee management. Skip will + provide this functionality via our free API, which enables + applications anywhere in Cosmos to seamlessly draw on Osmosis + liquidity. While this proposal gives authority for + osmo1raa4kyx5ypz75qqk3566c6slx2mw3qzsu6rymw to permissionlessly + upload CosmWasm contracts to Osmosis, governance only signals + approval for contracts relating to the function of Skip API + service. Details can be seen in the Commonwealth thread: + https://gov.osmosis.zone/discussion/11973-skip-api-contract-upload + + + + + Proposal Messages + + + Proposal message content + + + + + + + Proposal Period + + + Proposal period content + + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/ProposalTop.tsx b/src/lib/pages/proposal-details/components/ProposalTop.tsx new file mode 100644 index 000000000..971cf8d6c --- /dev/null +++ b/src/lib/pages/proposal-details/components/ProposalTop.tsx @@ -0,0 +1,5 @@ +import { Flex } from "@chakra-ui/react"; + +export const ProposalTop = () => { + return proposal top; +}; diff --git a/src/lib/pages/proposal-details/components/VoteDetail.tsx b/src/lib/pages/proposal-details/components/VoteDetail.tsx new file mode 100644 index 000000000..2c4b19809 --- /dev/null +++ b/src/lib/pages/proposal-details/components/VoteDetail.tsx @@ -0,0 +1,36 @@ +import { Flex, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"; + +import { VoteDetailTab } from "./VoteDetailTab"; + +export const VoteDetail = () => { + return ( + + {/* To add index to Tabs */} + + + + + + + 1 + 2 + + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/VoteDetailTab.tsx b/src/lib/pages/proposal-details/components/VoteDetailTab.tsx new file mode 100644 index 000000000..533f5c88c --- /dev/null +++ b/src/lib/pages/proposal-details/components/VoteDetailTab.tsx @@ -0,0 +1,105 @@ +import type { TabProps } from "@chakra-ui/react"; +import { + Button, + useTab, + Text, + useMultiStyleConfig, + Flex, +} from "@chakra-ui/react"; + +import type { Nullish } from "lib/types"; + +interface CustomTabProps extends TabProps { + count?: Nullish; + isLoading?: boolean; + title: string; + description: string; + step: number; +} + +export const VoteDetailTab = ({ + count, + isLoading, + title, + description, + step, + ...restProps +}: CustomTabProps) => { + const tabProps = useTab({ ...restProps }); + const isSelected = tabProps["aria-selected"]; + const styles = useMultiStyleConfig("Tabs", tabProps); + + return ( + + ); +}; diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx new file mode 100644 index 000000000..52153d98d --- /dev/null +++ b/src/lib/pages/proposal-details/index.tsx @@ -0,0 +1,11 @@ +import PageContainer from "lib/components/PageContainer"; + +import { ProposalDetailBody } from "./components/ProposalDetailsBody"; + +export const ProposalDetail = () => { + return ( + + + + ); +}; diff --git a/src/lib/pages/proposal-details/type.ts b/src/lib/pages/proposal-details/type.ts new file mode 100644 index 000000000..696cb4921 --- /dev/null +++ b/src/lib/pages/proposal-details/type.ts @@ -0,0 +1,9 @@ +export enum TabIndex { + Overview = "overview", + Vote = "vote", +} + +export enum VoteTabIndex { + Deposit = "deposit", + Voting = "voting", +} diff --git a/src/pages/[network]/proposals/[id]/[tab].tsx b/src/pages/[network]/proposals/[id]/[tab].tsx new file mode 100644 index 000000000..82a0c00d8 --- /dev/null +++ b/src/pages/[network]/proposals/[id]/[tab].tsx @@ -0,0 +1,3 @@ +import { ProposalDetail } from "lib/pages/proposal-details"; + +export default ProposalDetail; diff --git a/src/pages/[network]/proposals/[id]/index.tsx b/src/pages/[network]/proposals/[id]/index.tsx new file mode 100644 index 000000000..82a0c00d8 --- /dev/null +++ b/src/pages/[network]/proposals/[id]/index.tsx @@ -0,0 +1,3 @@ +import { ProposalDetail } from "lib/pages/proposal-details"; + +export default ProposalDetail; diff --git a/src/pages/proposals/[id]/[tab].tsx b/src/pages/proposals/[id]/[tab].tsx new file mode 100644 index 000000000..82a0c00d8 --- /dev/null +++ b/src/pages/proposals/[id]/[tab].tsx @@ -0,0 +1,3 @@ +import { ProposalDetail } from "lib/pages/proposal-details"; + +export default ProposalDetail; diff --git a/src/pages/proposals/[id]/index.tsx b/src/pages/proposals/[id]/index.tsx new file mode 100644 index 000000000..82a0c00d8 --- /dev/null +++ b/src/pages/proposals/[id]/index.tsx @@ -0,0 +1,3 @@ +import { ProposalDetail } from "lib/pages/proposal-details"; + +export default ProposalDetail; From af04e5dd498bc7d5b957b8152b421014c4a07188 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Mon, 22 Jan 2024 15:41:55 +0700 Subject: [PATCH 002/531] fix(components): add voting period component --- .../components/AllVotesTable.tsx | 39 +++++ .../components/DepositPeriodSection.tsx | 46 ++++++ .../components/ProposalDetailsBody.tsx | 60 ++++---- .../components/ProposalStepper.tsx | 9 +- .../components/ProposalTop.tsx | 4 +- .../components/ValidatorVotesTable.tsx | 41 ++++++ .../components/VoteDetail.tsx | 42 +++--- .../components/VoteDetailTab.tsx | 8 +- .../components/VotingPeriodSection.tsx | 134 ++++++++++++++++++ src/lib/pages/proposal-details/index.tsx | 10 +- 10 files changed, 319 insertions(+), 74 deletions(-) create mode 100644 src/lib/pages/proposal-details/components/AllVotesTable.tsx create mode 100644 src/lib/pages/proposal-details/components/DepositPeriodSection.tsx create mode 100644 src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx create mode 100644 src/lib/pages/proposal-details/components/VotingPeriodSection.tsx diff --git a/src/lib/pages/proposal-details/components/AllVotesTable.tsx b/src/lib/pages/proposal-details/components/AllVotesTable.tsx new file mode 100644 index 000000000..10d93cd3a --- /dev/null +++ b/src/lib/pages/proposal-details/components/AllVotesTable.tsx @@ -0,0 +1,39 @@ +import type { FlexProps } from "@chakra-ui/react"; +import { Button, Flex } from "@chakra-ui/react"; + +import { useMobile } from "lib/app-provider"; +import { CustomIcon } from "lib/components/icon"; +import { TableTitle } from "lib/components/table"; + +interface AllVotesTableProps extends FlexProps { + onBack: () => void; +} + +export const AllVotesTable = ({ onBack, ...props }: AllVotesTableProps) => { + const isMobile = useMobile(); + return ( + + + + + + + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/DepositPeriodSection.tsx b/src/lib/pages/proposal-details/components/DepositPeriodSection.tsx new file mode 100644 index 000000000..293a8832f --- /dev/null +++ b/src/lib/pages/proposal-details/components/DepositPeriodSection.tsx @@ -0,0 +1,46 @@ +import { Flex, Text } from "@chakra-ui/react"; + +import { useMobile } from "lib/app-provider"; +import { CustomIcon } from "lib/components/icon"; +import { TableTitle } from "lib/components/table"; +import { Tooltip } from "lib/components/Tooltip"; + +export const DepositPeriodSection = () => { + const isMobile = useMobile(); + return ( + + {!isMobile && ( + + + + + + Total Deposited + + + + + + )} + Depositor Tables Lorem ipsum dolor sit amet consectetur adipisicing elit. + Porro, soluta in molestias saepe vero possimus ullam tempora eum vitae + provident corporis ab eligendi non facilis quae consequatur beatae quo. + Nostrum! + + ); +}; diff --git a/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx b/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx index 7b94760d5..ea7ef3f4e 100644 --- a/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx +++ b/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx @@ -8,13 +8,9 @@ import { CustomTab } from "lib/components/CustomTab"; import { getFirstQueryParam } from "lib/utils"; import { ProposalOverview } from "./ProposalOverview"; -import { ProposalTop } from "./ProposalTop"; import { VoteDetail } from "./VoteDetail"; -interface ProposalDetailBodyProps { - id?: number; -} -export const ProposalDetailBody = ({ id = 123 }: ProposalDetailBodyProps) => { +export const ProposalDetailBody = ({ id }: { id: number }) => { const router = useRouter(); const navigate = useInternalNavigate(); @@ -26,7 +22,6 @@ export const ProposalDetailBody = ({ id = 123 }: ProposalDetailBodyProps) => { navigate({ pathname: "/proposals/[id]/[tab]", query: { - // To get from route id, tab: nextTab, }, @@ -55,34 +50,31 @@ export const ProposalDetailBody = ({ id = 123 }: ProposalDetailBodyProps) => { }, [router.isReady, tab, navigate, id]); return ( - <> - - + - - - Proposal Overview - - - Vote Detail - - - - - - - - - - - - + + Proposal Overview + + + Vote Detail + + + + + + + + + + + ); }; diff --git a/src/lib/pages/proposal-details/components/ProposalStepper.tsx b/src/lib/pages/proposal-details/components/ProposalStepper.tsx index 9a7263f48..4e0160cd2 100644 --- a/src/lib/pages/proposal-details/components/ProposalStepper.tsx +++ b/src/lib/pages/proposal-details/components/ProposalStepper.tsx @@ -4,27 +4,26 @@ interface ProposalStepperProps { title: string; description: string; step: number; - isSelected?: boolean; } export const ProposalStepper = ({ title, description, step, - isSelected, }: ProposalStepperProps) => { return ( + {/* TODO: Color changes when state changes */} {step} diff --git a/src/lib/pages/proposal-details/components/ProposalTop.tsx b/src/lib/pages/proposal-details/components/ProposalTop.tsx index 971cf8d6c..24b3218f9 100644 --- a/src/lib/pages/proposal-details/components/ProposalTop.tsx +++ b/src/lib/pages/proposal-details/components/ProposalTop.tsx @@ -1,5 +1,5 @@ import { Flex } from "@chakra-ui/react"; -export const ProposalTop = () => { - return proposal top; +export const ProposalTop = ({ id }: { id: number }) => { + return {id} proposal top; }; diff --git a/src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx b/src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx new file mode 100644 index 000000000..249f3d555 --- /dev/null +++ b/src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx @@ -0,0 +1,41 @@ +import type { FlexProps } from "@chakra-ui/react"; +import { Button, Flex } from "@chakra-ui/react"; + +import { useMobile } from "lib/app-provider"; +import { CustomIcon } from "lib/components/icon"; +import { TableTitle } from "lib/components/table"; + +interface ValidatorVotesTableProps extends FlexProps { + onBack: () => void; +} +export const ValidatorVotesTable = ({ + onBack, + ...props +}: ValidatorVotesTableProps) => { + const isMobile = useMobile(); + return ( + + + + + + + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/VoteDetail.tsx b/src/lib/pages/proposal-details/components/VoteDetail.tsx index 9be6d6bc8..76d790169 100644 --- a/src/lib/pages/proposal-details/components/VoteDetail.tsx +++ b/src/lib/pages/proposal-details/components/VoteDetail.tsx @@ -14,8 +14,10 @@ import type { ReactNode } from "react"; import { useMobile } from "lib/app-provider"; +import { DepositPeriodSection } from "./DepositPeriodSection"; import { ProposalStepper } from "./ProposalStepper"; import { VoteDetailTab } from "./VoteDetailTab"; +import { VotingPeriodSection } from "./VotingPeriodSection"; const AccordionItemComponent = ({ step, @@ -29,28 +31,19 @@ const AccordionItemComponent = ({ children: ReactNode; }) => ( - {({ isExpanded }) => ( - <> - - - - - - {children} - - - )} + + + + + + {children} + ); @@ -61,13 +54,13 @@ export const VoteDetail = () => { step: 1, title: "Deposit Period", description: "Deposit ends in 4 days 21:00:11", - content: Deposit Period Content, + content: , }, { step: 2, title: "Voting Period", description: "Voting ends in 3 days 12:00:10", - content: Voting Period Content, + content: , }, ]; return isMobile ? ( @@ -96,7 +89,6 @@ export const VoteDetail = () => { { const tabProps = useTab({ ...restProps }); - const isSelected = tabProps["aria-selected"]; const styles = useMultiStyleConfig("Tabs", tabProps); return ( @@ -60,12 +59,7 @@ export const VoteDetailTab = ({ }} {...tabProps} > - + ); }; diff --git a/src/lib/pages/proposal-details/components/VotingPeriodSection.tsx b/src/lib/pages/proposal-details/components/VotingPeriodSection.tsx new file mode 100644 index 000000000..72ea46c16 --- /dev/null +++ b/src/lib/pages/proposal-details/components/VotingPeriodSection.tsx @@ -0,0 +1,134 @@ +import { Button, Flex, Grid, GridItem, useDisclosure } from "@chakra-ui/react"; +import type { ReactNode } from "react"; + +import { useMobile } from "lib/app-provider"; +import { CustomIcon } from "lib/components/icon"; +import { TableTitle } from "lib/components/table"; + +import { AllVotesTable } from "./AllVotesTable"; +import { ValidatorVotesTable } from "./ValidatorVotesTable"; + +export const ContentContainer = ({ + children, + hasSubSection, +}: { + children: ReactNode; + hasSubSection?: boolean; +}) => { + const isMobile = useMobile(); + return ( + + {children} + + ); +}; + +export const VotingPeriodSection = () => { + const isMobile = useMobile(); + const validatorVoteDisclosure = useDisclosure(); + const allVoteDisclosure = useDisclosure(); + + return ( + + + {/* Vote Participations */} + + {!isMobile && } + Vote Participations Lorem ipsum dolor sit amet consectetur adipisicing + elit. Soluta pariatur eveniet ducimus quasi veritatis labore aut + minima adipisci sit sed ratione laboriosam dolorum suscipit tenetur + reiciendis voluptatum, aliquid quam ullam! + + {/* Vote Results */} + + {!isMobile && } + Vote Results Lorem ipsum dolor sit amet consectetur adipisicing elit. + Soluta pariatur eveniet ducimus quasi veritatis labore aut minima + adipisci sit sed ratione laboriosam dolorum suscipit tenetur + reiciendis voluptatum, aliquid quam ullam! + + + {/* Validator Votes */} + + + + + + + Validator Votes Lorem ipsum dolor, sit amet consectetur + adipisicing elit. Necessitatibus ipsam perspiciatis eius illo + maiores, magnam architecto nesciunt esse animi obcaecati + voluptates delectus doloribus magni alias a eligendi odio nam + iure? + + + {/* Recent Votes */} + + + + + + + Recent Votes Lorem ipsum dolor, sit amet consectetur adipisicing + elit. Necessitatibus ipsam perspiciatis eius illo maiores, magnam + architecto nesciunt esse animi obcaecati voluptates delectus + doloribus magni alias a eligendi odio nam iure? + + + + + + + + ); +}; diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index 52153d98d..2f8b055b2 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -1,11 +1,19 @@ +import { useRouter } from "next/router"; + import PageContainer from "lib/components/PageContainer"; +import { EmptyState } from "lib/components/state"; import { ProposalDetailBody } from "./components/ProposalDetailsBody"; +import { ProposalTop } from "./components/ProposalTop"; export const ProposalDetail = () => { + const router = useRouter(); + const proposalId = parseInt(router.query.id as string, 10); + if (!proposalId) return ; return ( - + + ); }; From 7b3ce3043a684d7b109f16b84ee5c1bae750dd71 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Mon, 22 Jan 2024 18:38:12 +0700 Subject: [PATCH 003/531] feat(components): add proposal top --- CHANGELOG.md | 1 + package.json | 5 +- pnpm-lock.yaml | 1864 +++++++++++++++-- .../components/ProposalInfo.tsx | 155 ++ .../components/ProposalTop.tsx | 175 +- .../__stories__/ProposalInfo.stories.ts | 88 + 6 files changed, 2090 insertions(+), 198 deletions(-) create mode 100644 src/lib/pages/proposal-details/components/ProposalInfo.tsx create mode 100644 src/lib/pages/proposal-details/components/__stories__/ProposalInfo.stories.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 6eb511b36..b44cad460 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#745](https://github.com/alleslabs/celatone-frontend/pull/745) Add proposal top - [#731](https://github.com/alleslabs/celatone-frontend/pull/731) Add proposal detail page structure ### Improvements diff --git a/package.json b/package.json index 465514507..7b8a3ec72 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "build-storybook": "storybook build" }, "resolutions": { - "@interchain-ui/react": "1.11.4", + "@interchain-ui/react": "1.20.7", "chakra-react-select": "^4.7.0" }, "dependencies": { @@ -71,7 +71,7 @@ "@graphql-typed-document-node/core": "^3.2.0", "@initia/initia.js": "0.1.12", "@initia/initia.proto": "0.1.12", - "@interchain-ui/react": "1.11.4", + "@interchain-ui/react": "1.20.7", "@monaco-editor/react": "^4.6.0", "@rjsf/chakra-ui": "v5.0.0-beta.10", "@rjsf/core": "v5.0.0-beta.10", @@ -159,6 +159,7 @@ "next-sitemap": "^3.1.25", "prettier": "^3.0.3", "storybook": "^7.6.9", + "storybook-react-context": "^0.6.0", "ts-jest": "^29.0.5", "typescript": "^5.1.6" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b73d1cc5..161c1f440 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - '@interchain-ui/react': 1.11.4 + '@interchain-ui/react': 1.20.7 chakra-react-select: ^4.7.0 dependencies: @@ -71,7 +71,7 @@ dependencies: version: 2.7.2(@cosmjs/amino@0.32.2)(@cosmjs/proto-signing@0.32.2) '@cosmos-kit/react': specifier: 2.10.2 - version: 2.10.2(@interchain-ui/react@1.11.4)(react-dom@18.2.0)(react@18.2.0) + version: 2.10.2(@interchain-ui/react@1.20.7)(react-dom@18.2.0)(react@18.2.0) '@cosmos-kit/station': specifier: 2.5.2 version: 2.5.2(@cosmjs/amino@0.32.2)(@cosmjs/proto-signing@0.32.2)(@terra-money/terra.js@3.1.10)(axios@1.6.5) @@ -97,8 +97,8 @@ dependencies: specifier: 0.1.12 version: 0.1.12 '@interchain-ui/react': - specifier: 1.11.4 - version: 1.11.4(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + specifier: 1.20.7 + version: 1.20.7(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) '@monaco-editor/react': specifier: ^4.6.0 version: 4.6.0(monaco-editor@0.44.0)(react-dom@18.2.0)(react@18.2.0) @@ -356,6 +356,9 @@ devDependencies: storybook: specifier: ^7.6.9 version: 7.6.9 + storybook-react-context: + specifier: ^0.6.0 + version: 0.6.0(react-dom@18.2.0) ts-jest: specifier: ^29.0.5 version: 29.1.1(@babel/core@7.23.7)(esbuild@0.18.20)(jest@29.7.0)(typescript@5.3.3) @@ -3519,17 +3522,17 @@ packages: - utf-8-validate dev: false - /@cosmos-kit/react@2.10.2(@interchain-ui/react@1.11.4)(react-dom@18.2.0)(react@18.2.0): + /@cosmos-kit/react@2.10.2(@interchain-ui/react@1.20.7)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-+/YCETixxhMc1P/cyKdNbqjgT728Nn7Y0aWqH7VbTGANS5NvCIlk82VPlXH7ybYRApBdsG8rJ1Sc/n3kAgdk4g==} peerDependencies: - '@interchain-ui/react': 1.11.4 + '@interchain-ui/react': 1.20.7 react: ^18 react-dom: ^18 dependencies: '@chain-registry/types': 0.17.0 '@cosmos-kit/core': 2.8.2 '@cosmos-kit/react-lite': 2.6.2(react-dom@18.2.0)(react@18.2.0) - '@interchain-ui/react': 1.11.4(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@interchain-ui/react': 1.20.7(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) '@react-icons/all-files': 4.1.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4347,8 +4350,42 @@ packages: /@floating-ui/utils@0.2.1: resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} - /@formkit/auto-animate@1.0.0-beta.6: - resolution: {integrity: sha512-PVDhLAlr+B4Xb7e+1wozBUWmXa6BFU8xUPR/W/E+TsQhPS1qkAdAsJ25keEnFrcePSnXHrOsh3tiFbEToOzV9w==} + /@formatjs/ecma402-abstract@1.18.2: + resolution: {integrity: sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==} + dependencies: + '@formatjs/intl-localematcher': 0.5.4 + tslib: 2.6.2 + dev: false + + /@formatjs/fast-memoize@2.2.0: + resolution: {integrity: sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==} + dependencies: + tslib: 2.6.2 + dev: false + + /@formatjs/icu-messageformat-parser@2.7.5: + resolution: {integrity: sha512-zCB53HdGDibh6/2ISEN3TGsFQruQ6gGKMFV94qHNyVrs0tNO6ncKhV0vq0n3Ydz8ipIQ2GaYAvfCoimNOVvKqA==} + dependencies: + '@formatjs/ecma402-abstract': 1.18.2 + '@formatjs/icu-skeleton-parser': 1.7.2 + tslib: 2.6.2 + dev: false + + /@formatjs/icu-skeleton-parser@1.7.2: + resolution: {integrity: sha512-nlIXVv280bjGW3ail5Np1+xgGKBnMhwQQIivgbk9xX0af8ESQO+y2VW9TOY7mCrs3WH786uVpZlLimXAlXH7SA==} + dependencies: + '@formatjs/ecma402-abstract': 1.18.2 + tslib: 2.6.2 + dev: false + + /@formatjs/intl-localematcher@0.5.4: + resolution: {integrity: sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==} + dependencies: + tslib: 2.6.2 + dev: false + + /@formkit/auto-animate@0.8.1: + resolution: {integrity: sha512-0/Z2cuNXWVVIG/l0SpcHAWFhGdvLJ8DRvEfRWvmojtmRWfEy+LWNwgDazbZqY0qQYtkHcoEK3jBLkhiZaB/4Ig==} dev: false /@graphql-codegen/cli@5.0.0(@types/node@20.11.5)(graphql@16.8.1)(typescript@5.3.3): @@ -4881,8 +4918,8 @@ packages: zod: 3.22.4 dev: false - /@interchain-ui/react@1.11.4(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-jUx02LyyUjSKANcpNJ9DPOkVlD2nERmQZsqEnUeJQ6wsG4rgO5yd0jHDUgqotvwxkRisYSy8jqDGe3r4pYsNBw==} + /@interchain-ui/react@1.20.7(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-356bhFYCWpokHcjXM5pYcWWsXjqG+fjnT8r3w9qjLmqMRVqJMp/m0vAB3OqlaejPKA0NIusnOfCSM6UwvdH09A==} peerDependencies: react: ^18.x react-dom: ^18.x @@ -4890,27 +4927,53 @@ packages: '@fastify/deepmerge': 1.3.0 '@floating-ui/dom': 1.5.4 '@floating-ui/react': 0.26.6(react-dom@18.2.0)(react@18.2.0) - '@formkit/auto-animate': 1.0.0-beta.6 + '@formkit/auto-animate': 0.8.1 + '@react-aria/utils': 3.23.0(react@18.2.0) '@vanilla-extract/css': 1.14.0 - '@vanilla-extract/css-utils': 0.1.3 '@vanilla-extract/dynamic': 2.1.0 - '@vanilla-extract/recipes': 0.4.0(@vanilla-extract/css@1.14.0) - '@zag-js/number-input': 0.15.0 - '@zag-js/react': 0.15.0(react-dom@18.2.0)(react@18.2.0) + '@vanilla-extract/recipes': 0.5.1(@vanilla-extract/css@1.14.0) animejs: 3.2.2 bignumber.js: 9.1.2 + client-only: 0.0.1 clsx: 1.2.1 copy-to-clipboard: 3.3.3 immer: 9.0.21 lodash: 4.17.21 rainbow-sprinkles: 0.17.1(@vanilla-extract/css@1.14.0)(@vanilla-extract/dynamic@2.1.0) react: 18.2.0 + react-aria: 3.31.1(react-dom@18.2.0)(react@18.2.0) react-dom: 18.2.0(react@18.2.0) + react-stately: 3.29.1(react@18.2.0) zustand: 4.4.7(@types/react@18.2.48)(immer@9.0.21)(react@18.2.0) transitivePeerDependencies: - '@types/react' dev: false + /@internationalized/date@3.5.1: + resolution: {integrity: sha512-LUQIfwU9e+Fmutc/DpRTGXSdgYZLBegi4wygCWDSVmUdLTaMHsQyASDiJtREwanwKuQLq0hY76fCJ9J/9I2xOQ==} + dependencies: + '@swc/helpers': 0.5.2 + dev: false + + /@internationalized/message@3.1.1: + resolution: {integrity: sha512-ZgHxf5HAPIaR0th+w0RUD62yF6vxitjlprSxmLJ1tam7FOekqRSDELMg4Cr/DdszG5YLsp5BG3FgHgqquQZbqw==} + dependencies: + '@swc/helpers': 0.5.2 + intl-messageformat: 10.5.10 + dev: false + + /@internationalized/number@3.5.0: + resolution: {integrity: sha512-ZY1BW8HT9WKYvaubbuqXbbDdHhOUMfE2zHHFJeTppid0S+pc8HtdIxFxaYMsGjCb4UsF+MEJ4n2TfU7iHnUK8w==} + dependencies: + '@swc/helpers': 0.5.2 + dev: false + + /@internationalized/string@3.2.0: + resolution: {integrity: sha512-Xx3Sy3f2c9ctT+vh8c7euEaEHQZltp0euZ3Hy4UfT3E13r6lxpUS3kgKyumEjboJZSnaZv7JhqWz3D75v+IxQg==} + dependencies: + '@swc/helpers': 0.5.2 + dev: false + /@ioredis/commands@1.2.0: resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} dev: false @@ -6238,113 +6301,1331 @@ packages: '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) '@types/react': 18.2.48 react: 18.2.0 - dev: true + dev: true + + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/rect': 1.0.1 + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-use-size@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true + + /@radix-ui/rect@1.0.1: + resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + dependencies: + '@babel/runtime': 7.23.8 + dev: true + + /@react-aria/breadcrumbs@3.5.9(react@18.2.0): + resolution: {integrity: sha512-asbXTL5NjeHl1+YIF0K70y8tNHk8Lb6VneYH8yOkpLO49ejyNDYBK0tp0jtI9IZAQiTa2qkhYq58c9LloTwebQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/link': 3.6.3(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/breadcrumbs': 3.7.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/button@3.9.1(react@18.2.0): + resolution: {integrity: sha512-nAnLMUAnwIVcRkKzS1G2IU6LZSkIWPJGu9amz/g7Y02cGUwFp3lk5bEw2LdoaXiSDJNSX8g0SZFU8FROg57jfQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/toggle': 3.7.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/calendar@3.5.4(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-8k7khgea5kwfWriZJWCADNB0R2d7g5A6tTjUEktK4FFZcTb0RCubFejts4hRyzKlF9XHUro2dfh6sbZrzfMKDQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/calendar': 3.4.3(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/calendar': 3.4.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/checkbox@3.13.0(react@18.2.0): + resolution: {integrity: sha512-eylJwtADIPKJ1Y5rITNJm/8JD8sXG2nhiZBIg1ko44Szxrpu+Le53NoGtg8nlrfh9vbUrXVvuFtf2jxbPXR5Jw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/form': 3.0.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/toggle': 3.10.0(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/checkbox': 3.6.1(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/toggle': 3.7.0(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/combobox@3.8.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-q8Kdw1mx6nSSydXqRagRuyKH1NPGvpSOFjUfgxdO8ZqaEEuZX3ObOoiO/DLtXDndViNc03dMbMpfuJoLYXfCtg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/listbox': 3.11.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/menu': 3.12.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/textfield': 3.14.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/combobox': 3.8.1(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/combobox': 3.10.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/datepicker@3.9.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-bdlY2H/zwe3hQf64Lp1oGTf7Va8ennDyAv4Ffowb+BOoL8+FB9smtGyONKe87zXu7VJL2M5xYAi4n7c004PM+w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@internationalized/number': 3.5.0 + '@internationalized/string': 3.2.0 + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/form': 3.0.1(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/spinbutton': 3.6.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/datepicker': 3.9.1(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/calendar': 3.4.3(react@18.2.0) + '@react-types/datepicker': 3.7.1(react@18.2.0) + '@react-types/dialog': 3.5.7(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/dialog@3.5.10(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-H2BNVLOfaum6/4irH5XUU/wIcXSs/ymxmTPGmucRG1hzaUh8H3tupdl/qCZ+SsW9oYDFlphY172uM1nsPjBMiQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/dialog': 3.5.7(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/dnd@3.5.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-7OPGePdle+xNYHAIAUOvIETRMfnkRt7h/C0bCkxUR2GYefEbTzfraso4ppNH2JZ7fCRd0K/Qe+jvQklwusHAKA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/string': 3.2.0 + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/dnd': 3.2.7(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/focus@3.16.0(react@18.2.0): + resolution: {integrity: sha512-GP6EYI07E8NKQQcXHjpIocEU0vh0oi0Vcsd+/71fKS0NnTR0TUOEeil0JuuQ9ymkmPDTu51Aaaa4FxVsuN/23A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + clsx: 2.1.0 + react: 18.2.0 + dev: false + + /@react-aria/form@3.0.1(react@18.2.0): + resolution: {integrity: sha512-6586oODMDR4/ciGRwXjpvEAg7tWGSDrXE//waK0n5e5sMuzlPOo1DHc5SpPTvz0XdJsu6VDt2rHdVWVIC9LEyw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/grid@3.8.6(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-JlQDkdm5heG1FfRyy5KnB8b6s/hRqSI6Xt2xN2AccLX5kcbfFr2/d5KVxyf6ahfa4Gfd46alN6477ju5eTWJew==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/grid': 3.8.4(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-stately/virtualizer': 3.6.6(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@react-types/grid': 3.2.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/gridlist@3.7.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-rkkepYM7xJiebR0g3uC4zzkdR7a8z0fLaM+sg9lSTbdElHMLAlrebS2ytEyZnhiu9nbOnw13GN1OC4/ZenzbHQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/grid': 3.8.6(react-dom@18.2.0)(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/i18n@3.10.0(react@18.2.0): + resolution: {integrity: sha512-sviD5Y1pLPG49HHRmVjR+5nONrp0HK219+nu9Y7cDfUhXu2EjyhMS9t/n9/VZ69hHChZ2PnHYLEE2visu9CuCg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@internationalized/message': 3.1.1 + '@internationalized/number': 3.5.0 + '@internationalized/string': 3.2.0 + '@react-aria/ssr': 3.9.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/interactions@3.20.1(react@18.2.0): + resolution: {integrity: sha512-PLNBr87+SzRhe9PvvF9qvzYeP4ofTwfKSorwmO+hjr3qoczrSXf4LRQlb27wB6hF10C7ZE/XVbUI1lj4QQrZ/g==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/ssr': 3.9.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/label@3.7.4(react@18.2.0): + resolution: {integrity: sha512-3Y0yyrqpLzZdzHw+TOyzwuyx5wa2ujU5DGfKuL5GFnU9Ii4DtdwBGSYS7Yu7qadU+eQmG4OGhAgFVswbIgIwJw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/link@3.6.3(react@18.2.0): + resolution: {integrity: sha512-8kPWc4u/lDow3Ll0LDxeMgaxt9Y3sl8UldKLGli8tzRSltYFugNh/n+i9sCnmo4Qv9Tp9kYv+yxBK50Uk9sINw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/link': 3.5.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/listbox@3.11.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-PBrnldmyEYUUJvfDeljW8ITvZyBTfGpLNf0b5kfBPK3TDgRH4niEH2vYEcaZvSqb0FrpdvcunuTRXcOpfb+gCQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-types/listbox': 3.4.6(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/live-announcer@3.3.1: + resolution: {integrity: sha512-hsc77U7S16trM86d+peqJCOCQ7/smO1cybgdpOuzXyiwcHQw8RQ4GrXrS37P4Ux/44E9nMZkOwATQRT2aK8+Ew==} + dependencies: + '@swc/helpers': 0.5.2 + dev: false + + /@react-aria/menu@3.12.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Nsujv3b61WR0gybDKnBjAeyxDVJOfPLMggRUf9SQDfPWnrPXEsAFxaPaVcAkzlfI4HiQs1IxNwsKFNpc3PPZTQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/menu': 3.6.0(react@18.2.0) + '@react-stately/tree': 3.7.5(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/menu': 3.9.6(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/meter@3.4.9(react@18.2.0): + resolution: {integrity: sha512-1/FHFmFmSyfQBJ2oH152lp4nps76v1UdhnFbIsmRIH+0g0IfMv1yDT2M9dIZ/b9DgVZSx527FmWOXm0eHGKD6w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/progress': 3.4.9(react@18.2.0) + '@react-types/meter': 3.3.6(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/numberfield@3.10.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-KjGTXq3lIhN4DEdEeHzfS/k9Qq0sDEpLgLr/hgSfGN4Q7Syu4Ck/n2HXmrDn//z08/wNvcukuP6Ioers138DcQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/spinbutton': 3.6.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/textfield': 3.14.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/numberfield': 3.8.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/numberfield': 3.7.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/overlays@3.20.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-2m7MpRJL5UucbEuu08lMHsiFJoDowkJV4JAIFBZYK1NzVH0vF/A+w9HRNM7jRwx2DUxE+iIsZnl8yKV/7KY8OQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/ssr': 3.9.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-aria/visually-hidden': 3.8.8(react@18.2.0) + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/overlays': 3.8.4(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/progress@3.4.9(react@18.2.0): + resolution: {integrity: sha512-CME1ZLsJHOmSgK8IAPOC/+vYO5Oc614mkEw5MluT/yclw5rMyjAkK1XsHLjEXy81uwPeiRyoQQIMPKG2/sMxFQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/progress': 3.5.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/radio@3.10.0(react@18.2.0): + resolution: {integrity: sha512-6NaKzdGymdcVWLYgHT0cHsVmNzPOp89o8r41w29OPBQWu8w2c9mxg4366OiIZn/uXIBS4abhQ4nL4toBRLgBrg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/form': 3.0.1(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/radio': 3.10.1(react@18.2.0) + '@react-types/radio': 3.7.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/searchfield@3.7.1(react@18.2.0): + resolution: {integrity: sha512-ebhnV/reNByIZzpcQLHIo1RQ+BrYS8HdwX624i9R7dep1gxGHXYEaqL9aSY+RdngNerB4OeiWmB75em9beSpjQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/textfield': 3.14.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/searchfield': 3.5.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/searchfield': 3.5.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/select@3.14.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-pAy/+Xbj11Lx6bi/O1hWH0NSIDRxFb6V7N0ry2L8x7MALljh516VbpnAc5RgvbjbuKq0cHUAcdINOzOzpYWm4A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/form': 3.0.1(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/listbox': 3.11.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/menu': 3.12.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-aria/visually-hidden': 3.8.8(react@18.2.0) + '@react-stately/select': 3.6.1(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/select': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/selection@3.17.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-xl2sgeGH61ngQeE05WOWWPVpGRTPMjQEFmsAWEprArFi4Z7ihSZgpGX22l1w7uSmtXM/eN/v0W8hUYUju5iXlQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/separator@3.3.9(react@18.2.0): + resolution: {integrity: sha512-1wEXiaSJjq2+DR5TC0RKnUBsfZN+YXTzyI7XMzjQoc3YlclumX8wQtzPAOGOEjHB1JKUgo1Gw70FtupVXz58QQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/slider@3.7.4(react@18.2.0): + resolution: {integrity: sha512-OFJWeGSL2duVDFs/kcjlWsY6bqCVKZgM0aFn2QN4wmID+vfBvBnqGHAgWv3BCePTAPS3+GBjMN002TrftorjwQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/slider': 3.5.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/slider': 3.7.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/spinbutton@3.6.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-u5GuOP3k4Zis055iY0fZJNHU7dUNCoSfUq5LKwJ1iNaCqDcavdstAnAg+X1a7rhpp5zCnJmAMseo3Qmzi9P+Ew==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/ssr@3.9.1(react@18.2.0): + resolution: {integrity: sha512-NqzkLFP8ZVI4GSorS0AYljC13QW2sc8bDqJOkBvkAt3M8gbcAXJWVRGtZBCRscki9RZF+rNlnPdg0G0jYkhJcg==} + engines: {node: '>= 12'} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/switch@3.6.0(react@18.2.0): + resolution: {integrity: sha512-YNWc5fGLNXE4XlmDAKyqAdllRiClGR7ki4KGFY7nL+xR5jxzjCGU3S3ToMK5Op3QSMGZLxY/aYmC4O+MvcoADQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/toggle': 3.10.0(react@18.2.0) + '@react-stately/toggle': 3.7.0(react@18.2.0) + '@react-types/switch': 3.5.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/table@3.13.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-AzmETpyxwNqISTzwHJPs85x9gujG40IIsSOBUdp49oKhB85RbPLvMwhadp4wCVAoHw3erOC/TJxHtVc7o2K1LA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/grid': 3.8.6(react-dom@18.2.0)(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-aria/visually-hidden': 3.8.8(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/flags': 3.0.0 + '@react-stately/table': 3.11.4(react@18.2.0) + '@react-stately/virtualizer': 3.6.6(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@react-types/grid': 3.2.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/table': 3.9.2(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/tabs@3.8.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Plw0K/5Qv35vYq7pHZFfQB2BF5OClFx4Abzo9hLVx4oMy3qb7i5lxmLBVbt81yPX/MdjYeP4zO1EHGBl4zMRhA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/tabs': 3.6.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/tabs': 3.3.4(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/tag@3.3.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-w7d8sVZqxTo8VFfeg2ixLp5kawtrcguGznVY4mt5aE6K8LMJOeNVDqNNfolfyia80VjOWjeX+RpVdVJRdrv/GQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/gridlist': 3.7.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/textfield@3.14.1(react@18.2.0): + resolution: {integrity: sha512-UMepuYtDdCgrUF4dMphNxrUm23xOmR54aZD1pbp9cJyfioVkJN35BTXZVkD0D07gHLn4RhxKIZxBortQQrLB9g==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/form': 3.0.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/textfield': 3.9.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/toggle@3.10.0(react@18.2.0): + resolution: {integrity: sha512-6cUf4V9TuG2J7AvXUdU/GspEPFCubUOID3mrselSe563RViy+mMZk0vUEOdyoNanDcEXl58W4dE3SGWxFn71vg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/toggle': 3.7.0(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/tooltip@3.7.0(react@18.2.0): + resolution: {integrity: sha512-+u9Sftkfe09IDyPEnbbreFKS50vh9X/WTa7n1u2y3PenI9VreLpUR6czyzda4BlvQ95e9jQz1cVxUjxTNaZmBw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/tooltip': 3.4.6(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/tooltip': 3.4.6(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/utils@3.23.0(react@18.2.0): + resolution: {integrity: sha512-fJA63/VU4iQNT8WUvrmll3kvToqMurD69CcgVmbQ56V7ZbvlzFi44E7BpnoaofScYLLtFWRjVdaHsohT6O/big==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/ssr': 3.9.1(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + clsx: 2.1.0 + react: 18.2.0 + dev: false + + /@react-aria/visually-hidden@3.8.8(react@18.2.0): + resolution: {integrity: sha512-Cn2PYKD4ijGDtF0+dvsh8qa4y7KTNAlkTG6h20r8Q+6UTyRNmtE2/26QEaApRF8CBiNy9/BZC/ZC4FK2OjvCoA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-icons/all-files@4.1.0(react@18.2.0): + resolution: {integrity: sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==} + peerDependencies: + react: '*' + dependencies: + react: 18.2.0 + dev: false + + /@react-stately/calendar@3.4.3(react@18.2.0): + resolution: {integrity: sha512-OrEcdskszDjnjVnFuSiDC2PVBJ6lWMCJROD5s6W1LUehUtBp8LX9wPavAGHV43LbhN9ldj560sxaQ4WCddrRCA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/calendar': 3.4.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/checkbox@3.6.1(react@18.2.0): + resolution: {integrity: sha512-rOjFeVBy32edYwhKiHj3ZLdLeO+xZ2fnBwxnOBjcygnw4Neygm8FJH/dB1J0hdYYR349yby86ED2x0wRc84zPw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/collections@3.10.4(react@18.2.0): + resolution: {integrity: sha512-OHhCrItGt4zB2bSrgObRo0H2SC7QlkH8ReGxo+NVIWchXRLRoiWBP7S+IwleewEo5gOqDVPY3hqA9n4iiI8twg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/combobox@3.8.1(react@18.2.0): + resolution: {integrity: sha512-FaWkqTXQdWg7ptaeU4iPcqF/kxbRg2ZNUcvW/hiL/enciV5tRCsddvfNqvDvy1L30z9AUwlp9MWqzm/DhBITCw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-stately/select': 3.6.1(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/combobox': 3.10.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/data@3.11.0(react@18.2.0): + resolution: {integrity: sha512-0BlPT58WrAtUvpiEfUuyvIsGFTzp/9vA5y+pk53kGJhOdc5tqBGHi9cg40pYE/i1vdHJGMpyHGRD9nkQb8wN3Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/datepicker@3.9.1(react@18.2.0): + resolution: {integrity: sha512-o5xLvlZGJyAbTev2yruGlV2fzQyIDuYTgL19TTt0W0WCfjGGr/AAA9GjGXXmyoRA7sZMxqIPnnv7lNrdA38ofA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@internationalized/string': 3.2.0 + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/datepicker': 3.7.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/dnd@3.2.7(react@18.2.0): + resolution: {integrity: sha512-QqSCvE9Rhp+Mr8Mt/SrByze24BFX1cy7gmXbwoqAYgHNIx3gWCVdBLqxfpfgYIhZdF9H72EWS8lQkfkZla06Ng==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/flags@3.0.0: + resolution: {integrity: sha512-e3i2ItHbIa0eEwmSXAnPdD7K8syW76JjGe8ENxwFJPW/H1Pu9RJfjkCb/Mq0WSPN/TpxBb54+I9TgrGhbCoZ9w==} + dependencies: + '@swc/helpers': 0.4.36 + dev: false + + /@react-stately/form@3.0.0(react@18.2.0): + resolution: {integrity: sha512-C8wkfFmtx1escizibhdka5JvTy9/Vp173CS9cakjvWTmnjYYC1nOlzwp7BsYWTgerCFbRY/BU/Cf/bJDxPiUKQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/grid@3.8.4(react@18.2.0): + resolution: {integrity: sha512-rwqV1K4lVhaiaqJkt4TfYqdJoVIyqvSm98rKAYfCNzrKcivVpoiCMJ2EMt6WlYCjDVBdEOQ7fMV1I60IV0pntA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-types/grid': 3.2.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/list@3.10.2(react@18.2.0): + resolution: {integrity: sha512-INt+zofkIg2KN8B95xPi9pJG7ZFWAm30oIm/lCPBqM3K1Nm03/QaAbiQj2QeJcOsG3lb7oqI6D6iwTolwJkjIQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/menu@3.6.0(react@18.2.0): + resolution: {integrity: sha512-OB6CjNyfOkAuirqx1oTL8z8epS9WDzLyrXjmRnxdiCU9EgRXLGAQNECuO7VIpl58oDry8tgRJiJ8fn8FivWSQA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-types/menu': 3.9.6(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/numberfield@3.8.0(react@18.2.0): + resolution: {integrity: sha512-1XvB8tDOvZKcFnMM6qNLEaTVJcIc0jRFS/9jtS8MzalZvh8DbKi0Ucm1bGU7S5rkCx2QWqZ0rGOIm2h/RlcpkA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/number': 3.5.0 + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/numberfield': 3.7.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/overlays@3.6.4(react@18.2.0): + resolution: {integrity: sha512-tHEaoAGpE9dSnsskqLPVKum59yGteoSqsniTopodM+miQozbpPlSjdiQnzGLroy5Afx5OZYClE616muNHUILXA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/overlays': 3.8.4(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/radio@3.10.1(react@18.2.0): + resolution: {integrity: sha512-MsBYbcLCvjKsqTAKe43T681F2XwKMsS7PLG0eplZgWP9210AMY78GeY1XPYZKHPAau8XkbYiuJqbqTerIJ3DBw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/radio': 3.7.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/searchfield@3.5.0(react@18.2.0): + resolution: {integrity: sha512-SStjChkn/33pEn40slKQPnBnmQYyxVazVwPjiBkdeVejC42lUVairUTrGJgF0PNoZTbxn0so2/XzjqTC9T8iCw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/searchfield': 3.5.2(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/select@3.6.1(react@18.2.0): + resolution: {integrity: sha512-e5ixtLiYLlFWM8z1msDqXWhflF9esIRfroptZsltMn1lt2iImUlDRlOTZlMtPQzUrDWoiHXRX88sSKUM/jXjQQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-types/select': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/selection@3.14.2(react@18.2.0): + resolution: {integrity: sha512-mL7OoiUgVWaaF7ks5XSxgbXeShijYmD4G3bkBHhqkpugU600QH6BM2hloCq8KOUupk1y8oTljPtF9EmCv375DA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/slider@3.5.0(react@18.2.0): + resolution: {integrity: sha512-dOVpIxb7XKuiRxgpHt1bUSlsklciFki100tKIyBPR+Okar9iC/CwLYROYgVfLkGe77jEBNkor9tDLjDGEWcc1w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/slider': 3.7.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/table@3.11.4(react@18.2.0): + resolution: {integrity: sha512-dWINJIEOKQl4qq3moq+S8xCD3m+yJqBj0dahr+rOkS+t2uqORwzsusTM35D2T/ZHZi49S2GpE7QuDa+edCynPw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/flags': 3.0.0 + '@react-stately/grid': 3.8.4(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/grid': 3.2.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/table': 3.9.2(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/tabs@3.6.3(react@18.2.0): + resolution: {integrity: sha512-Nj+Gacwa2SIzYIvHW40GsyX4Q6c8kF7GOuXESeQswbCjnwqhrSbDBp+ngPcUPUJxqFh6JhDCVwAS3wMhUoyUwA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/tabs': 3.3.4(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/toggle@3.7.0(react@18.2.0): + resolution: {integrity: sha512-TRksHkCJk/Xogq4181g3CYgJf+EfsJCqX5UZDSw1Z1Kgpvonjmdf6FAfQfCh9QR2OuXUL6hOLUDVLte5OPI+5g==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/tooltip@3.4.6(react@18.2.0): + resolution: {integrity: sha512-uL93bmsXf+OOgpKLPEKfpDH4z+MK2CuqlqVxx7rshN0vjWOSoezE5nzwgee90+RpDrLNNNWTNa7n+NkDRpI1jA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-types/tooltip': 3.4.6(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/tree@3.7.5(react@18.2.0): + resolution: {integrity: sha512-xTJVwvhAeY0N5rui4N/TxN7f8hjXdqApDuGDxMZeFAWoQz8Abf7LFKBVQ3OkT6qVr7P+23dgoisUDBhD5a45Hg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/utils@3.9.0(react@18.2.0): + resolution: {integrity: sha512-yPKFY1F88HxuZ15BG2qwAYxtpE4HnIU0Ofi4CuBE0xC6I8mwo4OQjDzi+DZjxQngM9D6AeTTD6F1V8gkozA0Gw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/virtualizer@3.6.6(react@18.2.0): + resolution: {integrity: sha512-9hWvfITdE/028q4YFve6FxlmA3PdSMkUwpYA+vfaGCXI/4DFZIssBMspUeu4PTRJoV+k+m0z1wYHPmufrq6a3g==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-types/breadcrumbs@3.7.2(react@18.2.0): + resolution: {integrity: sha512-esl6RucDW2CNMsApJxNYfMtDaUcfLlwKMPH/loYsOBbKxGl2HsgVLMcdpjEkTRs2HCTNCbBXWpeU8AY77t+bsw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/link': 3.5.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/button@3.9.1(react@18.2.0): + resolution: {integrity: sha512-bf9iTar3PtqnyV9rA+wyFyrskZKhwmOuOd/ifYIjPs56YNVXWH5Wfqj6Dx3xdFBgtKx8mEVQxVhoX+WkHX+rtw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/calendar@3.4.3(react@18.2.0): + resolution: {integrity: sha512-96x57ctX5wNEl+8et3sc2NQm8neOJayEeqOQQpyPtI7jyvst/xBrKCwysf9W/dhgPlUC+KeBAYFWfjd5hFVHYA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/checkbox@3.6.0(react@18.2.0): + resolution: {integrity: sha512-vgbuJzQpVCNT5AZWV0OozXCnihqrXxoZKfJFIw0xro47pT2sn3t5UC4RA9wfjDGMoK4frw1K/4HQLsQIOsPBkw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/combobox@3.10.0(react@18.2.0): + resolution: {integrity: sha512-1IXSNS02TPbguyYopaW2snU6sZusbClHrEyVr4zPeexTV4kpUUBNXOzFQ+eSQRR0r2XW57Z0yRW4GJ6FGU0yCA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/datepicker@3.7.1(react@18.2.0): + resolution: {integrity: sha512-5juVDULOytNzkotqX8j5mYKJckeIpkgbHqVSGkPgLw0++FceIaSZ6RH56cqLup0pO45paqIt9zHh+QXBYX+syg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@react-types/calendar': 3.4.3(react@18.2.0) + '@react-types/overlays': 3.8.4(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/dialog@3.5.7(react@18.2.0): + resolution: {integrity: sha512-geYoqAyQaTLG43AaXdMUVqZXYgkSifrD9cF7lR2kPAT0uGFv0YREi6ieU+aui8XJ83EW0xcxP+EPWd2YkN4D4w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/overlays': 3.8.4(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/grid@3.2.3(react@18.2.0): + resolution: {integrity: sha512-GQM4RDmYhstcYZ0Odjq+xUwh1fhLmRebG6qMM8OXHTPQ77nhl3wc1UTGRhZm6mzEionplSRx4GCpEMEHMJIU0w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/link@3.5.2(react@18.2.0): + resolution: {integrity: sha512-/s51/WejmpLiyxOgP89s4txgxYoGaPe8pVDItVo1h4+BhU1Puyvgv/Jx8t9dPvo6LUXbraaN+SgKk/QDxaiirw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/listbox@3.4.6(react@18.2.0): + resolution: {integrity: sha512-XOQvrTqNh5WIPDvKiWiep8T07RAsMfjAXTjDbnjxVlKACUXkcwpts9kFaLnJ9LJRFt6DwItfP+WMkzvmx63/NQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/menu@3.9.6(react@18.2.0): + resolution: {integrity: sha512-w/RbFInOf4nNayQDv5c2L8IMJbcFOkBhsT3xvvpTy+CHvJcQdjggwaV1sRiw7eF/PwB81k2CwigmidUzHJhKDg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/overlays': 3.8.4(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/meter@3.3.6(react@18.2.0): + resolution: {integrity: sha512-1XYp1fA9UU0lO6kjf3TwVE8mppOJa64mBKAcLWtTyq1e/cYIAbx5o6CsuUx0YDpXKF6gdtvIWvfmxeWsmqJ1jQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/progress': 3.5.1(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/numberfield@3.7.0(react@18.2.0): + resolution: {integrity: sha512-gaGi+vqm1Y8LCWRsWYUjcGftPIzl+8W2VOfkgKMLM8y76nnwTPtmAqs+Ap1cg7sEJSfsiKMq93e9yvP3udrC2w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/overlays@3.8.4(react@18.2.0): + resolution: {integrity: sha512-pfgNlQnbF6RB/R2oSxyqAP3Uzz0xE/k5q4n5gUeCDNLjY5qxFHGE8xniZZ503nZYw6VBa9XMN1efDOKQyeiO0w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/progress@3.5.1(react@18.2.0): + resolution: {integrity: sha512-CqsUjczUK/SfuFzDcajBBaXRTW0D3G9S/yqLDj9e8E0ii+lGDLt1PHj24t1J7E88U2rVYqmM9VL4NHTt8o3IYA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/radio@3.7.0(react@18.2.0): + resolution: {integrity: sha512-EcwGAXzSHjSqpFZha7xn3IUrhPiJLj+0yb1Ip0qPmhWz0VVw2DwrkY7q/jfaKroVvQhTo2TbfGhcsAQrt0fRqg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/searchfield@3.5.2(react@18.2.0): + resolution: {integrity: sha512-JAK2/Kg4Dr393FYfbRw0TlXKnJPX77sq1x/ZBxtO6p64+MuuIYKqw0i9PwDlo1PViw2QI5u8GFhKA2TgemY9uA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/textfield': 3.9.0(react@18.2.0) + react: 18.2.0 + dev: false - /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + /@react-types/select@3.9.1(react@18.2.0): + resolution: {integrity: sha512-EpKSxrnh8HdZvOF9dHQkjivAcdIp1K81FaxmvosH8Lygqh0iYXxAdZGtKLMyBoPI8YFhA+rotIzTcOqgCCnqWA==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + /@react-types/shared@3.22.0(react@18.2.0): + resolution: {integrity: sha512-yVOekZWbtSmmiThGEIARbBpnmUIuePFlLyctjvCbgJgGhz8JnEJOipLQ/a4anaWfzAgzSceQP8j/K+VOOePleA==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} + /@react-types/slider@3.7.0(react@18.2.0): + resolution: {integrity: sha512-uyQXUVFfqc9SPUW0LZLMan2n232F/OflRafiHXz9viLFa9tVOupVa7GhASRAoHojwkjoJ1LjFlPih7g5dOZ0/Q==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} + /@react-types/switch@3.5.0(react@18.2.0): + resolution: {integrity: sha512-/wNmUGjk69bP6t5k2QkAdrNN5Eb9Rz4dOyp0pCPmoeE+5haW6sV5NmtkvWX1NSc4DQz1xL/a5b+A0vxPCP22Jw==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/rect': 1.0.1 - '@types/react': 18.2.48 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-use-size@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} + /@react-types/table@3.9.2(react@18.2.0): + resolution: {integrity: sha512-brw5JUANOzBa2rYNpN8AIl9nDZ9RwRZC6G/wTM/JhtirjC1S42oCtf8Ap5rWJBdmMG/5KOfcGNcAl/huyqb3gg==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 + '@react-types/grid': 3.2.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} + /@react-types/tabs@3.3.4(react@18.2.0): + resolution: {integrity: sha512-4mCTtFrwMRypyGTZCvNYVT9CkknexO/UYvqwDm2jMYb8JgjRvxnomu776Yh7uyiYKWyql2upm20jqasEOm620w==} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true + dev: false - /@radix-ui/rect@1.0.1: - resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + /@react-types/textfield@3.9.0(react@18.2.0): + resolution: {integrity: sha512-D/DiwzsfkwlAg3uv8hoIfwju+zhB/hWDEdTvxQbPkntDr0kmN/QfI17NMSzbOBCInC4ABX87ViXLGxr940ykGA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - dev: true + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false - /@react-icons/all-files@4.1.0(react@18.2.0): - resolution: {integrity: sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==} + /@react-types/tooltip@3.4.6(react@18.2.0): + resolution: {integrity: sha512-RaZewdER7ZcsNL99RhVHs8kSLyzIBkwc0W6eFZrxST2MD9J5GzkVWRhIiqtFOd5U1aYnxdJ6woq72Ef+le6Vfw==} peerDependencies: - react: '*' + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: + '@react-types/overlays': 3.8.4(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 dev: false @@ -6916,6 +8197,54 @@ packages: memoizerific: 1.11.3 dev: true + /@storybook/addons@6.5.16(react-dom@18.2.0)(react@17.0.2): + resolution: {integrity: sha512-p3DqQi+8QRL5k7jXhXmJZLsE/GqHqyY6PcoA1oNTJr0try48uhTGUOYkgzmqtDaa/qPFO5LP+xCPzZXckGtquQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@storybook/api': 6.5.16(react-dom@18.2.0)(react@17.0.2) + '@storybook/channels': 6.5.16 + '@storybook/client-logger': 6.5.16 + '@storybook/core-events': 6.5.16 + '@storybook/csf': 0.0.2--canary.4566f4d.1 + '@storybook/router': 6.5.16(react-dom@18.2.0)(react@17.0.2) + '@storybook/theming': 6.5.16(react-dom@18.2.0)(react@17.0.2) + '@types/webpack-env': 1.18.4 + core-js: 3.35.1 + global: 4.4.0 + react: 17.0.2 + react-dom: 18.2.0(react@18.2.0) + regenerator-runtime: 0.13.11 + dev: true + + /@storybook/api@6.5.16(react-dom@18.2.0)(react@17.0.2): + resolution: {integrity: sha512-HOsuT8iomqeTMQJrRx5U8nsC7lJTwRr1DhdD0SzlqL4c80S/7uuCy4IZvOt4sYQjOzW5fOo/kamcoBXyLproTA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@storybook/channels': 6.5.16 + '@storybook/client-logger': 6.5.16 + '@storybook/core-events': 6.5.16 + '@storybook/csf': 0.0.2--canary.4566f4d.1 + '@storybook/router': 6.5.16(react-dom@18.2.0)(react@17.0.2) + '@storybook/semver': 7.3.2 + '@storybook/theming': 6.5.16(react-dom@18.2.0)(react@17.0.2) + core-js: 3.35.1 + fast-deep-equal: 3.1.3 + global: 4.4.0 + lodash: 4.17.21 + memoizerific: 1.11.3 + react: 17.0.2 + react-dom: 18.2.0(react@18.2.0) + regenerator-runtime: 0.13.11 + store2: 2.14.2 + telejson: 6.0.8 + ts-dedent: 2.2.0 + util-deprecate: 1.0.2 + dev: true + /@storybook/blocks@7.6.9(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-ZSQub0RoZ7uxa0FbbornJd+AVs8ikVe9ESxOB7h/Y1oPHEbKLkkxGfXVIzt9wu8kaDMNhVT+Ewg9pVnWu/p4yQ==} peerDependencies: @@ -7035,6 +8364,14 @@ packages: - webpack-cli dev: true + /@storybook/channels@6.5.16: + resolution: {integrity: sha512-VylzaWQZaMozEwZPJdyJoz+0jpDa8GRyaqu9TGG6QGv+KU5POoZaGLDkRE7TzWkyyP0KQLo80K99MssZCpgSeg==} + dependencies: + core-js: 3.35.1 + ts-dedent: 2.2.0 + util-deprecate: 1.0.2 + dev: true + /@storybook/channels@7.6.9: resolution: {integrity: sha512-goGGZPT294CS1QDF65Fs+PCauvM/nTMseU913ZVSZbFTk4uvqIXOaOraqhQze8A/C8a0yls4qu2Wp00tCnyaTA==} dependencies: @@ -7097,6 +8434,13 @@ packages: - utf-8-validate dev: true + /@storybook/client-logger@6.5.16: + resolution: {integrity: sha512-pxcNaCj3ItDdicPTXTtmYJE3YC1SjxFrBmHcyrN+nffeNyiMuViJdOOZzzzucTUG0wcOOX8jaSyak+nnHg5H1Q==} + dependencies: + core-js: 3.35.1 + global: 4.4.0 + dev: true + /@storybook/client-logger@7.6.9: resolution: {integrity: sha512-Xm6fa6AR3cjxabauMldBv/66OOp5IhDiUEpp4D/a7hXfvCWqwmjVJ6EPz9WzkMhcPbMJr8vWJBaS3glkFqsRng==} dependencies: @@ -7185,6 +8529,12 @@ packages: - supports-color dev: true + /@storybook/core-events@6.5.16: + resolution: {integrity: sha512-qMZQwmvzpH5F2uwNUllTPg6eZXr2OaYZQRRN8VZJiuorZzDNdAFmiVWMWdkThwmyLEJuQKXxqCL8lMj/7PPM+g==} + dependencies: + core-js: 3.35.1 + dev: true + /@storybook/core-events@7.6.9: resolution: {integrity: sha512-YCds7AA6sbnnZ2qq5l+AIxhQqYlXB8eVTkjj6phgczsLjkqKapYFxAFc3ppRnE0FcsL2iji17ikHzZ8+eHYznA==} dependencies: @@ -7286,6 +8636,12 @@ packages: lodash: 4.17.21 dev: true + /@storybook/csf@0.0.2--canary.4566f4d.1: + resolution: {integrity: sha512-9OVvMVh3t9znYZwb0Svf/YQoxX2gVOeQTGe2bses2yj+a3+OJnCrUF3/hGv6Em7KujtOdL2LL+JnG49oMVGFgQ==} + dependencies: + lodash: 4.17.21 + dev: true + /@storybook/csf@0.1.2: resolution: {integrity: sha512-ePrvE/pS1vsKR9Xr+o+YwdqNgHUyXvg+1Xjx0h9LrVx7Zq4zNe06pd63F5EvzTbCbJsHj7GHr9tkiaqm7U8WRA==} dependencies: @@ -7593,6 +8949,21 @@ packages: - supports-color dev: true + /@storybook/router@6.5.16(react-dom@18.2.0)(react@17.0.2): + resolution: {integrity: sha512-ZgeP8a5YV/iuKbv31V8DjPxlV4AzorRiR8OuSt/KqaiYXNXlOoQDz/qMmiNcrshrfLpmkzoq7fSo4T8lWo2UwQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@storybook/client-logger': 6.5.16 + core-js: 3.35.1 + memoizerific: 1.11.3 + qs: 6.11.2 + react: 17.0.2 + react-dom: 18.2.0(react@18.2.0) + regenerator-runtime: 0.13.11 + dev: true + /@storybook/router@7.6.9: resolution: {integrity: sha512-SSOt/rLcfrFYj+81zi1TOWBXgcx0nN6K41DPZ2T3ye94X8p1BNgxwj5P02/PB4SiOfEHJwTrXZDFUbZQMOo8aA==} dependencies: @@ -7601,6 +8972,15 @@ packages: qs: 6.11.2 dev: true + /@storybook/semver@7.3.2: + resolution: {integrity: sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + core-js: 3.35.1 + find-up: 4.1.0 + dev: true + /@storybook/source-loader@7.6.9: resolution: {integrity: sha512-UrKfHEvZbg3deM1q0ZZGXrcbQQZbGtAH2BMl7xPSlheGtYsKracwTRpriAH27cpJnIem4ZZa0agtYeza7JkS+g==} dependencies: @@ -7649,6 +9029,20 @@ packages: - vitest dev: true + /@storybook/theming@6.5.16(react-dom@18.2.0)(react@17.0.2): + resolution: {integrity: sha512-hNLctkjaYLRdk1+xYTkC1mg4dYz2wSv6SqbLpcKMbkPHTE0ElhddGPHQqB362md/w9emYXNkt1LSMD8Xk9JzVQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@storybook/client-logger': 6.5.16 + core-js: 3.35.1 + memoizerific: 1.11.3 + react: 17.0.2 + react-dom: 18.2.0(react@18.2.0) + regenerator-runtime: 0.13.11 + dev: true + /@storybook/theming@7.6.9(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-S2tow/l2HJFL7im+ovFQE0nLCzy/39qZU30/WVc8gM2dfM7Gsn6M4xiXu23BEwJHnCP8TIOBiCDN1JkOcOvvgg==} peerDependencies: @@ -7779,6 +9173,19 @@ packages: /@swc/counter@0.1.2: resolution: {integrity: sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==} + /@swc/helpers@0.4.14: + resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} + dependencies: + tslib: 2.6.2 + dev: false + + /@swc/helpers@0.4.36: + resolution: {integrity: sha512-5lxnyLEYFskErRPenYItLRSge5DjrJngYKdVjRSrWfza9G6KkgHEXi0vUZiyUeMU5JfXH1YnvXZzSp8ul88o2Q==} + dependencies: + legacy-swc-helpers: /@swc/helpers@0.4.14 + tslib: 2.6.2 + dev: false + /@swc/helpers@0.5.2: resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} dependencies: @@ -8121,6 +9528,10 @@ packages: resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} dev: true + /@types/is-function@1.0.3: + resolution: {integrity: sha512-/CLhCW79JUeLKznI6mbVieGbl4QU5Hfn+6udw1YHZoofASjbQ5zaP5LzAUZYDpRYEjS4/P+DhEgyJ/PQmGGTWw==} + dev: true + /@types/istanbul-lib-coverage@2.0.6: resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -8305,6 +9716,10 @@ packages: resolution: {integrity: sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==} dev: true + /@types/webpack-env@1.18.4: + resolution: {integrity: sha512-I6e+9+HtWADAWeeJWDFQtdk4EVSAbj6Rtz4q8fJ7mSr1M0jzlFcs8/HZ+Xb5SHzVm1dxH7aUiI+A8kA8Gcrm0A==} + dev: true + /@types/ws@8.5.10: resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} dependencies: @@ -8523,10 +9938,6 @@ packages: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true - /@vanilla-extract/css-utils@0.1.3: - resolution: {integrity: sha512-PZAcHROlgtCUGI2y0JntdNwvPwCNyeVnkQu6KTYKdmxBbK3w72XJUmLFYapfaFfgami4I9CTLnrJTPdtmS3gpw==} - dev: false - /@vanilla-extract/css@1.14.0: resolution: {integrity: sha512-rYfm7JciWZ8PFzBM/HDiE2GLnKI3xJ6/vdmVJ5BSgcCZ5CxRlM9Cjqclni9lGzF3eMOijnUhCd/KV8TOzyzbMA==} dependencies: @@ -8553,8 +9964,8 @@ packages: resolution: {integrity: sha512-17kVyLq3ePTKOkveHxXuIJZtGYs+cSoev7BlP+Lf4916qfDhk/HBjvlYDe8egrea7LNPHKwSZJK/bzZC+Q6AwQ==} dev: false - /@vanilla-extract/recipes@0.4.0(@vanilla-extract/css@1.14.0): - resolution: {integrity: sha512-gFgB7BofUYbtbxINHK6DhMv1JDFDXp/YI/Xm+cqKar+1I/2dfxPepeDxSexL6YB4ftfeaDw8Kn5zydMvHcGOEQ==} + /@vanilla-extract/recipes@0.5.1(@vanilla-extract/css@1.14.0): + resolution: {integrity: sha512-7dCuBgPQQ/89siQ0w2lkfjgkmToPUUDzFlHf5DRmt9ykiiycfA52tmPJ2RI/mr7jXi7U/vEN2aGP9QJSXEpGlA==} peerDependencies: '@vanilla-extract/css': ^1.0.0 dependencies: @@ -9025,28 +10436,6 @@ packages: tslib: 1.14.1 dev: true - /@zag-js/anatomy@0.15.0: - resolution: {integrity: sha512-+lmu/JVQ6Q5M9Tmbt1sXVkp3CtP10JYOo/PU2L6w6mXpwazT5FUpsuorrBrBM9rhWOnxI7CVvFy7r/rxReDWgg==} - dev: false - - /@zag-js/core@0.15.0: - resolution: {integrity: sha512-eH3yx9nv0hMyoR+hWtJVJpCagpU5s61rOMHfLkdjMPTWSVjQZdp3SGEm6BTUjBlNbQkTZhUbPpg/FEqx1iPfJw==} - dependencies: - '@zag-js/store': 0.15.0 - klona: 2.0.6 - dev: false - - /@zag-js/dom-event@0.15.0: - resolution: {integrity: sha512-5Sw2pNCcX2PqSiz4Ntm2PDu+YARQLtUrAf6PBBSUIqMZ0X9pp7DWTY3IfpdqY2ADsRLRMIe1LqzM+/c0u3Gd1Q==} - dependencies: - '@zag-js/text-selection': 0.15.0 - '@zag-js/types': 0.15.0 - dev: false - - /@zag-js/dom-query@0.15.0: - resolution: {integrity: sha512-gxm7GefQ+ggJE+iN0/kHgbM90DPd4RZYoQC6TQOWy3nxij69IuoSI6goMakJ33hUckszWm9z86Sqe1U1puzssQ==} - dev: false - /@zag-js/dom-query@0.16.0: resolution: {integrity: sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ==} @@ -9058,70 +10447,6 @@ packages: dependencies: '@zag-js/dom-query': 0.16.0 - /@zag-js/form-utils@0.15.0: - resolution: {integrity: sha512-3gFzyF8x48wK2Fabt6rxjMETmhSlwTtCjF10XFrKscL1LZASc3Abl7lJcpTEmVJ5kb5D+50Zw+jlHjHrvddH6g==} - dependencies: - '@zag-js/mutation-observer': 0.15.0 - dev: false - - /@zag-js/mutation-observer@0.15.0: - resolution: {integrity: sha512-7e2d1RYA0nuKOAJknbYBw6XfywF5eFC/4oel/nINHmS14JtjZnjMq/8z/kdrMMJnlQHou+wnaoskOLv+4Sv7pw==} - dev: false - - /@zag-js/number-input@0.15.0: - resolution: {integrity: sha512-WyIGLI4gUm9+53OPCoOmzyZaqT32ALdfZl1QjTVLuDXzckoBgqxaowR0mJU1gDkJ89mSI02p0B0Q89SOiokUfQ==} - dependencies: - '@zag-js/anatomy': 0.15.0 - '@zag-js/core': 0.15.0 - '@zag-js/dom-event': 0.15.0 - '@zag-js/dom-query': 0.15.0 - '@zag-js/form-utils': 0.15.0 - '@zag-js/mutation-observer': 0.15.0 - '@zag-js/number-utils': 0.15.0 - '@zag-js/types': 0.15.0 - '@zag-js/utils': 0.15.0 - dev: false - - /@zag-js/number-utils@0.15.0: - resolution: {integrity: sha512-ebDPCv4UNl5qAe+x55NSUK5gMLbhlqh8mVVq6EnPUqPfbglcjUgNzht78TZ3d+0rdfgC3F8SI3pWaZk9DY4O1Q==} - dev: false - - /@zag-js/react@0.15.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Uygdyq29Y7q5GPOYv1VC9Ya5tdFOs+jdCZk5h5BKzFy3vCSDaVuZ8WT+w7JgvUWh6aQUKjUMLG8lXxWWnJA0Jg==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@zag-js/core': 0.15.0 - '@zag-js/store': 0.15.0 - '@zag-js/types': 0.15.0 - proxy-compare: 2.5.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@zag-js/store@0.15.0: - resolution: {integrity: sha512-xq4WFrd+fqJE+Y0Os3FhN2/ru2zxvIvV8IT9y5Ev+3VRZw+L6Ut4tEjOONk+zr+UpkRx3jflPqlekjLHtowp0w==} - dependencies: - proxy-compare: 2.5.1 - dev: false - - /@zag-js/text-selection@0.15.0: - resolution: {integrity: sha512-5i/MkTTBOJN17YylGgvRC+dyO5l3pgz2a/z0xBiIpimYqP1W66P0N1Yq0/5VZubs9TG41jKyEKuulKfcpLwmYg==} - dependencies: - '@zag-js/dom-query': 0.15.0 - dev: false - - /@zag-js/types@0.15.0: - resolution: {integrity: sha512-rkAwZDl6e5p2iXF9HknP03TQ/G9jfOto0x2r2rds4wsPbfVJBNGk0Mo6Jl9GXcpNiyOCOO74SoO9VjZTmMqVvw==} - dependencies: - csstype: 3.1.2 - dev: false - - /@zag-js/utils@0.15.0: - resolution: {integrity: sha512-aNjydiheTKMoIo1wASk3XgN3mbcCiCk2zAiUyldU4JCw9xWevMk5aSszW2v3A0yms6z+qhRb77Z50fejG7OlSA==} - dev: false - /JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -10350,6 +11675,11 @@ packages: engines: {node: '>=6'} dev: false + /clsx@2.1.0: + resolution: {integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==} + engines: {node: '>=6'} + dev: false + /cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} @@ -10636,6 +11966,11 @@ packages: requiresBuild: true dev: true + /core-js@3.35.1: + resolution: {integrity: sha512-IgdsbxNyMskrTFxa9lWHyMwAJU5gXOPP+1yO+K59d50VLVAIDAbs7gIv705KzALModfK3ZrSZTPNpC0PQgIZuw==} + requiresBuild: true + dev: true + /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} dev: true @@ -10850,10 +12185,6 @@ packages: engines: {node: '>=4'} hasBin: true - /csstype@3.1.2: - resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} - dev: false - /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -11226,6 +12557,10 @@ packages: entities: 2.2.0 dev: true + /dom-walk@0.1.2: + resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} + dev: true + /domain-browser@4.23.0: resolution: {integrity: sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==} engines: {node: '>=10'} @@ -12864,6 +14199,13 @@ packages: which: 1.3.1 dev: true + /global@4.4.0: + resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==} + dependencies: + min-document: 2.19.0 + process: 0.11.10 + dev: true + /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -13392,6 +14734,15 @@ packages: side-channel: 1.0.4 dev: true + /intl-messageformat@10.5.10: + resolution: {integrity: sha512-3yzwX6t/my9WRtNiqP05r+/UkpWxwstQiwaHAiuHmDRt7ykzWJ+nceOVjNLZYYWGiSltY+C+Likd8OIVkASepw==} + dependencies: + '@formatjs/ecma402-abstract': 1.18.2 + '@formatjs/fast-memoize': 2.2.0 + '@formatjs/icu-messageformat-parser': 2.7.5 + tslib: 2.6.2 + dev: false + /invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} dependencies: @@ -13537,6 +14888,10 @@ packages: engines: {node: '>=12'} dev: true + /is-function@1.0.2: + resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==} + dev: true + /is-generator-fn@2.1.0: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} @@ -13768,6 +15123,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /isobject@4.0.0: + resolution: {integrity: sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==} + engines: {node: '>=0.10.0'} + dev: true + /isomorphic-unfetch@3.1.0: resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} dependencies: @@ -14525,6 +15885,7 @@ packages: /klona@2.0.6: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} + dev: true /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} @@ -15114,6 +16475,12 @@ packages: engines: {node: '>=10'} dev: true + /min-document@2.19.0: + resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==} + dependencies: + dom-walk: 0.1.2 + dev: true + /min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -16257,10 +17624,6 @@ packages: ipaddr.js: 1.9.1 dev: true - /proxy-compare@2.5.1: - resolution: {integrity: sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==} - dev: false - /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -16464,6 +17827,53 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /react-aria@3.31.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-q4jRCVDKO6V2o4Sgir5S2obssw/YnMx6QOy10+p0dYqROHpSnMFNkONrKT1w/nA+Nx4ptfPqZbaNra1hR1bUWg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/string': 3.2.0 + '@react-aria/breadcrumbs': 3.5.9(react@18.2.0) + '@react-aria/button': 3.9.1(react@18.2.0) + '@react-aria/calendar': 3.5.4(react-dom@18.2.0)(react@18.2.0) + '@react-aria/checkbox': 3.13.0(react@18.2.0) + '@react-aria/combobox': 3.8.2(react-dom@18.2.0)(react@18.2.0) + '@react-aria/datepicker': 3.9.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/dialog': 3.5.10(react-dom@18.2.0)(react@18.2.0) + '@react-aria/dnd': 3.5.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/gridlist': 3.7.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/link': 3.6.3(react@18.2.0) + '@react-aria/listbox': 3.11.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/menu': 3.12.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/meter': 3.4.9(react@18.2.0) + '@react-aria/numberfield': 3.10.2(react-dom@18.2.0)(react@18.2.0) + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/progress': 3.4.9(react@18.2.0) + '@react-aria/radio': 3.10.0(react@18.2.0) + '@react-aria/searchfield': 3.7.1(react@18.2.0) + '@react-aria/select': 3.14.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/separator': 3.3.9(react@18.2.0) + '@react-aria/slider': 3.7.4(react@18.2.0) + '@react-aria/ssr': 3.9.1(react@18.2.0) + '@react-aria/switch': 3.6.0(react@18.2.0) + '@react-aria/table': 3.13.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/tabs': 3.8.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/tag': 3.3.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/textfield': 3.14.1(react@18.2.0) + '@react-aria/tooltip': 3.7.0(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-aria/visually-hidden': 3.8.8(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /react-clientside-effect@1.2.6(react@18.2.0): resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==} peerDependencies: @@ -16713,6 +18123,37 @@ packages: - '@types/react' dev: false + /react-stately@3.29.1(react@18.2.0): + resolution: {integrity: sha512-hc4ZHy/ahvMwr6z7XMjYJ7EgzNVrXhzM4l2Qj17rdRhERo7/ovWmQencf9pF7K8kD5TraEHxPHLrYzGN4fxfUQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/calendar': 3.4.3(react@18.2.0) + '@react-stately/checkbox': 3.6.1(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/combobox': 3.8.1(react@18.2.0) + '@react-stately/data': 3.11.0(react@18.2.0) + '@react-stately/datepicker': 3.9.1(react@18.2.0) + '@react-stately/dnd': 3.2.7(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-stately/menu': 3.6.0(react@18.2.0) + '@react-stately/numberfield': 3.8.0(react@18.2.0) + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-stately/radio': 3.10.1(react@18.2.0) + '@react-stately/searchfield': 3.5.0(react@18.2.0) + '@react-stately/select': 3.6.1(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-stately/slider': 3.5.0(react@18.2.0) + '@react-stately/table': 3.11.4(react@18.2.0) + '@react-stately/tabs': 3.6.3(react@18.2.0) + '@react-stately/toggle': 3.7.0(react@18.2.0) + '@react-stately/tooltip': 3.4.6(react@18.2.0) + '@react-stately/tree': 3.7.5(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + /react-style-singleton@2.2.1(@types/react@18.2.48)(react@18.2.0): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} @@ -16743,6 +18184,14 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /react@17.0.2: + resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + dev: true + /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} @@ -16868,6 +18317,10 @@ packages: resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} dev: true + /regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: true + /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -17567,6 +19020,16 @@ packages: resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==} dev: true + /storybook-react-context@0.6.0(react-dom@18.2.0): + resolution: {integrity: sha512-6IOUbSoC1WW68x8zQBEh8tZsVXjEvOBSJSOhkaD9o8IF9caIg/o1jnwuGibdyAd47ARN6g95O0N0vFBjXcB7pA==} + dependencies: + '@storybook/addons': 6.5.16(react-dom@18.2.0)(react@17.0.2) + is-plain-object: 5.0.0 + react: 17.0.2 + transitivePeerDependencies: + - react-dom + dev: true + /storybook@7.6.9: resolution: {integrity: sha512-zsPLvhbEfheqt9bN7X38vgrhLcxSyn7HdWbjZC+02hgNQ0U1jZ4VfrzNbJSqFxzxU+B5gdDZSFMui7OUx9A9Ew==} hasBin: true @@ -17899,6 +19362,19 @@ packages: yallist: 4.0.0 dev: true + /telejson@6.0.8: + resolution: {integrity: sha512-nerNXi+j8NK1QEfBHtZUN/aLdDcyupA//9kAboYLrtzZlPLpUfqbVGWb9zz91f/mIjRbAYhbgtnJHY8I1b5MBg==} + dependencies: + '@types/is-function': 1.0.3 + global: 4.4.0 + is-function: 1.0.2 + is-regex: 1.1.4 + is-symbol: 1.0.4 + isobject: 4.0.0 + lodash: 4.17.21 + memoizerific: 1.11.3 + dev: true + /telejson@7.2.0: resolution: {integrity: sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==} dependencies: diff --git a/src/lib/pages/proposal-details/components/ProposalInfo.tsx b/src/lib/pages/proposal-details/components/ProposalInfo.tsx new file mode 100644 index 000000000..d25dee111 --- /dev/null +++ b/src/lib/pages/proposal-details/components/ProposalInfo.tsx @@ -0,0 +1,155 @@ +import { Divider, Flex, Text } from "@chakra-ui/react"; +import type { ReactNode } from "react"; + +import { ExplorerLink } from "lib/components/ExplorerLink"; +import { MobileLabel, StatusChip } from "lib/components/table"; +import type { BechAddr } from "lib/types"; +import { ProposalStatus } from "lib/types"; +import { formatUTC } from "lib/utils"; + +interface InfoItemProps { + label: string; + children: ReactNode; +} + +const InfoItem = ({ label, children }: InfoItemProps) => { + return ( + + + {children} + + ); +}; + +type ProposalData = { + status: ProposalStatus; + createdTxHash: string; + proposer: BechAddr; + depositStart?: Date; + depositEnd?: Date; + voteStart?: Date; + voteEnd?: Date; + resolvedHeight?: number; + resolvedDate?: Date; +}; + +interface ProposalStatusProps { + data: ProposalData; +} + +const getProposalInfo = (data: ProposalStatusProps["data"]) => { + switch (data.status) { + case ProposalStatus.DEPOSIT_PERIOD: + return ( + + + {data.depositStart && data.depositEnd + ? `${formatUTC(data.depositStart)} - ${formatUTC(data.depositEnd)}` + : "N/A"} + + + ); + case ProposalStatus.DEPOSIT_FAILED: + return ( + + + {data.resolvedHeight ? ( + + ) : ( + + N/A + + )} + + + + {data.resolvedDate ? formatUTC(data.resolvedDate) : "N/A"} + + + + ); + case ProposalStatus.VOTING_PERIOD: + return ( + + + {data.voteStart && data.voteEnd + ? `${formatUTC(data.voteStart)} - ${formatUTC(data.voteEnd)}` + : "N/A"} + + + ); + case ProposalStatus.PASSED: + case ProposalStatus.FAILED: + case ProposalStatus.REJECTED: + return ( + + + {data.resolvedHeight ? ( + + ) : ( + + N/A + + )} + + + + {data.resolvedDate ? formatUTC(data.resolvedDate) : "N/A"} + + + + ); + default: + return ( + + N/A + + ); + } +}; + +export const ProposalInfo = ({ data }: ProposalStatusProps) => { + return ( + + + + + + + + + + + + + + + + {getProposalInfo(data)} + + ); +}; diff --git a/src/lib/pages/proposal-details/components/ProposalTop.tsx b/src/lib/pages/proposal-details/components/ProposalTop.tsx index 24b3218f9..096ce0bf5 100644 --- a/src/lib/pages/proposal-details/components/ProposalTop.tsx +++ b/src/lib/pages/proposal-details/components/ProposalTop.tsx @@ -1,5 +1,176 @@ -import { Flex } from "@chakra-ui/react"; +import { Button, Flex, Heading, Text } from "@chakra-ui/react"; + +import { useMobile } from "lib/app-provider"; +import { Breadcrumb } from "lib/components/Breadcrumb"; +import { CopyLink } from "lib/components/CopyLink"; +import { DotSeparator } from "lib/components/DotSeparator"; +import { CustomIcon } from "lib/components/icon"; +import { InvalidState } from "lib/components/state"; +import type { BechAddr } from "lib/types"; +import { ProposalStatus } from "lib/types"; + +import { ProposalInfo } from "./ProposalInfo"; export const ProposalTop = ({ id }: { id: number }) => { - return {id} proposal top; + const isMobile = useMobile(); + + if (!id) return ; + + return ( + + + + + + + + + #{id} + {" "} + - Regular Incentive adjustment for 2023-07-10 + + + {!isMobile && ( + + )} + + + + + Proposal Messages: + + + ProposalStoreCode / ProposalStoreCode / ProposalStoreCode / + ProposalStoreCode / ProposalStoreCode + + + {!isMobile && ( + + + Created Height: + + + + + {/* {formatUTC(blockData.timestamp)} */} timestamp + + + )} + + {isMobile && ( + + )} + + + + + + + + + ); }; diff --git a/src/lib/pages/proposal-details/components/__stories__/ProposalInfo.stories.ts b/src/lib/pages/proposal-details/components/__stories__/ProposalInfo.stories.ts new file mode 100644 index 000000000..ba6e5a925 --- /dev/null +++ b/src/lib/pages/proposal-details/components/__stories__/ProposalInfo.stories.ts @@ -0,0 +1,88 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { ProposalInfo } from "../ProposalInfo"; +import type { BechAddr } from "lib/types"; +import { ProposalStatus } from "lib/types"; + +const meta: Meta = { + component: ProposalInfo, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], +}; + +export default meta; +type Story = StoryObj; + +export const DEPOSIT_PERIOD: Story = { + args: { + data: { + status: ProposalStatus.DEPOSIT_PERIOD, + createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", + proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, + depositStart: new Date(), + depositEnd: new Date(), + }, + }, +}; + +export const DEPOSIT_FAILED: Story = { + args: { + data: { + status: ProposalStatus.DEPOSIT_FAILED, + createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", + proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, + resolvedHeight: 123456, + resolvedDate: new Date(), + }, + }, +}; + +export const VOTING_PERIOD: Story = { + args: { + data: { + status: ProposalStatus.VOTING_PERIOD, + createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", + proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, + voteStart: new Date(), + voteEnd: new Date(), + }, + }, +}; + +export const PASSED: Story = { + args: { + data: { + status: ProposalStatus.PASSED, + createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", + proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, + resolvedHeight: 123456, + resolvedDate: new Date(), + }, + }, +}; + +export const REJECTED: Story = { + args: { + data: { + status: ProposalStatus.REJECTED, + createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", + proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, + resolvedHeight: 123456, + resolvedDate: new Date(), + }, + }, +}; + +export const FAILED: Story = { + args: { + data: { + status: ProposalStatus.FAILED, + createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", + proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, + resolvedHeight: 123456, + resolvedDate: new Date(), + }, + }, +}; From 11d7f1f8c326668faf908fda2d86430b2455abea Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Mon, 22 Jan 2024 19:03:44 +0700 Subject: [PATCH 004/531] fix(components): fix mobile --- .../components/ProposalOverview.tsx | 2 +- .../components/ProposalStepper.tsx | 91 +++++++++++++------ .../components/VotingPeriodSection.tsx | 2 +- 3 files changed, 64 insertions(+), 31 deletions(-) diff --git a/src/lib/pages/proposal-details/components/ProposalOverview.tsx b/src/lib/pages/proposal-details/components/ProposalOverview.tsx index c95ae97d1..d30ffbbd3 100644 --- a/src/lib/pages/proposal-details/components/ProposalOverview.tsx +++ b/src/lib/pages/proposal-details/components/ProposalOverview.tsx @@ -27,7 +27,7 @@ export const ProposalOverview = () => { Proposal Description - + This is a proposal to give the address osmo1raa4kyx5ypz75qqk3566c6slx2mw3qzsu6rymw permission to upload CosmWasm contracts to Osmosis without seeking governance approval diff --git a/src/lib/pages/proposal-details/components/ProposalStepper.tsx b/src/lib/pages/proposal-details/components/ProposalStepper.tsx index 4e0160cd2..1e0d0ee68 100644 --- a/src/lib/pages/proposal-details/components/ProposalStepper.tsx +++ b/src/lib/pages/proposal-details/components/ProposalStepper.tsx @@ -1,5 +1,7 @@ import { Flex, Text } from "@chakra-ui/react"; +import { useMobile } from "lib/app-provider"; + interface ProposalStepperProps { title: string; description: string; @@ -11,43 +13,74 @@ export const ProposalStepper = ({ description, step, }: ProposalStepperProps) => { + const isMobile = useMobile(); return ( - - - {/* TODO: Color changes when state changes */} + + + + {/* TODO: Color changes when state changes */} + + {step} + + + + {title} + + {!isMobile && ( + + {description} + + )} + + - {step} - - - - {title} - - - {description} + + + Waiting For Deposit - - - - Waiting For Deposit + {isMobile && ( + + {description} - + )} ); }; diff --git a/src/lib/pages/proposal-details/components/VotingPeriodSection.tsx b/src/lib/pages/proposal-details/components/VotingPeriodSection.tsx index 72ea46c16..6dc4228c3 100644 --- a/src/lib/pages/proposal-details/components/VotingPeriodSection.tsx +++ b/src/lib/pages/proposal-details/components/VotingPeriodSection.tsx @@ -23,7 +23,7 @@ export const ContentContainer = ({ border="1px solid" borderColor={isMobile && !hasSubSection ? "transparent" : "gray.700"} borderRadius="8px" - p={isMobile && !hasSubSection ? 0 : 6} + p={{ base: !hasSubSection ? 0 : 4, md: !hasSubSection ? 0 : 6 }} gap={4} > {children} From c4a89a7670210e2020f7335f316bcb1c9146f2c2 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Wed, 24 Jan 2024 11:34:31 +0700 Subject: [PATCH 005/531] docs: cut release v1.5.1 --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac26c7ebd..e3263c6c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +### Bug fixes + +## v1.5.1 + +### Improvements + - [#743](https://github.com/alleslabs/celatone-frontend/pull/743) Add mobile view for proposal list ### Bug fixes diff --git a/package.json b/package.json index 465514507..44d117e5a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "celatone", - "version": "1.5.0", + "version": "1.5.1", "author": "Alles Labs", "contributors": [ { From 027d5d8e6674b15470c871de1003e9c2c37641be Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Wed, 24 Jan 2024 13:05:00 +0700 Subject: [PATCH 006/531] fix(components): add zod --- src/lib/components/MobileGuard.tsx | 2 +- .../components/ProposalDetailsBody.tsx | 10 +++--- src/lib/pages/proposal-details/index.tsx | 32 +++++++++++++++---- src/lib/pages/proposal-details/type.ts | 24 ++++++++++++++ src/pages/[network]/proposals/[id]/[tab].tsx | 4 +-- src/pages/[network]/proposals/[id]/index.tsx | 4 +-- src/pages/proposals/[id]/[tab].tsx | 4 +-- src/pages/proposals/[id]/index.tsx | 4 +-- 8 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/lib/components/MobileGuard.tsx b/src/lib/components/MobileGuard.tsx index fd86aaeaa..727ed4235 100644 --- a/src/lib/components/MobileGuard.tsx +++ b/src/lib/components/MobileGuard.tsx @@ -24,7 +24,7 @@ export const MobileGuard = ({ children }: MobileGuardProps) => { pathName.includes(`/network-overview`) || pathName.includes(`/dev-home`) || pathName.includes(`/404`) || - pathName.includes(`/proposals/`) || + pathName.includes(`/proposals`) || // wasm pathName.includes(`/contracts/`) || pathName === `/${currentChainId}/contracts` || diff --git a/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx b/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx index ea7ef3f4e..43aa40a40 100644 --- a/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx +++ b/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx @@ -2,20 +2,22 @@ import { TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"; import { useRouter } from "next/router"; import { useCallback, useEffect } from "react"; +import type { ProposalDetailsQueryParams } from "../type"; import { TabIndex } from "../type"; import { useInternalNavigate } from "lib/app-provider"; import { CustomTab } from "lib/components/CustomTab"; -import { getFirstQueryParam } from "lib/utils"; import { ProposalOverview } from "./ProposalOverview"; import { VoteDetail } from "./VoteDetail"; -export const ProposalDetailBody = ({ id }: { id: number }) => { +export const ProposalDetailBody = ({ + id, + tab, + // voteTab, +}: ProposalDetailsQueryParams) => { const router = useRouter(); const navigate = useInternalNavigate(); - const tab = getFirstQueryParam(router.query.tab) as TabIndex; - const handleTabChange = useCallback( (nextTab: TabIndex) => () => { if (nextTab === tab) return; diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index 2f8b055b2..b6acc4d7a 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -1,19 +1,39 @@ import { useRouter } from "next/router"; import PageContainer from "lib/components/PageContainer"; -import { EmptyState } from "lib/components/state"; +import { InvalidState } from "lib/components/state"; import { ProposalDetailBody } from "./components/ProposalDetailsBody"; import { ProposalTop } from "./components/ProposalTop"; +import type { ProposalDetailsQueryParams } from "./type"; +import { zProposalDetailsQueryParams } from "./type"; -export const ProposalDetail = () => { +const ProposalDetailsBody = ({ + id, + tab, + voteTab, +}: ProposalDetailsQueryParams) => { + // TODO Mock up + if (id === 999) return ; + return ( + <> + + + + ); +}; +export const ProposalDetails = () => { const router = useRouter(); - const proposalId = parseInt(router.query.id as string, 10); - if (!proposalId) return ; + + const validated = zProposalDetailsQueryParams.safeParse(router.query); + return ( - - + {!validated.success ? ( + + ) : ( + + )} ); }; diff --git a/src/lib/pages/proposal-details/type.ts b/src/lib/pages/proposal-details/type.ts index 696cb4921..1466ab302 100644 --- a/src/lib/pages/proposal-details/type.ts +++ b/src/lib/pages/proposal-details/type.ts @@ -1,3 +1,5 @@ +import { z } from "zod"; + export enum TabIndex { Overview = "overview", Vote = "vote", @@ -7,3 +9,25 @@ export enum VoteTabIndex { Deposit = "deposit", Voting = "voting", } + +export const zProposalDetailsQueryParams = z.object({ + id: z.coerce.number(), + tab: z.union([ + z.nativeEnum(TabIndex), + z + .string() + .optional() + .transform(() => TabIndex.Overview), + ]), + voteTab: z.union([ + z.nativeEnum(VoteTabIndex), + z + .string() + .optional() + .transform(() => VoteTabIndex.Deposit), + ]), +}); + +export type ProposalDetailsQueryParams = z.infer< + typeof zProposalDetailsQueryParams +>; diff --git a/src/pages/[network]/proposals/[id]/[tab].tsx b/src/pages/[network]/proposals/[id]/[tab].tsx index 82a0c00d8..a44532bda 100644 --- a/src/pages/[network]/proposals/[id]/[tab].tsx +++ b/src/pages/[network]/proposals/[id]/[tab].tsx @@ -1,3 +1,3 @@ -import { ProposalDetail } from "lib/pages/proposal-details"; +import { ProposalDetails } from "lib/pages/proposal-details"; -export default ProposalDetail; +export default ProposalDetails; diff --git a/src/pages/[network]/proposals/[id]/index.tsx b/src/pages/[network]/proposals/[id]/index.tsx index 82a0c00d8..a44532bda 100644 --- a/src/pages/[network]/proposals/[id]/index.tsx +++ b/src/pages/[network]/proposals/[id]/index.tsx @@ -1,3 +1,3 @@ -import { ProposalDetail } from "lib/pages/proposal-details"; +import { ProposalDetails } from "lib/pages/proposal-details"; -export default ProposalDetail; +export default ProposalDetails; diff --git a/src/pages/proposals/[id]/[tab].tsx b/src/pages/proposals/[id]/[tab].tsx index 82a0c00d8..a44532bda 100644 --- a/src/pages/proposals/[id]/[tab].tsx +++ b/src/pages/proposals/[id]/[tab].tsx @@ -1,3 +1,3 @@ -import { ProposalDetail } from "lib/pages/proposal-details"; +import { ProposalDetails } from "lib/pages/proposal-details"; -export default ProposalDetail; +export default ProposalDetails; diff --git a/src/pages/proposals/[id]/index.tsx b/src/pages/proposals/[id]/index.tsx index 82a0c00d8..a44532bda 100644 --- a/src/pages/proposals/[id]/index.tsx +++ b/src/pages/proposals/[id]/index.tsx @@ -1,3 +1,3 @@ -import { ProposalDetail } from "lib/pages/proposal-details"; +import { ProposalDetails } from "lib/pages/proposal-details"; -export default ProposalDetail; +export default ProposalDetails; From d13035ed34c9f3e41e96dd8af8549e1b64657b23 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:10:14 +0700 Subject: [PATCH 007/531] fix: add changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3263c6c6..7da5d88e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#749](https://github.com/alleslabs/celatone-frontend/pull/749) Add multi-type proposals + ### Improvements ### Bug fixes From 4924a52301302cf44dff6196de70864d0f1d4aa9 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:12:49 +0700 Subject: [PATCH 008/531] fix: changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3263c6c6..1b573cdbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#750](https://github.com/alleslabs/celatone-frontend/pull/750) api v1 - recent codes list + ### Bug fixes ## v1.5.1 From f15fc69cf404f350949003bd31bfc274e076f378 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:43:19 +0700 Subject: [PATCH 009/531] feat: code list api --- src/lib/amplitude/types.ts | 2 +- src/lib/app-provider/hooks/useBaseApiRoute.ts | 9 +- src/lib/layout/mobile/NavDrawer.tsx | 2 +- .../codes/components/RecentCodesTable.tsx | 91 +++++++++++++++++++ src/lib/pages/codes/data.ts | 67 +++++++------- src/lib/pages/codes/index.tsx | 41 ++------- src/lib/query/code.ts | 20 ---- src/lib/services/code.ts | 20 +++- src/lib/services/codeService.ts | 43 ++++----- src/lib/services/publicProjectService.ts | 2 +- 10 files changed, 178 insertions(+), 119 deletions(-) create mode 100644 src/lib/pages/codes/components/RecentCodesTable.tsx diff --git a/src/lib/amplitude/types.ts b/src/lib/amplitude/types.ts index 85fb609b8..e67d65515 100644 --- a/src/lib/amplitude/types.ts +++ b/src/lib/amplitude/types.ts @@ -44,7 +44,7 @@ export enum AmpEvent { TO_MY_SAVED_CODES = "To My Saved Codes", TO_MY_STORED_CODES = "To My Stored Codes", TO_MY_SAVED_ACCOUNTS = "To My Saved Accounts", - TO_RECENT_CODES = "To Recent Codes", + TO_CODES = "To Codes", TO_CONTRACTS = "To Contracts", TO_INSTANTIATED_BY_ME = "To Instantiated By Me", TO_SAVED_CONTRACT = "To Saved Contract", diff --git a/src/lib/app-provider/hooks/useBaseApiRoute.ts b/src/lib/app-provider/hooks/useBaseApiRoute.ts index 71b0012a8..8df7b409b 100644 --- a/src/lib/app-provider/hooks/useBaseApiRoute.ts +++ b/src/lib/app-provider/hooks/useBaseApiRoute.ts @@ -9,10 +9,11 @@ export const useBaseApiRoute = ( | "accounts" | "assets" | "blocks" + | "codes" | "contracts" | "proposals" | "projects" - | "codes" + | "public_codes" | "legacy.accounts" | "rest" | "icns_names" @@ -44,13 +45,15 @@ export const useBaseApiRoute = ( return `${api}/v1/${chain}/${currentChainId}/assets`; case "blocks": return `${api}/v1/${chain}/${currentChainId}/blocks`; + case "codes": + return `${api}/v1/${chain}/${currentChainId}/wasm/codes`; case "contracts": - return `${api}/v1/${chain}/${currentChainId}/contracts`; + return `${api}/v1/${chain}/${currentChainId}/wasm/contracts`; case "proposals": return `${api}/v1/${chain}/${currentChainId}/proposals`; case "projects": return `${api}/projects/${chain}/${currentChainId}`; - case "codes": + case "public_codes": return `${api}/codes/${chain}/${currentChainId}`; case "legacy.accounts": return `${api}/accounts/${chain}/${currentChainId}`; diff --git a/src/lib/layout/mobile/NavDrawer.tsx b/src/lib/layout/mobile/NavDrawer.tsx index 5f8aaaaf3..a9a355bc4 100644 --- a/src/lib/layout/mobile/NavDrawer.tsx +++ b/src/lib/layout/mobile/NavDrawer.tsx @@ -58,7 +58,7 @@ export const NavDrawer = () => { ...(wasmConfig.enabled ? [ { - name: "Recent Codes", + name: "Codes", slug: "/codes", icon: "code" as IconKeys, }, diff --git a/src/lib/pages/codes/components/RecentCodesTable.tsx b/src/lib/pages/codes/components/RecentCodesTable.tsx new file mode 100644 index 000000000..7c04515af --- /dev/null +++ b/src/lib/pages/codes/components/RecentCodesTable.tsx @@ -0,0 +1,91 @@ +import { observer } from "mobx-react-lite"; +import { useEffect } from "react"; + +import { useRecentCodes } from "../data"; +import { useCurrentChain, useInternalNavigate } from "lib/app-provider"; +import { Pagination } from "lib/components/pagination"; +import { usePaginator } from "lib/components/pagination/usePaginator"; +import { EmptyState, ErrorFetching } from "lib/components/state"; +import { CodesTable } from "lib/components/table"; +import type { PermissionFilterValue } from "lib/hooks"; + +interface RecentCodesTableProps { + permissionValue: PermissionFilterValue; +} + +export const RecentCodesTable = observer( + ({ permissionValue }: RecentCodesTableProps) => { + const navigate = useInternalNavigate(); + const { address } = useCurrentChain(); + + const { + pagesQuantity, + setTotalData, + currentPage, + setCurrentPage, + pageSize, + setPageSize, + offset, + } = usePaginator({ + initialState: { + pageSize: 10, + currentPage: 1, + isDisabled: false, + }, + }); + const { data, isLoading } = useRecentCodes( + pageSize, + offset, + address, + permissionValue, + setTotalData + ); + + const onRowSelect = (codeId: number) => + navigate({ + pathname: "/codes/[codeId]", + query: { codeId }, + }); + + useEffect(() => { + setCurrentPage(1); + setPageSize(10); + }, [permissionValue, setCurrentPage, setPageSize]); + + return ( + <> + + ) : ( + + ) + } + onRowSelect={onRowSelect} + /> + {data && data.total > 10 && ( + { + const size = Number(e.target.value); + setPageSize(size); + setCurrentPage(1); + }} + /> + )} + + ); + } +); diff --git a/src/lib/pages/codes/data.ts b/src/lib/pages/codes/data.ts index 9360ed375..ed4c6920a 100644 --- a/src/lib/pages/codes/data.ts +++ b/src/lib/pages/codes/data.ts @@ -1,37 +1,40 @@ -import { useMemo } from "react"; - import type { PermissionFilterValue } from "lib/hooks"; -import { useCodePermissionFilter, useCodeSearchFilter } from "lib/hooks"; import { useCodeStore } from "lib/providers/store"; -import { useCodeListQuery } from "lib/services/codeService"; -import type { CodeInfo } from "lib/types"; - -interface RecentCodesData { - recentCodes: CodeInfo[]; - isLoading: boolean; -} - -export const useRecentCodesData = ( - keyword: string, - permissionValue: PermissionFilterValue -): RecentCodesData => { - const { getCodeLocalInfo, isCodeIdSaved } = useCodeStore(); - const { data: rawRecentCodes = [], isLoading } = useCodeListQuery(); - const permissionFilterFn = useCodePermissionFilter(permissionValue); - const searchFilterFn = useCodeSearchFilter(keyword); +import { useCodes } from "lib/services/codeService"; +import type { BechAddr20, CodeInfo, Option } from "lib/types"; - const recentCodes = rawRecentCodes.map((code) => ({ - ...code, - name: getCodeLocalInfo(code.id)?.name, - isSaved: isCodeIdSaved(code.id), - })); +export const useRecentCodes = ( + pageSize: number, + offset: number, + address: Option, + permissionValue: PermissionFilterValue, + setTotalData: (totalData: number) => void +) => { + const { getCodeLocalInfo } = useCodeStore(); + const { data: codes, isLoading } = useCodes( + pageSize, + offset, + address, + permissionValue === "all" + ? undefined + : permissionValue === "without-proposal", + { + onSuccess: (data) => setTotalData(data.total), + } + ); - return useMemo(() => { - return { - recentCodes: recentCodes - .filter(permissionFilterFn) - .filter(searchFilterFn), - isLoading, - }; - }, [recentCodes, isLoading, permissionFilterFn, searchFilterFn]); + if (!codes) return { data: undefined, isLoading }; + return { + data: { + items: codes.items.map((code) => { + const localInfo = getCodeLocalInfo(code.id); + return { + ...code, + name: localInfo?.name, + }; + }), + total: codes.total, + }, + isLoading, + }; }; diff --git a/src/lib/pages/codes/index.tsx b/src/lib/pages/codes/index.tsx index 2236c6cb6..2b43aed90 100644 --- a/src/lib/pages/codes/index.tsx +++ b/src/lib/pages/codes/index.tsx @@ -5,62 +5,40 @@ import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { AmpEvent, track } from "lib/amplitude"; -import { useInternalNavigate, useWasmConfig } from "lib/app-provider"; +import { useWasmConfig } from "lib/app-provider"; import { FilterByPermission } from "lib/components/forms"; import PageContainer from "lib/components/PageContainer"; -import { EmptyState } from "lib/components/state"; -import { CodesTable } from "lib/components/table"; import type { PermissionFilterValue } from "lib/hooks"; -import { useRecentCodesData } from "./data"; +import { RecentCodesTable } from "./components/RecentCodesTable"; interface RecentCodesState { - keyword: string; permissionValue: PermissionFilterValue; } const RecentCodes = observer(() => { useWasmConfig({ shouldRedirect: true }); const router = useRouter(); - const navigate = useInternalNavigate(); - const onRowSelect = (codeId: number) => - navigate({ - pathname: "/codes/[codeId]", - query: { codeId }, - }); const { watch, setValue } = useForm({ defaultValues: { permissionValue: "all", - keyword: "", }, }); - const { keyword, permissionValue } = watch(); - const { recentCodes, isLoading } = useRecentCodesData( - keyword, - permissionValue - ); + const { permissionValue } = watch(); useEffect(() => { - if (router.isReady) track(AmpEvent.TO_RECENT_CODES); + if (router.isReady) track(AmpEvent.TO_CODES); }, [router.isReady]); - const emptyState = ( - - ); - return ( - Recent Codes + Codes - Showing the 100 most recent stored codes on this network + This page displays all codes on this network sorted by recency { /> - + ); }); diff --git a/src/lib/query/code.ts b/src/lib/query/code.ts index f00bea3cf..728b741b3 100644 --- a/src/lib/query/code.ts +++ b/src/lib/query/code.ts @@ -1,25 +1,5 @@ import { graphql } from "lib/gql"; -export const getCodeListQueryDocument = graphql(` - query getCodeListQuery { - codes(limit: 100, offset: 0, order_by: { id: desc }) { - id - contracts_aggregate { - aggregate { - count - } - } - account { - uploader: address - } - access_config_permission - access_config_addresses - cw2_contract - cw2_version - } - } -`); - export const getCodeListByUserQueryDocument = graphql(` query getCodeListByUserQuery($walletAddr: String!) { codes( diff --git a/src/lib/services/code.ts b/src/lib/services/code.ts index b6427010b..d90a11bac 100644 --- a/src/lib/services/code.ts +++ b/src/lib/services/code.ts @@ -2,7 +2,7 @@ import axios from "axios"; import { z } from "zod"; import { AccessConfigPermission, zBechAddr } from "lib/types"; -import type { BechAddr, CodeInfo } from "lib/types"; +import type { BechAddr, BechAddr20, CodeInfo, Option } from "lib/types"; export interface CodeIdInfoResponse { code_info: { @@ -55,6 +55,24 @@ const zCodesResponse = z.object({ export type CodesResponse = z.infer; +export const getCodes = async ( + endpoint: string, + limit: number, + offset: number, + address: Option, + permission: Option +): Promise => + axios + .get(`${endpoint}`, { + params: { + limit, + offset, + address, + permission, + }, + }) + .then(({ data }) => zCodesResponse.parse(data)); + export const getCodesByAddress = async ( endpoint: string, address: BechAddr, diff --git a/src/lib/services/codeService.ts b/src/lib/services/codeService.ts index d254b10bc..5c99fa4fc 100644 --- a/src/lib/services/codeService.ts +++ b/src/lib/services/codeService.ts @@ -13,7 +13,6 @@ import { getCodeDataByCodeId, getCodeListByIDsQueryDocument, getCodeListByUserQueryDocument, - getCodeListQueryDocument, } from "lib/query"; import type { CodeInfo, @@ -28,31 +27,7 @@ import type { import { isId, parseDateOpt, parseTxHashOpt } from "lib/utils"; import type { CodeIdInfoResponse, CodesResponse } from "./code"; -import { getCodeIdInfo, getCodesByAddress } from "./code"; - -export const useCodeListQuery = (): UseQueryResult => { - const { indexerGraphClient } = useCelatoneApp(); - - const queryFn = useCallback(async () => { - return indexerGraphClient - .request(getCodeListQueryDocument) - .then(({ codes }) => - codes.map((code) => ({ - id: code.id, - uploader: code.account.uploader as BechAddr, - contractCount: code.contracts_aggregate.aggregate?.count, - instantiatePermission: - code.access_config_permission as AccessConfigPermission, - permissionAddresses: - code.access_config_addresses as PermissionAddresses, - cw2Contract: code.cw2_contract, - cw2Version: code.cw2_version, - })) - ); - }, [indexerGraphClient]); - - return useQuery([CELATONE_QUERY_KEYS.CODES, indexerGraphClient], queryFn); -}; +import { getCodeIdInfo, getCodes, getCodesByAddress } from "./code"; export const useCodeListByWalletAddress = ( walletAddr: Option @@ -188,6 +163,22 @@ export const useCodeDataByCodeId = ({ ); }; +export const useCodes = ( + limit: number, + offset: number, + address: Option, + permission: Option, + options?: Pick, "onSuccess"> +): UseQueryResult => { + const endpoint = useBaseApiRoute("codes"); + + return useQuery( + [CELATONE_QUERY_KEYS.CODES, endpoint, limit, offset, address, permission], + async () => getCodes(endpoint, limit, offset, address, permission), + { retry: 1, refetchOnWindowFocus: false, ...options } + ); +}; + export const useCodesByAddress = ( address: BechAddr, limit: number, diff --git a/src/lib/services/publicProjectService.ts b/src/lib/services/publicProjectService.ts index 93fa06432..26b9a6ed0 100644 --- a/src/lib/services/publicProjectService.ts +++ b/src/lib/services/publicProjectService.ts @@ -92,7 +92,7 @@ export const usePublicProjectBySlug = ( export const usePublicProjectByCodeId = ( codeId: string ): UseQueryResult => { - const projectsApiRoute = useBaseApiRoute("codes"); + const projectsApiRoute = useBaseApiRoute("public_codes"); const projectConfig = usePublicProjectConfig({ shouldRedirect: false }); const wasmConfig = useWasmConfig({ shouldRedirect: false }); From b60c037b924fd23b4623d07568f8112a591da139 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:47:29 +0700 Subject: [PATCH 010/531] fix: local --- src/lib/pages/codes/data.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/lib/pages/codes/data.ts b/src/lib/pages/codes/data.ts index ed4c6920a..96b0d792f 100644 --- a/src/lib/pages/codes/data.ts +++ b/src/lib/pages/codes/data.ts @@ -10,7 +10,7 @@ export const useRecentCodes = ( permissionValue: PermissionFilterValue, setTotalData: (totalData: number) => void ) => { - const { getCodeLocalInfo } = useCodeStore(); + const { getCodeLocalInfo, isCodeIdSaved } = useCodeStore(); const { data: codes, isLoading } = useCodes( pageSize, offset, @@ -26,13 +26,11 @@ export const useRecentCodes = ( if (!codes) return { data: undefined, isLoading }; return { data: { - items: codes.items.map((code) => { - const localInfo = getCodeLocalInfo(code.id); - return { - ...code, - name: localInfo?.name, - }; - }), + items: codes.items.map((code) => ({ + ...code, + name: getCodeLocalInfo(code.id)?.name, + isSaved: isCodeIdSaved(code.id), + })), total: codes.total, }, isLoading, From 61b54ab72c82400a91efee6108bb42f4e684a99c Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Thu, 25 Jan 2024 18:45:08 +0700 Subject: [PATCH 011/531] fix: tx logs and stone-12-1 --- CHANGELOG.md | 2 + src/config/chain/initia.ts | 56 +------------------ src/lib/chain-registry/initiatestnet.ts | 47 ---------------- .../tx-details/components/MessageSection.tsx | 4 +- .../components/tx-message/TxMsgExpand.tsx | 2 +- .../components/tx-message/index.tsx | 3 +- src/lib/utils/tx/extractTxLogs.ts | 35 ++++++------ 7 files changed, 26 insertions(+), 123 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b573cdbd..1fd527f7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Bug fixes +- [#751](https://github.com/alleslabs/celatone-frontend/pull/751) Fix fail txs should have no logs and remove stone-12-1 + ## v1.5.1 ### Improvements diff --git a/src/config/chain/initia.ts b/src/config/chain/initia.ts index 40d6c0481..49935251d 100644 --- a/src/config/chain/initia.ts +++ b/src/config/chain/initia.ts @@ -10,7 +10,7 @@ export const INITIA_CHAIN_CONFIGS: ChainConfigs = { "mahalo-1": { chain: "initia", registryChainName: "initiadevnet1", - prettyName: "Initia Closed Testnet 1", + prettyName: "Initia Devnet 1", lcd: "https://lcd.mahalo-1.initia.xyz", rpc: "https://rpc.mahalo-1.initia.xyz:443", indexer: "https://mahalo-1-graphql.alleslabs.dev/v1/graphql", @@ -60,7 +60,7 @@ export const INITIA_CHAIN_CONFIGS: ChainConfigs = { "minimove-1": { chain: "initia", registryChainName: "minitiamovedevnet1", - prettyName: "Minitia Move Closed Testnet 1", + prettyName: "Minitia Move Devnet 1", lcd: "https://lcd.minimove-1.initia.xyz", rpc: "https://rpc.minimove-1.initia.xyz:443", indexer: "https://minimove-1-graphql.alleslabs.dev/v1/graphql", @@ -110,7 +110,7 @@ export const INITIA_CHAIN_CONFIGS: ChainConfigs = { "miniwasm-1": { chain: "initia", registryChainName: "minitiawasmdevnet1", - prettyName: "Minitia Wasm Closed Testnet 1", + prettyName: "Minitia Wasm Devnet 1", lcd: "https://lcd.miniwasm-1.initia.xyz", rpc: "https://rpc.miniwasm-1.initia.xyz:443", indexer: "https://miniwasm-1-graphql.alleslabs.dev/v1/graphql", @@ -156,56 +156,6 @@ export const INITIA_CHAIN_CONFIGS: ChainConfigs = { }, extra: { disableDelegation: true }, }, - "stone-12-1": { - chain: "initia", - registryChainName: "initiatestnet12-1", - prettyName: "Initia Testnet 12-1", - lcd: "https://next-stone-rest.initia.tech", - rpc: "https://next-stone-rpc.initia.tech:443", - indexer: "https://stone-12-1-nft-graphql.alleslabs.dev/v1/graphql", - wallets: [...initiaWallets, ...keplrWallets], - features: { - faucet: { - enabled: true, - url: process.env.NEXT_PUBLIC_INITIA_TESTNET_FAUCET_URL ?? "", - }, - wasm: { - enabled: false, - }, - move: { - enabled: true, - moduleMaxFileSize: 1_048_576, - decodeApi: INITIA_DECODER, - verify: "https://stone-compiler.initia.tech/contracts/verify", - }, - pool: { - enabled: false, - }, - publicProject: { - enabled: true, - }, - gov: { - enabled: true, - hideOpenProposal: true, - }, - nft: { - enabled: true, - }, - }, - gas: { - gasPrice: { - tokenPerGas: 0.151, - denom: "uinit", - }, - gasAdjustment: 1.5, - maxGasLimit: 25_000_000, - }, - explorerLink: { - validator: "https://next.app.initia.tech/validator", - proposal: "https://next.app.initia.tech/proposal", - }, - extra: {}, - }, "stone-13": { chain: "initia", registryChainName: "initiatestnet13", diff --git a/src/lib/chain-registry/initiatestnet.ts b/src/lib/chain-registry/initiatestnet.ts index a54ddd4bc..b75ca5ec8 100644 --- a/src/lib/chain-registry/initiatestnet.ts +++ b/src/lib/chain-registry/initiatestnet.ts @@ -136,53 +136,6 @@ export const initiatestnet: Chain[] = [ ], }, }, - { - $schema: CHAIN_SCHEMA, - chain_name: "initiatestnet12-1", - status: "live", - network_type: "testnet", - pretty_name: "Initia Testnet 12-1", - chain_id: "stone-12-1", - bech32_prefix: "init", - daemon_name: "initiad", - node_home: NODE_HOME, - key_algos: ["secp256k1"], - slip44: 118, - fees: { - fee_tokens: [ - { - denom: "uinit", - fixed_min_gas_price: 0, - low_gas_price: 0.151, - average_gas_price: 0.151, - high_gas_price: 0.151, - }, - ], - }, - staking: { - staking_tokens: [ - { - denom: "uinit", - }, - ], - }, - logo_URIs: { - png: "", - svg: "", - }, - apis: { - rpc: [ - { - address: "https://next-stone-rpc.initia.tech:443", - }, - ], - rest: [ - { - address: "https://next-stone-rest.initia.tech", - }, - ], - }, - }, { $schema: CHAIN_SCHEMA, chain_name: "initiatestnet13", diff --git a/src/lib/pages/tx-details/components/MessageSection.tsx b/src/lib/pages/tx-details/components/MessageSection.tsx index 524154caf..f877bd060 100644 --- a/src/lib/pages/tx-details/components/MessageSection.tsx +++ b/src/lib/pages/tx-details/components/MessageSection.tsx @@ -47,9 +47,9 @@ export const MessageSection = ({ txData }: MessageSectionProps) => { {messages.map((msg, idx) => ( log.msg_index === idx)} isSingleMsg={messages.length === 1} /> ))} diff --git a/src/lib/pages/tx-details/components/tx-message/TxMsgExpand.tsx b/src/lib/pages/tx-details/components/tx-message/TxMsgExpand.tsx index 2e3216b5d..54b2e410d 100644 --- a/src/lib/pages/tx-details/components/tx-message/TxMsgExpand.tsx +++ b/src/lib/pages/tx-details/components/tx-message/TxMsgExpand.tsx @@ -41,7 +41,7 @@ export const TxMsgExpand = ({ const { "@type": type, ...body } = msgBody; const isIBC = - Boolean(log.events.find((event) => event.type === "send_packet")) || + Boolean(log?.events.find((event) => event.type === "send_packet")) || type.startsWith("/ibc"); const isOpinit = Boolean(type.startsWith("/opinit")); diff --git a/src/lib/pages/tx-details/components/tx-message/index.tsx b/src/lib/pages/tx-details/components/tx-message/index.tsx index 7403265d2..448c2cab5 100644 --- a/src/lib/pages/tx-details/components/tx-message/index.tsx +++ b/src/lib/pages/tx-details/components/tx-message/index.tsx @@ -3,13 +3,14 @@ import type { logs } from "@cosmjs/stargate"; import { useState } from "react"; import type { MsgBody } from "lib/services/tx"; +import type { Option } from "lib/types"; import { TxMsgDetails } from "./TxMsgDetails"; import { TxMsgExpand } from "./TxMsgExpand"; export interface TxMsgData { msgBody: MsgBody; - log: logs.Log; + log: Option; isSingleMsg?: boolean; } diff --git a/src/lib/utils/tx/extractTxLogs.ts b/src/lib/utils/tx/extractTxLogs.ts index 64ced80d7..032de98ce 100644 --- a/src/lib/utils/tx/extractTxLogs.ts +++ b/src/lib/utils/tx/extractTxLogs.ts @@ -3,26 +3,23 @@ import type { Event, logs } from "@cosmjs/stargate"; import type { TxResponse } from "lib/services/tx"; export const extractTxLogs = (txData: TxResponse): logs.Log[] => { - const msgLogs = txData.tx.body.messages.map((_, idx) => ({ - msg_index: idx, - log: "", - events: [] as Event[], - })); + if (txData.logs.length > 0) return txData.logs; - if (txData.logs.length > 0) - txData.logs.forEach((log) => - msgLogs[log.msg_index].events.push(...log.events) - ); - else - txData.events.forEach((event) => { - const attribute = event.attributes.find( - (attr) => attr.key === "msg_index" - ); - if (attribute) { - const index = Number(attribute.value); - msgLogs[index].events.push(event); + const logs: Record = {}; + txData.events.forEach((event) => { + const attribute = event.attributes.find((attr) => attr.key === "msg_index"); + if (attribute) { + const index = attribute.value; + if (!Object.keys(logs).includes(attribute.value)) { + logs[index] = { + msg_index: Number(index), + log: "", + events: [] as Event[], + }; } - }); + logs[index].events.push(event); + } + }); - return msgLogs; + return Object.values(logs).toSorted((a, b) => a.msg_index - b.msg_index); }; From 3aee001fe5f8a90d1e37d286cdd007c9a2d119f3 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Thu, 25 Jan 2024 21:43:09 +0700 Subject: [PATCH 012/531] fix: empty case fn --- src/lib/utils/tx/extractTxLogs.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/lib/utils/tx/extractTxLogs.ts b/src/lib/utils/tx/extractTxLogs.ts index 032de98ce..ec168584e 100644 --- a/src/lib/utils/tx/extractTxLogs.ts +++ b/src/lib/utils/tx/extractTxLogs.ts @@ -2,24 +2,31 @@ import type { Event, logs } from "@cosmjs/stargate"; import type { TxResponse } from "lib/services/tx"; +interface Log extends logs.Log { + events: Event[]; +} + export const extractTxLogs = (txData: TxResponse): logs.Log[] => { if (txData.logs.length > 0) return txData.logs; - const logs: Record = {}; + const logs: Record = {}; txData.events.forEach((event) => { - const attribute = event.attributes.find((attr) => attr.key === "msg_index"); - if (attribute) { - const index = attribute.value; - if (!Object.keys(logs).includes(attribute.value)) { + const index = event.attributes.find( + (attr) => attr.key === "msg_index" + )?.value; + if (index) { + if (!logs[index]) logs[index] = { msg_index: Number(index), log: "", - events: [] as Event[], + events: [], }; - } + logs[index].events.push(event); } }); - return Object.values(logs).toSorted((a, b) => a.msg_index - b.msg_index); + const msgLogs = Object.values(logs); + msgLogs.sort((a, b) => a.msg_index - b.msg_index); + return msgLogs; }; From d2383a11bc33964f8880f46f8bfbe1781b1b2354 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Fri, 26 Jan 2024 12:11:24 +0700 Subject: [PATCH 013/531] fix(components): fix as comment --- .../components/ProposalDetailsBody.tsx | 82 ------------------ .../components/ValidatorVotesTable.tsx | 1 + .../components/VoteDetailTab.tsx | 8 +- .../proposal-details/components/index.ts | 1 + src/lib/pages/proposal-details/index.tsx | 86 +++++++++++++++++-- src/pages/[network]/proposals/[id]/[tab].tsx | 2 +- src/pages/[network]/proposals/[id]/index.tsx | 2 +- src/pages/proposals/[id]/[tab].tsx | 2 +- src/pages/proposals/[id]/index.tsx | 2 +- 9 files changed, 88 insertions(+), 98 deletions(-) delete mode 100644 src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx create mode 100644 src/lib/pages/proposal-details/components/index.ts diff --git a/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx b/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx deleted file mode 100644 index 43aa40a40..000000000 --- a/src/lib/pages/proposal-details/components/ProposalDetailsBody.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"; -import { useRouter } from "next/router"; -import { useCallback, useEffect } from "react"; - -import type { ProposalDetailsQueryParams } from "../type"; -import { TabIndex } from "../type"; -import { useInternalNavigate } from "lib/app-provider"; -import { CustomTab } from "lib/components/CustomTab"; - -import { ProposalOverview } from "./ProposalOverview"; -import { VoteDetail } from "./VoteDetail"; - -export const ProposalDetailBody = ({ - id, - tab, - // voteTab, -}: ProposalDetailsQueryParams) => { - const router = useRouter(); - const navigate = useInternalNavigate(); - - const handleTabChange = useCallback( - (nextTab: TabIndex) => () => { - if (nextTab === tab) return; - navigate({ - pathname: "/proposals/[id]/[tab]", - query: { - id, - tab: nextTab, - }, - options: { - shallow: true, - }, - }); - }, - [id, tab, navigate] - ); - - useEffect(() => { - if (router.isReady && (!tab || !Object.values(TabIndex).includes(tab))) { - navigate({ - replace: true, - pathname: "/proposals/[id]/[tab]", - query: { - id, - tab: TabIndex.Overview, - }, - options: { - shallow: true, - }, - }); - } - }, [router.isReady, tab, navigate, id]); - - return ( - - - - Proposal Overview - - - Vote Detail - - - - - - - - - - - - ); -}; diff --git a/src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx b/src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx index 249f3d555..c8e0bb416 100644 --- a/src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx +++ b/src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx @@ -8,6 +8,7 @@ import { TableTitle } from "lib/components/table"; interface ValidatorVotesTableProps extends FlexProps { onBack: () => void; } + export const ValidatorVotesTable = ({ onBack, ...props diff --git a/src/lib/pages/proposal-details/components/VoteDetailTab.tsx b/src/lib/pages/proposal-details/components/VoteDetailTab.tsx index 9a9660c46..ddb479be3 100644 --- a/src/lib/pages/proposal-details/components/VoteDetailTab.tsx +++ b/src/lib/pages/proposal-details/components/VoteDetailTab.tsx @@ -1,12 +1,12 @@ import type { TabProps } from "@chakra-ui/react"; import { Button, useTab, useMultiStyleConfig } from "@chakra-ui/react"; -import type { Nullish } from "lib/types"; +import type { Nullable } from "lib/types"; import { ProposalStepper } from "./ProposalStepper"; -interface CustomTabProps extends TabProps { - count?: Nullish; +interface VoteDetailTabProps extends TabProps { + count?: Nullable; isLoading?: boolean; title: string; description: string; @@ -20,7 +20,7 @@ export const VoteDetailTab = ({ description, step, ...restProps -}: CustomTabProps) => { +}: VoteDetailTabProps) => { const tabProps = useTab({ ...restProps }); const styles = useMultiStyleConfig("Tabs", tabProps); diff --git a/src/lib/pages/proposal-details/components/index.ts b/src/lib/pages/proposal-details/components/index.ts new file mode 100644 index 000000000..f3e755726 --- /dev/null +++ b/src/lib/pages/proposal-details/components/index.ts @@ -0,0 +1 @@ +export * from "./ProposalTop"; diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index b6acc4d7a..60a50b212 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -1,28 +1,96 @@ +import { TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"; import { useRouter } from "next/router"; +import { useCallback, useEffect } from "react"; +import { useInternalNavigate } from "lib/app-provider"; +import { CustomTab } from "lib/components/CustomTab"; import PageContainer from "lib/components/PageContainer"; import { InvalidState } from "lib/components/state"; -import { ProposalDetailBody } from "./components/ProposalDetailsBody"; -import { ProposalTop } from "./components/ProposalTop"; +import { ProposalTop } from "./components"; +import { ProposalOverview } from "./components/ProposalOverview"; +import { VoteDetail } from "./components/VoteDetail"; import type { ProposalDetailsQueryParams } from "./type"; -import { zProposalDetailsQueryParams } from "./type"; +import { zProposalDetailsQueryParams, TabIndex } from "./type"; const ProposalDetailsBody = ({ id, tab, - voteTab, + // voteTab, }: ProposalDetailsQueryParams) => { - // TODO Mock up - if (id === 999) return ; + const router = useRouter(); + const navigate = useInternalNavigate(); + + const handleTabChange = useCallback( + (nextTab: TabIndex) => () => { + if (nextTab === tab) return; + navigate({ + pathname: "/proposals/[id]/[tab]", + query: { + id, + tab: nextTab, + }, + options: { + shallow: true, + }, + }); + }, + [id, tab, navigate] + ); + + useEffect(() => { + if (router.isReady && (!tab || !Object.values(TabIndex).includes(tab))) { + navigate({ + replace: true, + pathname: "/proposals/[id]/[tab]", + query: { + id, + tab: TabIndex.Overview, + }, + options: { + shallow: true, + }, + }); + } + }, [router.isReady, tab, navigate, id]); + + // TODO mock up data + if (id > 9999) return ; + return ( <> - + + + + Proposal Overview + + + Vote Detail + + + + + + + + + + + ); }; -export const ProposalDetails = () => { + +const ProposalDetails = () => { const router = useRouter(); const validated = zProposalDetailsQueryParams.safeParse(router.query); @@ -37,3 +105,5 @@ export const ProposalDetails = () => { ); }; + +export default ProposalDetails; diff --git a/src/pages/[network]/proposals/[id]/[tab].tsx b/src/pages/[network]/proposals/[id]/[tab].tsx index a44532bda..06eb5134c 100644 --- a/src/pages/[network]/proposals/[id]/[tab].tsx +++ b/src/pages/[network]/proposals/[id]/[tab].tsx @@ -1,3 +1,3 @@ -import { ProposalDetails } from "lib/pages/proposal-details"; +import ProposalDetails from "lib/pages/proposal-details"; export default ProposalDetails; diff --git a/src/pages/[network]/proposals/[id]/index.tsx b/src/pages/[network]/proposals/[id]/index.tsx index a44532bda..06eb5134c 100644 --- a/src/pages/[network]/proposals/[id]/index.tsx +++ b/src/pages/[network]/proposals/[id]/index.tsx @@ -1,3 +1,3 @@ -import { ProposalDetails } from "lib/pages/proposal-details"; +import ProposalDetails from "lib/pages/proposal-details"; export default ProposalDetails; diff --git a/src/pages/proposals/[id]/[tab].tsx b/src/pages/proposals/[id]/[tab].tsx index a44532bda..06eb5134c 100644 --- a/src/pages/proposals/[id]/[tab].tsx +++ b/src/pages/proposals/[id]/[tab].tsx @@ -1,3 +1,3 @@ -import { ProposalDetails } from "lib/pages/proposal-details"; +import ProposalDetails from "lib/pages/proposal-details"; export default ProposalDetails; diff --git a/src/pages/proposals/[id]/index.tsx b/src/pages/proposals/[id]/index.tsx index a44532bda..06eb5134c 100644 --- a/src/pages/proposals/[id]/index.tsx +++ b/src/pages/proposals/[id]/index.tsx @@ -1,3 +1,3 @@ -import { ProposalDetails } from "lib/pages/proposal-details"; +import ProposalDetails from "lib/pages/proposal-details"; export default ProposalDetails; From 25a7309af9dfd28180dc7b48dcce07c05c982936 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 12:27:19 +0700 Subject: [PATCH 014/531] fix: comment --- src/lib/chain-registry/initiatestnet.ts | 23 --- .../tx/__test__/extractTxLogs.example.ts | 176 ++++++++++++++++++ .../utils/tx/__test__/extractTxLogs.test.ts | 11 +- 3 files changed, 186 insertions(+), 24 deletions(-) diff --git a/src/lib/chain-registry/initiatestnet.ts b/src/lib/chain-registry/initiatestnet.ts index b75ca5ec8..ee61fe1bf 100644 --- a/src/lib/chain-registry/initiatestnet.ts +++ b/src/lib/chain-registry/initiatestnet.ts @@ -259,29 +259,6 @@ export const initiatestnetAssets: AssetList[] = [ }, ], }, - { - $schema: ASSETLIST_SCHEMA, - chain_name: "initiatestnet12-1", - assets: [ - { - description: "The native staking token of Initia.", - denom_units: [ - { - denom: "uinit", - exponent: 0, - }, - { - denom: "init", - exponent: 6, - }, - ], - base: "uinit", - name: "Init", - display: "init", - symbol: "INIT", - }, - ], - }, { $schema: ASSETLIST_SCHEMA, chain_name: "initiatestnet13", diff --git a/src/lib/utils/tx/__test__/extractTxLogs.example.ts b/src/lib/utils/tx/__test__/extractTxLogs.example.ts index cfadfe752..5c91c9c52 100644 --- a/src/lib/utils/tx/__test__/extractTxLogs.example.ts +++ b/src/lib/utils/tx/__test__/extractTxLogs.example.ts @@ -361,6 +361,182 @@ export const fromLogs: TestCase = { ], }; +export const fromLogsTxFailed: TestCase = { + txData: { + code: 10, + codespace: "gov", + data: "", + events: [ + { + attributes: [ + { + key: "c3BlbmRlcg==", + value: + "b3NtbzFnMmdkemhocXYzOHFhdThubjI5NXp2ZWdzbmZ2NnU0am02dW1qNw==", + }, + { + key: "YW1vdW50", + value: "MjI1MDAwdW9zbW8=", + }, + ], + type: "coin_spent", + }, + { + attributes: [ + { + key: "cmVjZWl2ZXI=", + value: + "b3NtbzE3eHBmdmFrbTJhbWc5NjJ5bHM2Zjg0ejNrZWxsOGM1bGN6c3NhMA==", + }, + { + key: "YW1vdW50", + value: "MjI1MDAwdW9zbW8=", + }, + ], + type: "coin_received", + }, + { + attributes: [ + { + key: "cmVjaXBpZW50", + value: + "b3NtbzE3eHBmdmFrbTJhbWc5NjJ5bHM2Zjg0ejNrZWxsOGM1bGN6c3NhMA==", + }, + { + key: "c2VuZGVy", + value: + "b3NtbzFnMmdkemhocXYzOHFhdThubjI5NXp2ZWdzbmZ2NnU0am02dW1qNw==", + }, + { + key: "YW1vdW50", + value: "MjI1MDAwdW9zbW8=", + }, + ], + type: "transfer", + }, + { + attributes: [ + { + key: "c2VuZGVy", + value: + "b3NtbzFnMmdkemhocXYzOHFhdThubjI5NXp2ZWdzbmZ2NnU0am02dW1qNw==", + }, + ], + type: "message", + }, + { + attributes: [ + { + key: "ZmVl", + value: "MjI1MDAwdW9zbW8=", + }, + ], + type: "tx", + }, + { + attributes: [ + { + key: "YWNjX3NlcQ==", + value: + "b3NtbzFnMmdkemhocXYzOHFhdThubjI5NXp2ZWdzbmZ2NnU0am02dW1qNy80", + }, + ], + type: "tx", + }, + { + attributes: [ + { + key: "c2lnbmF0dXJl", + value: + "elkxQXk2SHRJaWtveno0NUV0WFpKMk91TlRyR0hwQkZEY1pWc3JxWDU2TXdJN0ZmeitKS0lKdzBRSGFVUkNLRmpBbkVhNDhkRzZWQzIrVTkvTnhIeGc9PQ==", + }, + ], + type: "tx", + }, + ], + gas_used: "706339", + gas_wanted: "9000000", + height: "5902531", + info: "", + logs: [], + raw_log: + "failed to execute message; message index: 0: was (1000uosmo), need (400000000uosmo): minimum deposit is too small", + timestamp: parseDate("2022-09-06T09:03:15Z"), + tx: { + "@type": "/cosmos.tx.v1beta1.Tx", + auth_info: { + fee: { + amount: [ + { + amount: "225000", + denom: "uosmo", + }, + ], + gas_limit: "9000000", + granter: "", + payer: "", + }, + signer_infos: [ + { + mode_info: { + single: { + mode: "SIGN_MODE_DIRECT", + }, + }, + public_key: { + "@type": "/cosmos.crypto.secp256k1.PubKey", + key: "A0KHudvOKFXLps3gbcvvMwLy7Tm05wUfuGmNKiszslQ4", + }, + sequence: "4", + }, + ], + }, + body: { + extension_options: [], + memo: "", + messages: [ + { + "@type": "/cosmos.gov.v1beta1.MsgSubmitProposal", + content: { + "@type": "/cosmwasm.wasm.v1.StoreCodeProposal", + builder: "", + code_hash: null, + description: + "We are Band Protocol and would like to propose the upload of oracle base contract. This contract is for receiving price relay from BandChain and we're not recommend anyone to reference price from this contract. The oracle contract code can be found here: [https://github.com/bandprotocol/band-stdreference-contracts-cosmwasm/tree/main/std_reference_basic](https://github.com/bandprotocol/band-stdreference-contracts-cosmwasm/tree/main/std_reference_basic)", + instantiate_permission: { + address: "osmo1jkw02jjluu733radeg6vx6zqyg42awg2sy3k3e", + addresses: [], + permission: "OnlyAddress", + }, + run_as: "osmo1g2gdzhhqv38qau8nn295zvegsnfv6u4jm6umj7", + source: "", + title: "Upload Oracle StdReferenceBasic Contract", + unpin_code: false, + wasm_byte_code: + "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", + }, + initial_deposit: [ + { + amount: "1000", + denom: "uosmo", + }, + ], + is_expedited: false, + proposer: "osmo1g2gdzhhqv38qau8nn295zvegsnfv6u4jm6umj7", + }, + ], + non_critical_extension_options: [], + timeout_height: "0", + }, + signatures: [ + "zY1Ay6HtIikozz45EtXZJ2OuNTrGHpBFDcZVsrqX56MwI7Ffz+JKIJw0QHaURCKFjAnEa48dG6VC2+U9/NxHxg==", + ], + }, + txhash: "4722758776F36276F617D6018E6AC7D4C1491B31267E7EB5CCC8CD93288F1B63", + }, + result: [], +}; + export const fromEvents: TestCase = { txData: { code: 0, diff --git a/src/lib/utils/tx/__test__/extractTxLogs.test.ts b/src/lib/utils/tx/__test__/extractTxLogs.test.ts index dde869309..1511a2ea4 100644 --- a/src/lib/utils/tx/__test__/extractTxLogs.test.ts +++ b/src/lib/utils/tx/__test__/extractTxLogs.test.ts @@ -1,11 +1,20 @@ import { extractTxLogs } from "../extractTxLogs"; -import { fromLogs, fromEvents } from "./extractTxLogs.example"; +import { + fromLogs, + fromLogsTxFailed, + fromEvents, +} from "./extractTxLogs.example"; describe("extractTxLogs", () => { test("from logs", () => { expect(extractTxLogs(fromLogs.txData)).toEqual(fromLogs.result); }); + test("from logs Tx Failed", () => { + expect(extractTxLogs(fromLogsTxFailed.txData)).toEqual( + fromLogsTxFailed.result + ); + }); test("from events", () => { expect(extractTxLogs(fromEvents.txData)).toEqual(fromEvents.result); }); From 502ab4c10aa6e02a2f58d232369d6bc24e3b11a6 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 13:15:33 +0700 Subject: [PATCH 015/531] feat: multi-type proposal --- .../table/proposals/ProposalTextCell.tsx | 6 ++-- .../proposals/ProposalsTableMobileCard.tsx | 10 +++--- .../table/proposals/ProposalsTableRow.tsx | 4 +-- src/lib/services/proposal.ts | 31 ++----------------- src/lib/services/proposalService.ts | 3 +- src/lib/types/proposal.ts | 2 +- 6 files changed, 17 insertions(+), 39 deletions(-) diff --git a/src/lib/components/table/proposals/ProposalTextCell.tsx b/src/lib/components/table/proposals/ProposalTextCell.tsx index cea121fd6..a2c846365 100644 --- a/src/lib/components/table/proposals/ProposalTextCell.tsx +++ b/src/lib/components/table/proposals/ProposalTextCell.tsx @@ -6,14 +6,14 @@ import { Expedited } from "lib/components/Expedited"; interface ProposalTextCellProps { title: string; - type: string; + types: string[]; isExpedited: boolean; isDepositOrVoting: boolean; } export const ProposalTextCell = ({ title, - type, + types, isExpedited, isDepositOrVoting, }: ProposalTextCellProps) => { @@ -69,7 +69,7 @@ export const ProposalTextCell = ({ maxW={showName ? undefined : "full"} className={showName ? undefined : "ellipsis"} > - {type} + {types.join(", ")} diff --git a/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx b/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx index 5ea14c885..81cc92a53 100644 --- a/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx +++ b/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx @@ -53,9 +53,11 @@ export const ProposalsTableMobileCard = ({ {proposal.title} - - {proposal.type} - + {proposal.types.map((msgType) => ( + + {msgType} + + ))} @@ -86,7 +88,7 @@ export const ProposalsTableMobileCard = ({ !isDepositFailed ? () => { trackMintScan("proposal-detail", { - type: proposal.type, + types: proposal.types, status: proposal.status, }); // TOOD: revisit retrieving url (make a proper hook) diff --git a/src/lib/components/table/proposals/ProposalsTableRow.tsx b/src/lib/components/table/proposals/ProposalsTableRow.tsx index 4c71295f2..925ac4811 100644 --- a/src/lib/components/table/proposals/ProposalsTableRow.tsx +++ b/src/lib/components/table/proposals/ProposalsTableRow.tsx @@ -54,7 +54,7 @@ export const ProposalsTableRow = ({ !isDepositFailed ? () => { trackMintScan("proposal-detail", { - type: proposal.type, + types: proposal.types, status: proposal.status, }); // TOOD: revisit retrieving url (make a proper hook) @@ -86,7 +86,7 @@ export const ProposalsTableRow = ({ > diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 6c2d04be7..38f9df548 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -76,7 +76,7 @@ const zProposalsResponseItem = z resolved_height: z.number().nullable(), status: zProposalStatus, title: z.string(), - type: zProposalType, + types: zProposalType.array(), voting_end_time: zUtcDate.nullable(), }) .transform((val) => ({ @@ -87,7 +87,7 @@ const zProposalsResponseItem = z resolvedHeight: val.resolved_height, status: val.status, title: val.title, - type: val.type, + types: val.types, votingEndTime: val.voting_end_time, })); @@ -135,34 +135,9 @@ export const getProposalsByAddress = async ( }) .then(({ data }) => zProposalsResponse.parse(data)); -const zRelatedProposalsResponseItem = z - .object({ - deposit_end_time: zUtcDate, - proposal_id: z.number().nonnegative(), - is_expedited: z.boolean(), - proposer: zBechAddr, - resolved_height: z.number().nullable(), - status: zProposalStatus, - title: z.string(), - type: zProposalType, - voting_end_time: zUtcDate, - }) - .transform((val) => ({ - depositEndTime: val.deposit_end_time, - proposalId: val.proposal_id, - isExpedited: val.is_expedited, - proposer: val.proposer, - resolvedHeight: val.resolved_height, - status: val.status, - title: val.title, - type: val.type, - votingEndTime: val.voting_end_time, - })); - const zRelatedProposalsResponse = z.object({ - items: z.array(zRelatedProposalsResponseItem), + items: z.array(zProposalsResponseItem), }); - export type RelatedProposalsResponse = z.infer< typeof zRelatedProposalsResponse >; diff --git a/src/lib/services/proposalService.ts b/src/lib/services/proposalService.ts index e07656621..7b01b2007 100644 --- a/src/lib/services/proposalService.ts +++ b/src/lib/services/proposalService.ts @@ -160,7 +160,8 @@ export const useRelatedProposalsByModuleIdPagination = ( votingEndTime: parseDate(proposal.proposal.voting_end_time), depositEndTime: parseDate(proposal.proposal.deposit_end_time), resolvedHeight: proposal.proposal.resolved_height ?? null, - type: proposal.proposal.type as ProposalType, + // TODO: fix + types: [proposal.proposal.type as ProposalType], proposer: proposal.proposal.account?.address as BechAddr, isExpedited: Boolean(proposal.proposal.is_expedited), })) diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 30d7ae24f..bdf7f66de 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -63,7 +63,7 @@ export interface Proposal { votingEndTime: Nullable; depositEndTime: Date; resolvedHeight: Nullable; - type: ProposalType; + types: ProposalType[]; proposer: Option; isExpedited: boolean; } From d874c573f4799d1b233c9f09795467f5befeb5e2 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 13:29:06 +0700 Subject: [PATCH 016/531] fix: type --- src/lib/components/table/proposals/ProposalTextCell.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/components/table/proposals/ProposalTextCell.tsx b/src/lib/components/table/proposals/ProposalTextCell.tsx index a2c846365..4057d1c51 100644 --- a/src/lib/components/table/proposals/ProposalTextCell.tsx +++ b/src/lib/components/table/proposals/ProposalTextCell.tsx @@ -3,10 +3,11 @@ import { useRef, useState } from "react"; import { DotSeparator } from "lib/components/DotSeparator"; import { Expedited } from "lib/components/Expedited"; +import type { ProposalType } from "lib/types"; interface ProposalTextCellProps { title: string; - types: string[]; + types: ProposalType[]; isExpedited: boolean; isDepositOrVoting: boolean; } From 2a793a2d9951ef9e06ad3e02162cf8f57b993145 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 13:30:42 +0700 Subject: [PATCH 017/531] fix: change separator --- src/lib/components/table/proposals/ProposalTextCell.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/table/proposals/ProposalTextCell.tsx b/src/lib/components/table/proposals/ProposalTextCell.tsx index 4057d1c51..01ed24a35 100644 --- a/src/lib/components/table/proposals/ProposalTextCell.tsx +++ b/src/lib/components/table/proposals/ProposalTextCell.tsx @@ -70,7 +70,7 @@ export const ProposalTextCell = ({ maxW={showName ? undefined : "full"} className={showName ? undefined : "ellipsis"} > - {types.join(", ")} + {types.join(" / ")} From 1b1c33bc50196668661d33d069d785576faac1c4 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 14:15:44 +0700 Subject: [PATCH 018/531] fix: reset pagination --- .../table/proposals/ProposalsTableMobileCard.tsx | 9 +++++++-- src/lib/pages/proposals/index.tsx | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx b/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx index 81cc92a53..d8367cfa3 100644 --- a/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx +++ b/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx @@ -53,8 +53,13 @@ export const ProposalsTableMobileCard = ({ {proposal.title} - {proposal.types.map((msgType) => ( - + {proposal.types.map((msgType, index) => ( + {msgType} ))} diff --git a/src/lib/pages/proposals/index.tsx b/src/lib/pages/proposals/index.tsx index 7988bd1bb..124176f00 100644 --- a/src/lib/pages/proposals/index.tsx +++ b/src/lib/pages/proposals/index.tsx @@ -80,6 +80,20 @@ const Proposals = () => { setSearch(""); }, [currentChainId, address]); + useEffect(() => { + setCurrentPage(1); + setPageSize(10); + }, [ + proposer, + // eslint-disable-next-line react-hooks/exhaustive-deps + JSON.stringify(statuses), + // eslint-disable-next-line react-hooks/exhaustive-deps + JSON.stringify(types), + debouncedSearch, + setCurrentPage, + setPageSize, + ]); + return ( From 8cb7ca10c251c8e5213cd39d677ca1b05c59e7cf Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 14:41:17 +0700 Subject: [PATCH 019/531] fix: logic and add test --- .../tx/__test__/extractTxLogs.example.ts | 203 ++++++++++++++++++ .../utils/tx/__test__/extractTxLogs.test.ts | 6 + src/lib/utils/tx/extractTxLogs.ts | 29 +-- 3 files changed, 220 insertions(+), 18 deletions(-) diff --git a/src/lib/utils/tx/__test__/extractTxLogs.example.ts b/src/lib/utils/tx/__test__/extractTxLogs.example.ts index 5c91c9c52..9e55252c1 100644 --- a/src/lib/utils/tx/__test__/extractTxLogs.example.ts +++ b/src/lib/utils/tx/__test__/extractTxLogs.example.ts @@ -872,3 +872,206 @@ export const fromEvents: TestCase = { }, ], }; + +export const fromEventsTxFailed: TestCase = { + txData: { + code: 1, + codespace: "undefined", + data: "", + events: [ + { + attributes: [ + { + key: "sender", + value: "0xb9fe1fd018852d49cd066379ba314f94dce57f16", + }, + { + key: "module_addr", + value: "0x1", + }, + { + key: "module_name", + value: "coin", + }, + { + key: "function_name", + value: "transfer", + }, + ], + type: "execute", + }, + { + attributes: [ + { + key: "type_tag", + value: "0x1::fungible_asset::WithdrawEvent", + }, + { + key: "data", + value: + '{"store_addr":"0xb3a18ed65a760faa12b9fa834f53ac6b413e05e416c29d14488aa45d76f15dd3","metadata_addr":"0x8e4733bdabcf7d4afc3d14f0dd46c9bf52fb0fce9e4b996c939e195b8bc891d9","amount":"750000"}', + }, + ], + type: "move", + }, + { + attributes: [ + { + key: "type_tag", + value: "0x1::fungible_asset::DepositEvent", + }, + { + key: "data", + value: + '{"store_addr":"0x66a8cb0bfb991610dcffb8a6543ac0887c7c5405b8f985ebed6d628fe50c4686","metadata_addr":"0x8e4733bdabcf7d4afc3d14f0dd46c9bf52fb0fce9e4b996c939e195b8bc891d9","amount":"750000"}', + }, + ], + type: "move", + }, + { + attributes: [ + { + key: "spender", + value: "init1h8lpl5qcs5k5nngxvdum5v20jnww2lckg3n2ta", + }, + { + key: "amount", + value: "750000uinit", + }, + ], + type: "coin_spent", + }, + { + attributes: [ + { + key: "receiver", + value: "init17xpfvakm2amg962yls6f84z3kell8c5l70rnql", + }, + { + key: "amount", + value: "750000uinit", + }, + ], + type: "coin_received", + }, + { + attributes: [ + { + key: "recipient", + value: "init17xpfvakm2amg962yls6f84z3kell8c5l70rnql", + }, + { + key: "sender", + value: "init1h8lpl5qcs5k5nngxvdum5v20jnww2lckg3n2ta", + }, + { + key: "amount", + value: "750000uinit", + }, + ], + type: "transfer", + }, + { + attributes: [ + { + key: "sender", + value: "init1h8lpl5qcs5k5nngxvdum5v20jnww2lckg3n2ta", + }, + ], + type: "message", + }, + { + attributes: [ + { + key: "fee", + value: "750000uinit", + }, + { + key: "fee_payer", + value: "init1h8lpl5qcs5k5nngxvdum5v20jnww2lckg3n2ta", + }, + ], + type: "tx", + }, + { + attributes: [ + { + key: "acc_seq", + value: "init1h8lpl5qcs5k5nngxvdum5v20jnww2lckg3n2ta/73", + }, + ], + type: "tx", + }, + { + attributes: [ + { + key: "signature", + value: + "2CXCevdXDrBhyMqVuh3QRwvnWrgecv6bJ2FBOv9o/JhrAF1i7HnXkoTF21fDWMgUbtHFeZvYSpU+ebTiT9+2ew==", + }, + ], + type: "tx", + }, + ], + gas_used: "84285", + gas_wanted: "5000000", + height: "191957", + info: "", + logs: [], + raw_log: + "failed to execute message; message index: 0: VM failure: status OUT_OF_GAS of type Execution, location=0000000000000000000000002ab506311ffe3aaf8871f84a7ba8a685e025dbba::ed25519, function=1, code_offset=12", + timestamp: parseDate("2024-01-26T07:05:00Z"), + tx: { + "@type": "/cosmos.tx.v1beta1.Tx", + auth_info: { + fee: { + amount: [ + { + amount: "750000", + denom: "uinit", + }, + ], + gas_limit: "5000000", + granter: "", + payer: "", + }, + signer_infos: [ + { + mode_info: { + single: { + mode: "SIGN_MODE_DIRECT", + }, + }, + public_key: { + "@type": "/cosmos.crypto.secp256k1.PubKey", + key: "A5vqpm4KH4Qz7T2DC31p3nZ8nK5M6ZrnDa4PcE6zg/Y0", + }, + sequence: "73", + }, + ], + }, + body: { + extension_options: [], + memo: "", + messages: [ + { + "@type": "/initia.move.v1.MsgExecute" as TypeUrl, + args: [], + function_name: "hash_x", + module_address: "0x2ab506311ffe3aaf8871f84a7ba8a685e025dbba", + module_name: "ed25519", + sender: "init1h8lpl5qcs5k5nngxvdum5v20jnww2lckg3n2ta", + type_args: [], + }, + ], + non_critical_extension_options: [], + timeout_height: "0", + }, + signatures: [ + "2CXCevdXDrBhyMqVuh3QRwvnWrgecv6bJ2FBOv9o/JhrAF1i7HnXkoTF21fDWMgUbtHFeZvYSpU+ebTiT9+2ew==", + ], + }, + txhash: "F252AA07AA9FA79A3488FD6E552E6B7A168E997CB923E0C43C770835F42F217C", + }, + result: [], +}; diff --git a/src/lib/utils/tx/__test__/extractTxLogs.test.ts b/src/lib/utils/tx/__test__/extractTxLogs.test.ts index 1511a2ea4..20da772ec 100644 --- a/src/lib/utils/tx/__test__/extractTxLogs.test.ts +++ b/src/lib/utils/tx/__test__/extractTxLogs.test.ts @@ -4,6 +4,7 @@ import { fromLogs, fromLogsTxFailed, fromEvents, + fromEventsTxFailed, } from "./extractTxLogs.example"; describe("extractTxLogs", () => { @@ -18,4 +19,9 @@ describe("extractTxLogs", () => { test("from events", () => { expect(extractTxLogs(fromEvents.txData)).toEqual(fromEvents.result); }); + test("from events Tx Failed", () => { + expect(extractTxLogs(fromEventsTxFailed.txData)).toEqual( + fromEventsTxFailed.result + ); + }); }); diff --git a/src/lib/utils/tx/extractTxLogs.ts b/src/lib/utils/tx/extractTxLogs.ts index ec168584e..d47f7611d 100644 --- a/src/lib/utils/tx/extractTxLogs.ts +++ b/src/lib/utils/tx/extractTxLogs.ts @@ -2,31 +2,24 @@ import type { Event, logs } from "@cosmjs/stargate"; import type { TxResponse } from "lib/services/tx"; -interface Log extends logs.Log { - events: Event[]; -} - export const extractTxLogs = (txData: TxResponse): logs.Log[] => { + // Failed Tx - no logs + if (txData.code !== 0) return []; + + // pre Cosmos SDK 0.50 if (txData.logs.length > 0) return txData.logs; - const logs: Record = {}; + // post Cosmos SDK 0.50 + const msgLogs = txData.tx.body.messages.map((_, index) => ({ + msg_index: index, + log: "", + events: [] as Event[], + })); txData.events.forEach((event) => { const index = event.attributes.find( (attr) => attr.key === "msg_index" )?.value; - if (index) { - if (!logs[index]) - logs[index] = { - msg_index: Number(index), - log: "", - events: [], - }; - - logs[index].events.push(event); - } + if (index) msgLogs[Number(index)].events.push(event); }); - - const msgLogs = Object.values(logs); - msgLogs.sort((a, b) => a.msg_index - b.msg_index); return msgLogs; }; From 799f86c2a1ea402c67cf3a75a7e7b578739bcad7 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 14:55:52 +0700 Subject: [PATCH 020/531] fix: type separator --- .../components/table/proposals/ProposalTextCell.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lib/components/table/proposals/ProposalTextCell.tsx b/src/lib/components/table/proposals/ProposalTextCell.tsx index 01ed24a35..afd2bb2f0 100644 --- a/src/lib/components/table/proposals/ProposalTextCell.tsx +++ b/src/lib/components/table/proposals/ProposalTextCell.tsx @@ -70,7 +70,16 @@ export const ProposalTextCell = ({ maxW={showName ? undefined : "full"} className={showName ? undefined : "ellipsis"} > - {types.join(" / ")} + {types.map((msgType, index) => ( + <> + {index > 0 && ( + + {" / "} + + )} + {msgType} + + ))} From 902a6b282fd1fe075cf2837678f398c86acfaff4 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 15:04:49 +0700 Subject: [PATCH 021/531] fix: initia network name --- src/config/chain/initia.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/chain/initia.ts b/src/config/chain/initia.ts index 49935251d..c2d32fae3 100644 --- a/src/config/chain/initia.ts +++ b/src/config/chain/initia.ts @@ -10,7 +10,7 @@ export const INITIA_CHAIN_CONFIGS: ChainConfigs = { "mahalo-1": { chain: "initia", registryChainName: "initiadevnet1", - prettyName: "Initia Devnet 1", + prettyName: "Initia Closed Testnet 1", lcd: "https://lcd.mahalo-1.initia.xyz", rpc: "https://rpc.mahalo-1.initia.xyz:443", indexer: "https://mahalo-1-graphql.alleslabs.dev/v1/graphql", @@ -60,7 +60,7 @@ export const INITIA_CHAIN_CONFIGS: ChainConfigs = { "minimove-1": { chain: "initia", registryChainName: "minitiamovedevnet1", - prettyName: "Minitia Move Devnet 1", + prettyName: "Minitia Move Closed Testnet 1", lcd: "https://lcd.minimove-1.initia.xyz", rpc: "https://rpc.minimove-1.initia.xyz:443", indexer: "https://minimove-1-graphql.alleslabs.dev/v1/graphql", @@ -110,7 +110,7 @@ export const INITIA_CHAIN_CONFIGS: ChainConfigs = { "miniwasm-1": { chain: "initia", registryChainName: "minitiawasmdevnet1", - prettyName: "Minitia Wasm Devnet 1", + prettyName: "Minitia Wasm Closed Testnet 1", lcd: "https://lcd.miniwasm-1.initia.xyz", rpc: "https://rpc.miniwasm-1.initia.xyz:443", indexer: "https://miniwasm-1-graphql.alleslabs.dev/v1/graphql", From cc80589baf2e818704409f5dc189fec3c78f700d Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 15:07:25 +0700 Subject: [PATCH 022/531] fix: logs --- src/lib/pages/tx-details/components/MessageSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/pages/tx-details/components/MessageSection.tsx b/src/lib/pages/tx-details/components/MessageSection.tsx index f877bd060..7eb32d326 100644 --- a/src/lib/pages/tx-details/components/MessageSection.tsx +++ b/src/lib/pages/tx-details/components/MessageSection.tsx @@ -49,7 +49,7 @@ export const MessageSection = ({ txData }: MessageSectionProps) => { log.msg_index === idx)} + log={logs[idx]} isSingleMsg={messages.length === 1} /> ))} From 5cb43e7941bb646eb011cdfa45c1fba228c2d8c9 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 15:23:54 +0700 Subject: [PATCH 023/531] fix: add key --- src/lib/components/table/proposals/ProposalTextCell.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/components/table/proposals/ProposalTextCell.tsx b/src/lib/components/table/proposals/ProposalTextCell.tsx index afd2bb2f0..e6dcf1b25 100644 --- a/src/lib/components/table/proposals/ProposalTextCell.tsx +++ b/src/lib/components/table/proposals/ProposalTextCell.tsx @@ -71,14 +71,14 @@ export const ProposalTextCell = ({ className={showName ? undefined : "ellipsis"} > {types.map((msgType, index) => ( - <> + {index > 0 && ( {" / "} )} {msgType} - + ))} From da3900de596103e6a80af34ac092cedce19ec767 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Fri, 26 Jan 2024 15:29:43 +0700 Subject: [PATCH 024/531] feat: support base64 as contract state key --- src/lib/utils/contractState.test.ts | 18 +++++++++++++++--- src/lib/utils/contractState.ts | 14 +++++++++++--- src/lib/utils/validate.ts | 7 +++++-- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/lib/utils/contractState.test.ts b/src/lib/utils/contractState.test.ts index 63b194b19..253796476 100644 --- a/src/lib/utils/contractState.test.ts +++ b/src/lib/utils/contractState.test.ts @@ -80,8 +80,20 @@ describe("parseStateKey", () => { }); }); - it("should return a singleton key if parsing fails", () => { - const key = "not hex"; - expect(parseStateKey(key)).toEqual({ type: "singleton", value: key }); + it("should parse base64 key", () => { + const key = "SGVsbG8="; // "Hello" + expect(parseStateKey(key)).toEqual({ type: "singleton", value: "Hello" }); + }); + + it("should parse base64 key with multiple values", () => { + const key = + "AAdhdWN0aW9uc2VpMTJuZTdxdG1kd2QwajAzdDl0NWVzOG1kNjZ3cTRlNXhnOW5lbGFkcnNhZzhmeDN5ODlyY3M1bTJ4YWpDOTgxWjhvUVZUZXBPSzRQclN1c2VpMXhzZjA4bGtoNzBjeW10aGY0Z2h4YWVmODR3NHVsZTd5bnFucXJr=="; + expect(parseStateKey(key)).toEqual({ + type: "bucket", + values: [ + "auction", + "sei12ne7qtmdwd0j03t9t5es8md66wq4e5xg9neladrsag8fx3y89rcs5m2xajC981Z8oQVTepOK4PrSusei1xsf08lkh70cymthf4ghxaef84w4ule7ynqnqrk", + ], + }); }); }); diff --git a/src/lib/utils/contractState.ts b/src/lib/utils/contractState.ts index 0f513685f..70f77b2ba 100644 --- a/src/lib/utils/contractState.ts +++ b/src/lib/utils/contractState.ts @@ -1,13 +1,18 @@ import type { ContractState, DecodedKey } from "lib/types"; +import { isHex } from "./validate"; + const nameRegex = /^[a-zA-Z0-9_{}:"'/\\,\\[\]()]+$/; export const hexToString = (hex: string) => Buffer.from(hex, "hex").toString("utf-8"); -export const parseStateKey = (key: string): DecodedKey => { +// eslint-disable-next-line sonarjs/cognitive-complexity +export const parseStateKey = (rawKey: string): DecodedKey => { try { - const decodedStr = hexToString(key); + const decodedStr = isHex(rawKey) + ? hexToString(rawKey) + : Buffer.from(rawKey, "base64").toString(); if (decodedStr === "") throw new Error("Invalid hex string for decoding"); if (nameRegex.test(decodedStr)) { return { @@ -16,6 +21,9 @@ export const parseStateKey = (key: string): DecodedKey => { }; } + const key = isHex(rawKey) + ? rawKey + : Buffer.from(rawKey, "base64").toString("hex"); const values: string[] = []; let currentIndex = 0; while (currentIndex < key.length) { @@ -60,7 +68,7 @@ export const parseStateKey = (key: string): DecodedKey => { return { type: "singleton", - value: key, + value: rawKey, }; }; diff --git a/src/lib/utils/validate.ts b/src/lib/utils/validate.ts index 8d6da4adf..a4fe851ce 100644 --- a/src/lib/utils/validate.ts +++ b/src/lib/utils/validate.ts @@ -14,15 +14,18 @@ export const isPosDecimal = (input: string): boolean => { export const isId = (input: string): boolean => input.length <= 7 && isPosDecimal(input); -export const isTxHash = (input: string): boolean => { +export const isHex = (input: string): boolean => { try { fromHex(input); } catch { return false; } - return input.length === 64; + return true; }; +export const isTxHash = (input: string): boolean => + isHex(input) && input.length === 64; + const isHexAddress = (address: string, length: number): boolean => { const regex = new RegExp(`^0x[a-fA-F0-9]{1,${length}}$`); if (!regex.test(address)) { From f8ec91eb6af7da1bc85d889c371debb563946f17 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Fri, 26 Jan 2024 15:37:18 +0700 Subject: [PATCH 025/531] docs: add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 932c35eb9..9baab85bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements - [#750](https://github.com/alleslabs/celatone-frontend/pull/750) api v1 - recent codes list +- [#752](https://github.com/alleslabs/celatone-frontend/pull/752) Support contract state's key as base64 ### Bug fixes From 35cad581f87efc7a25489321b58fc3ca18c973a5 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Fri, 26 Jan 2024 15:45:55 +0700 Subject: [PATCH 026/531] fix: as more test --- src/lib/utils/validate.test.ts | 16 +++++++++++++++- src/lib/utils/validate.ts | 8 ++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/lib/utils/validate.test.ts b/src/lib/utils/validate.test.ts index b97b14b80..6e48de826 100644 --- a/src/lib/utils/validate.test.ts +++ b/src/lib/utils/validate.test.ts @@ -1,5 +1,5 @@ /* eslint-disable sonarjs/no-duplicate-string */ -import { isId, isTxHash, isPosDecimal } from "./validate"; +import { isId, isTxHash, isPosDecimal, isHex } from "./validate"; describe("isId", () => { test("valid", () => { @@ -24,6 +24,20 @@ describe("isId", () => { }); }); +describe("isHex", () => { + test("valid", () => { + expect(isHex("1234ABCD")).toBeTruthy(); + }); + describe("invalid", () => { + test("empty string", () => { + expect(isHex("")).toBeFalsy(); + }); + test("non-hexstring", () => { + expect(isHex("XYZ")).toBeFalsy(); + }); + }); +}); + describe("isTxHash", () => { test("valid", () => { expect( diff --git a/src/lib/utils/validate.ts b/src/lib/utils/validate.ts index a4fe851ce..537186f88 100644 --- a/src/lib/utils/validate.ts +++ b/src/lib/utils/validate.ts @@ -15,6 +15,7 @@ export const isId = (input: string): boolean => input.length <= 7 && isPosDecimal(input); export const isHex = (input: string): boolean => { + if (input.trim() === "") return false; try { fromHex(input); } catch { @@ -33,12 +34,7 @@ const isHexAddress = (address: string, length: number): boolean => { } const strip = padHexAddress(address as HexAddr, length).slice(2); - try { - fromHex(strip); - } catch { - return false; - } - return true; + return isHex(strip); }; export const isHexWalletAddress = (address: string) => From 3c6eeca42b6fdb8fb02ca20268c7db81472adf1f Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 26 Jan 2024 16:49:39 +0700 Subject: [PATCH 027/531] feat: api v1 - proposal type filter --- CHANGELOG.md | 1 + src/lib/query/proposal.ts | 8 -------- src/lib/services/proposal.ts | 5 +++++ src/lib/services/proposalService.ts | 28 ++++++++++------------------ 4 files changed, 16 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 932c35eb9..0e50fccce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features - [#749](https://github.com/alleslabs/celatone-frontend/pull/749) Add multi-type proposals +- [#753](https://github.com/alleslabs/celatone-frontend/pull/753) api v1 - proposal type filter ### Improvements diff --git a/src/lib/query/proposal.ts b/src/lib/query/proposal.ts index 55e36eb6f..a2cf50601 100644 --- a/src/lib/query/proposal.ts +++ b/src/lib/query/proposal.ts @@ -38,11 +38,3 @@ export const getRelatedProposalsCountByModuleId = graphql(` } } `); - -export const getProposalTypes = graphql(` - query getProposalTypes { - proposals(distinct_on: type) { - type - } - } -`); diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 38f9df548..382bcee8e 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -67,6 +67,11 @@ export const fetchGovUploadAccessParams = async ( ): Promise => axios.get(`${lcdEndpoint}/upload_access`).then(({ data }) => data); +export const getProposalTypes = async (endpoint: string) => + axios + .get(`${endpoint}/types`) + .then(({ data }) => zProposalType.array().parse(data)); + const zProposalsResponseItem = z .object({ deposit_end_time: zUtcDate, diff --git a/src/lib/services/proposalService.ts b/src/lib/services/proposalService.ts index 7b01b2007..0ce729a43 100644 --- a/src/lib/services/proposalService.ts +++ b/src/lib/services/proposalService.ts @@ -10,7 +10,6 @@ import { useCelatoneApp, } from "lib/app-provider"; import { - getProposalTypes, getRelatedProposalsByModuleIdPagination, getRelatedProposalsCountByModuleId, } from "lib/query"; @@ -51,6 +50,7 @@ import { getProposalsByAddress, getRelatedProposalsByContractAddress, getProposals, + getProposalTypes, } from "./proposal"; export const useProposals = ( @@ -89,6 +89,15 @@ export const useProposals = ( ); }; +export const useProposalTypes = (): UseQueryResult => { + const endpoint = useBaseApiRoute("proposals"); + return useQuery( + [CELATONE_QUERY_KEYS.PROPOSAL_TYPES, endpoint], + async () => getProposalTypes(endpoint), + { retry: 1, refetchOnWindowFocus: false } + ); +}; + export const useProposalsByAddress = ( address: BechAddr, offset: number, @@ -213,23 +222,6 @@ export const useRelatedProposalsCountByModuleId = ( ); }; -export const useProposalTypes = (): UseQueryResult => { - const { indexerGraphClient } = useCelatoneApp(); - const queryFn = useCallback( - async () => - indexerGraphClient - .request(getProposalTypes) - .then(({ proposals }) => - proposals.map((proposal) => proposal.type).sort() - ), - [indexerGraphClient] - ); - return useQuery( - [CELATONE_QUERY_KEYS.PROPOSAL_TYPES, indexerGraphClient], - queryFn - ); -}; - export interface MinDeposit { amount: U>; denom: string; From bcd4fef1c71dde4f3bc6e62917602d549cf46ff0 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Fri, 26 Jan 2024 16:54:50 +0700 Subject: [PATCH 028/531] fix: name less than 4 --- src/lib/utils/contractState.test.ts | 8 ++++++++ src/lib/utils/contractState.ts | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lib/utils/contractState.test.ts b/src/lib/utils/contractState.test.ts index 253796476..51208928c 100644 --- a/src/lib/utils/contractState.test.ts +++ b/src/lib/utils/contractState.test.ts @@ -96,4 +96,12 @@ describe("parseStateKey", () => { ], }); }); + + it("should parse base64 key name length less than 4", () => { + const key = "AAZ0b2tlbnMx"; // 0006746f6b656e7331 + expect(parseStateKey(key)).toEqual({ + type: "bucket", + values: ["tokens", "1"], + }); + }); }); diff --git a/src/lib/utils/contractState.ts b/src/lib/utils/contractState.ts index 70f77b2ba..51401a8d3 100644 --- a/src/lib/utils/contractState.ts +++ b/src/lib/utils/contractState.ts @@ -32,7 +32,8 @@ export const parseStateKey = (rawKey: string): DecodedKey => { // We've assumed that the length of the key is less than 256 // This should be the last part of key - if (!(length > 0 && length <= 256)) { + const remainingLength = key.length - currentIndex; + if (!(length > 0 && length <= 256) || remainingLength <= 4) { const valueHex = key.slice(currentIndex); const decodedValue = hexToString(valueHex); values.push(nameRegex.test(decodedValue) ? decodedValue : valueHex); From 5aa552407d64ccb3b74794132776e6c54825173b Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Fri, 26 Jan 2024 17:00:27 +0700 Subject: [PATCH 029/531] fix(components): fix mobile guard --- src/lib/components/MobileGuard.tsx | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/lib/components/MobileGuard.tsx b/src/lib/components/MobileGuard.tsx index 727ed4235..6406cdcda 100644 --- a/src/lib/components/MobileGuard.tsx +++ b/src/lib/components/MobileGuard.tsx @@ -1,7 +1,7 @@ import { useRouter } from "next/router"; import type { ReactNode } from "react"; -import { useCelatoneApp, useMobile } from "lib/app-provider"; +import { useMobile } from "lib/app-provider"; import { NoMobile } from "./modal"; @@ -12,26 +12,20 @@ export const MobileGuard = ({ children }: MobileGuardProps) => { const router = useRouter(); const pathName = router.asPath; const isMobile = useMobile(); - const { currentChainId } = useCelatoneApp(); const isResponsive = - pathName.includes(`/account`) || + pathName.includes(`/accounts`) || pathName.includes(`/txs`) || pathName.includes(`/blocks`) || pathName.includes(`/projects`) || - pathName.includes(`/code`) || - pathName.includes(`/nft-collections`) || pathName.includes(`/query`) || - pathName.includes(`/network-overview`) || - pathName.includes(`/dev-home`) || pathName.includes(`/404`) || pathName.includes(`/proposals`) || + pathName.includes(`/nft-collections`) || // wasm pathName.includes(`/contracts/`) || - pathName === `/${currentChainId}/contracts` || + pathName.includes(`/codes`) || // move - pathName.includes(`/modules/`) || - pathName === `/${currentChainId}/modules` || - pathName === `/${currentChainId}`; + pathName.includes(`/modules`); if (isResponsive && isMobile) return <>{children}; if (!isResponsive && isMobile) return ; From a3198f8c1fe52406d0f9b426f2e8dccf3b3a23df Mon Sep 17 00:00:00 2001 From: evilpeach Date: Fri, 26 Jan 2024 19:09:58 +0700 Subject: [PATCH 030/531] fix: contract route --- src/lib/components/MobileGuard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/MobileGuard.tsx b/src/lib/components/MobileGuard.tsx index 6406cdcda..54a88cd40 100644 --- a/src/lib/components/MobileGuard.tsx +++ b/src/lib/components/MobileGuard.tsx @@ -22,7 +22,7 @@ export const MobileGuard = ({ children }: MobileGuardProps) => { pathName.includes(`/proposals`) || pathName.includes(`/nft-collections`) || // wasm - pathName.includes(`/contracts/`) || + pathName.includes(`/contracts`) || pathName.includes(`/codes`) || // move pathName.includes(`/modules`); From 499c90814934af5a486553891f80c62ae8f8b88b Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Mon, 29 Jan 2024 10:19:15 +0700 Subject: [PATCH 031/531] fix: mobile guard --- CHANGELOG.md | 1 + src/lib/components/MobileGuard.tsx | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9115274ee..6df084f50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Bug fixes +- [#754](https://github.com/alleslabs/celatone-frontend/pull/754) Fix mobile guard incorrect behavior - [#751](https://github.com/alleslabs/celatone-frontend/pull/751) Fix fail txs should have no logs and remove stone-12-1 ## v1.5.1 diff --git a/src/lib/components/MobileGuard.tsx b/src/lib/components/MobileGuard.tsx index 54a88cd40..bde287021 100644 --- a/src/lib/components/MobileGuard.tsx +++ b/src/lib/components/MobileGuard.tsx @@ -1,7 +1,7 @@ import { useRouter } from "next/router"; import type { ReactNode } from "react"; -import { useMobile } from "lib/app-provider"; +import { useCelatoneApp, useMobile } from "lib/app-provider"; import { NoMobile } from "./modal"; @@ -10,9 +10,12 @@ interface MobileGuardProps { } export const MobileGuard = ({ children }: MobileGuardProps) => { const router = useRouter(); - const pathName = router.asPath; const isMobile = useMobile(); + const { currentChainId } = useCelatoneApp(); + + const pathName = router.asPath; const isResponsive = + pathName === `/${currentChainId}` || pathName.includes(`/accounts`) || pathName.includes(`/txs`) || pathName.includes(`/blocks`) || @@ -27,7 +30,6 @@ export const MobileGuard = ({ children }: MobileGuardProps) => { // move pathName.includes(`/modules`); - if (isResponsive && isMobile) return <>{children}; if (!isResponsive && isMobile) return ; return <>{children}; }; From 7a95056f9e1da20a5bde5ed3aa85172dad604141 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Tue, 30 Jan 2024 11:10:08 +0700 Subject: [PATCH 032/531] feat: redirect from usei to homepage --- CHANGELOG.md | 1 + next.config.js | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1361881b..e0da3c5b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#756](https://github.com/alleslabs/celatone-frontend/pull/756) Redirect usei to homepage - [#750](https://github.com/alleslabs/celatone-frontend/pull/750) api v1 - recent codes list - [#752](https://github.com/alleslabs/celatone-frontend/pull/752) Support contract state's key as base64 diff --git a/next.config.js b/next.config.js index 6ed6f527c..9ad5a246d 100644 --- a/next.config.js +++ b/next.config.js @@ -49,7 +49,7 @@ const nextConfig = { "tx", ]; - return routes.reduce((acc, route) => { + const rules = routes.reduce((acc, route) => { acc.push({ source: `/:network/${route}/:id`, destination: `/:network/${route}s/:id`, @@ -76,6 +76,14 @@ const nextConfig = { return acc; }, []); + + rules.push({ + source: "/:network/accounts/usei", + destination: "/:network", + permanent: false, + }); + + return rules; }, }; From cc85df16653fc203b58846b27eb914a9544dbd7d Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Tue, 30 Jan 2024 11:31:10 +0700 Subject: [PATCH 033/531] feat(components): get proposal data from api --- CHANGELOG.md | 1 + src/lib/app-provider/env.ts | 1 + .../table/proposals/ProposalsTable.tsx | 7 +- .../proposals/ProposalsTableMobileCard.tsx | 4 +- .../table/proposals/ProposalsTableRow.tsx | 4 +- src/lib/services/proposal.ts | 83 +++++++++++++------ src/lib/services/proposalService.ts | 14 +++- src/lib/types/asset.ts | 5 ++ src/lib/types/proposal.ts | 27 +++++- 9 files changed, 110 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1361881b..48ccfa59e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#757](https://github.com/alleslabs/celatone-frontend/pull/757) api v1 - proposal data - [#731](https://github.com/alleslabs/celatone-frontend/pull/731) Add proposal detail page structure - [#749](https://github.com/alleslabs/celatone-frontend/pull/749) Add multi-type proposals - [#753](https://github.com/alleslabs/celatone-frontend/pull/753) api v1 - proposal type filter diff --git a/src/lib/app-provider/env.ts b/src/lib/app-provider/env.ts index faf280141..d74ca2b0c 100644 --- a/src/lib/app-provider/env.ts +++ b/src/lib/app-provider/env.ts @@ -51,6 +51,7 @@ export enum CELATONE_QUERY_KEYS { // FAUCET FAUCET_INFO = "CELATONE_QUERY_FAUCET_INFO", // X/GOV + PROPOSAL_DATA = "CELATONE_QUERY_PROPOSAL_DATA", RELATED_PROPOSALS_BY_CONTRACT_ADDRESS = "CELATONE_QUERY_RELATED_PROPOSALS_BY_CONTRACT_ADDRESS", PROPOSALS_BY_MODULE_ID = "CELATONE_QUERY_PROPOSALS_BY_MODULE_ID", PROPOSALS_COUNT_BY_MODULE_ID = "CELATONE_QUERY_PROPOSALS_COUNT_BY_MODULE_ID", diff --git a/src/lib/components/table/proposals/ProposalsTable.tsx b/src/lib/components/table/proposals/ProposalsTable.tsx index 65ad75314..1a9531c3c 100644 --- a/src/lib/components/table/proposals/ProposalsTable.tsx +++ b/src/lib/components/table/proposals/ProposalsTable.tsx @@ -30,10 +30,7 @@ export const ProposalsTable = ({ return isMobile ? ( {proposals.map((proposal) => ( - + ))} ) : ( @@ -44,7 +41,7 @@ export const ProposalsTable = ({ /> {proposals.map((proposal) => ( @@ -101,7 +101,7 @@ export const ProposalsTableMobileCard = ({ getNavigationUrl({ type: "proposal_id", explorerConfig: explorerLink, - value: proposal.proposalId.toString(), + value: proposal.id.toString(), lcdEndpoint, }) ); diff --git a/src/lib/components/table/proposals/ProposalsTableRow.tsx b/src/lib/components/table/proposals/ProposalsTableRow.tsx index 925ac4811..a0f30c1d1 100644 --- a/src/lib/components/table/proposals/ProposalsTableRow.tsx +++ b/src/lib/components/table/proposals/ProposalsTableRow.tsx @@ -62,7 +62,7 @@ export const ProposalsTableRow = ({ getNavigationUrl({ type: "proposal_id", explorerConfig: explorerLink, - value: proposal.proposalId.toString(), + value: proposal.id.toString(), lcdEndpoint, }) ); @@ -74,7 +74,7 @@ export const ProposalsTableRow = ({ diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 382bcee8e..975d1d0bf 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -2,7 +2,13 @@ import type { Coin } from "@cosmjs/stargate"; import axios from "axios"; import { z } from "zod"; -import { zUtcDate, zProposalType, zBechAddr, zProposalStatus } from "lib/types"; +import { + zBechAddr, + zCoin, + zProposalStatus, + zProposalType, + zUtcDate, +} from "lib/types"; import type { AccessConfigPermission, BechAddr, @@ -11,6 +17,7 @@ import type { Proposal, Option, BechAddr20, + ProposalData, ProposalStatus, ProposalType, } from "lib/types"; @@ -72,29 +79,18 @@ export const getProposalTypes = async (endpoint: string) => .get(`${endpoint}/types`) .then(({ data }) => zProposalType.array().parse(data)); -const zProposalsResponseItem = z - .object({ - deposit_end_time: zUtcDate, - id: z.number().nonnegative(), - is_expedited: z.boolean(), - proposer: zBechAddr, - resolved_height: z.number().nullable(), - status: zProposalStatus, - title: z.string(), - types: zProposalType.array(), - voting_end_time: zUtcDate.nullable(), - }) - .transform((val) => ({ - depositEndTime: val.deposit_end_time, - proposalId: val.id, - isExpedited: val.is_expedited, - proposer: val.proposer, - resolvedHeight: val.resolved_height, - status: val.status, - title: val.title, - types: val.types, - votingEndTime: val.voting_end_time, - })); +const zProposal = z.object({ + deposit_end_time: zUtcDate, + id: z.number().nonnegative(), + is_expedited: z.boolean(), + proposer: zBechAddr, + resolved_height: z.number().nullable(), + status: zProposalStatus, + title: z.string(), + types: zProposalType.array(), + voting_end_time: zUtcDate.nullable(), +}); +const zProposalsResponseItem = zProposal.transform(snakeToCamel); const zProposalsResponse = z.object({ items: z.array(zProposalsResponseItem), @@ -164,3 +160,42 @@ export const getRelatedProposalsByContractAddress = async ( } ) .then(({ data }) => zRelatedProposalsResponse.parse(data)); + +const zProposalDataResponse = z.object({ + info: zProposal + .extend({ + created_height: z.number().nullable(), + created_timestamp: zUtcDate.nullable(), + created_tx_hash: z.string(), + description: z.string(), + messages: z.unknown().array(), + metadata: z.string(), + proposal_deposits: z + .object({ + amount: zCoin.array(), + depositor: zBechAddr, + timestamp: zUtcDate, + tx_hash: z.string(), + }) + .array(), + resolved_timestamp: zUtcDate.nullable(), + submit_time: zUtcDate, + total_deposit: zCoin.array(), + version: z.string(), + voting_time: zUtcDate.nullable(), + }) + .transform(({ messages, ...val }) => ({ + ...snakeToCamel(val), + messages, + })) + .nullable(), +}); +export type ProposalDataResponse = z.infer; + +export const getProposalData = async ( + endpoint: string, + id: number +): Promise => + axios + .get(`${endpoint}/${encodeURIComponent(id)}/info`) + .then(({ data }) => zProposalDataResponse.parse(data)); diff --git a/src/lib/services/proposalService.ts b/src/lib/services/proposalService.ts index 0ce729a43..db01582ea 100644 --- a/src/lib/services/proposalService.ts +++ b/src/lib/services/proposalService.ts @@ -38,6 +38,7 @@ import { useAssetInfos } from "./assetService"; import { useMovePoolInfos } from "./move"; import type { DepositParamsInternal, + ProposalDataResponse, ProposalsResponse, RelatedProposalsResponse, UploadAccess, @@ -51,6 +52,7 @@ import { getRelatedProposalsByContractAddress, getProposals, getProposalTypes, + getProposalData, } from "./proposal"; export const useProposals = ( @@ -163,7 +165,7 @@ export const useRelatedProposalsByModuleIdPagination = ( }) .then(({ module_proposals }) => module_proposals.map((proposal) => ({ - proposalId: proposal.proposal_id, + id: proposal.proposal_id, title: proposal.proposal.title, status: proposal.proposal.status as ProposalStatus, votingEndTime: parseDate(proposal.proposal.voting_end_time), @@ -222,6 +224,16 @@ export const useRelatedProposalsCountByModuleId = ( ); }; +export const useProposalData = (id: number) => { + const endpoint = useBaseApiRoute("proposals"); + + return useQuery( + [CELATONE_QUERY_KEYS.PROPOSAL_DATA, endpoint, id], + async () => getProposalData(endpoint, id), + { retry: 1, keepPreviousData: true } + ); +}; + export interface MinDeposit { amount: U>; denom: string; diff --git a/src/lib/types/asset.ts b/src/lib/types/asset.ts index 73a920854..4fafdb768 100644 --- a/src/lib/types/asset.ts +++ b/src/lib/types/asset.ts @@ -3,6 +3,11 @@ import { z } from "zod"; import type { PoolInfo, Option, Token, U, USD } from "lib/types"; +export const zCoin = z.object({ + denom: z.string(), + amount: z.string(), +}); + export const zAssetInfo = z.object({ coingecko: z.string(), description: z.string(), diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index bdf7f66de..91463fd4b 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -1,6 +1,7 @@ +import type { Coin } from "@cosmjs/amino"; import { z } from "zod"; -import type { BechAddr, Nullable, Option } from "lib/types"; +import { type BechAddr, type Nullable, type Option } from "lib/types"; export enum ProposalStatus { DEPOSIT_PERIOD = "DepositPeriod", @@ -57,7 +58,7 @@ export const zProposalType = z.union([ export type ProposalType = z.infer; export interface Proposal { - proposalId: number; + id: number; title: string; status: ProposalStatus; votingEndTime: Nullable; @@ -67,3 +68,25 @@ export interface Proposal { proposer: Option; isExpedited: boolean; } + +export interface ProposalDeposit { + amount: Coin[]; + depositor: BechAddr; + timestamp: Date; + txHash: string; +} + +export interface ProposalData extends Proposal { + createdHeight: Nullable; + createdTimestamp: Nullable; + createdTxHash: string; + description: string; + messages: unknown[]; + metadata: string; + proposalDeposits: ProposalDeposit[]; + resolvedTimestamp: Nullable; + submitTime: Date; + totalDeposit: Coin[]; + version: string; + votingTime: Nullable; +} From 2ab911fbfb266cdfd7ae80543f916aff81fb3ee4 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Tue, 30 Jan 2024 11:40:26 +0700 Subject: [PATCH 034/531] fix(components): fix import type --- src/lib/types/proposal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 91463fd4b..513f02847 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -1,7 +1,7 @@ import type { Coin } from "@cosmjs/amino"; import { z } from "zod"; -import { type BechAddr, type Nullable, type Option } from "lib/types"; +import type { BechAddr, Nullable, Option } from "lib/types"; export enum ProposalStatus { DEPOSIT_PERIOD = "DepositPeriod", From 4ee49ca0972be8d3d947b99b3e2fb07b66b5afdf Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Tue, 30 Jan 2024 13:10:59 +0700 Subject: [PATCH 035/531] fix(components): fix created tx hash type --- src/lib/services/proposal.ts | 2 +- src/lib/types/proposal.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 975d1d0bf..41323b034 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -166,7 +166,7 @@ const zProposalDataResponse = z.object({ .extend({ created_height: z.number().nullable(), created_timestamp: zUtcDate.nullable(), - created_tx_hash: z.string(), + created_tx_hash: z.string().nullable(), description: z.string(), messages: z.unknown().array(), metadata: z.string(), diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 513f02847..1b492208f 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -79,7 +79,7 @@ export interface ProposalDeposit { export interface ProposalData extends Proposal { createdHeight: Nullable; createdTimestamp: Nullable; - createdTxHash: string; + createdTxHash: Nullable; description: string; messages: unknown[]; metadata: string; From aaba5bfbc41f1702916c4c356033a0edaee9a12c Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Tue, 30 Jan 2024 13:14:48 +0700 Subject: [PATCH 036/531] fix(components): add nullable for proposal messages --- src/lib/services/proposal.ts | 2 +- src/lib/types/proposal.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 41323b034..74f65099a 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -168,7 +168,7 @@ const zProposalDataResponse = z.object({ created_timestamp: zUtcDate.nullable(), created_tx_hash: z.string().nullable(), description: z.string(), - messages: z.unknown().array(), + messages: z.unknown().array().nullable(), metadata: z.string(), proposal_deposits: z .object({ diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 1b492208f..8efbb6b56 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -81,7 +81,7 @@ export interface ProposalData extends Proposal { createdTimestamp: Nullable; createdTxHash: Nullable; description: string; - messages: unknown[]; + messages: Nullable; metadata: string; proposalDeposits: ProposalDeposit[]; resolvedTimestamp: Nullable; From 9d6abc91ad6b59406d75bf8bd3f8643b13787178 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Tue, 30 Jan 2024 15:12:24 +0700 Subject: [PATCH 037/531] fix(components): wireup proposal data --- .../components/ProposalInfo.tsx | 49 ++-- .../components/ProposalTop.tsx | 219 ++++++++---------- .../__stories__/ProposalInfo.stories.ts | 88 ------- src/lib/pages/proposal-details/index.tsx | 10 +- src/lib/services/proposal.ts | 19 +- src/lib/types/proposal.ts | 2 +- 6 files changed, 146 insertions(+), 241 deletions(-) delete mode 100644 src/lib/pages/proposal-details/components/__stories__/ProposalInfo.stories.ts diff --git a/src/lib/pages/proposal-details/components/ProposalInfo.tsx b/src/lib/pages/proposal-details/components/ProposalInfo.tsx index d25dee111..a162e9cd1 100644 --- a/src/lib/pages/proposal-details/components/ProposalInfo.tsx +++ b/src/lib/pages/proposal-details/components/ProposalInfo.tsx @@ -3,7 +3,7 @@ import type { ReactNode } from "react"; import { ExplorerLink } from "lib/components/ExplorerLink"; import { MobileLabel, StatusChip } from "lib/components/table"; -import type { BechAddr } from "lib/types"; +import type { ProposalData } from "lib/types"; import { ProposalStatus } from "lib/types"; import { formatUTC } from "lib/utils"; @@ -21,18 +21,6 @@ const InfoItem = ({ label, children }: InfoItemProps) => { ); }; -type ProposalData = { - status: ProposalStatus; - createdTxHash: string; - proposer: BechAddr; - depositStart?: Date; - depositEnd?: Date; - voteStart?: Date; - voteEnd?: Date; - resolvedHeight?: number; - resolvedDate?: Date; -}; - interface ProposalStatusProps { data: ProposalData; } @@ -43,8 +31,8 @@ const getProposalInfo = (data: ProposalStatusProps["data"]) => { return ( - {data.depositStart && data.depositEnd - ? `${formatUTC(data.depositStart)} - ${formatUTC(data.depositEnd)}` + {data.submitTime && data.depositEndTime + ? `${formatUTC(data.submitTime)} - ${formatUTC(data.depositEndTime)}` : "N/A"} @@ -69,7 +57,9 @@ const getProposalInfo = (data: ProposalStatusProps["data"]) => { - {data.resolvedDate ? formatUTC(data.resolvedDate) : "N/A"} + {data.resolvedTimestamp + ? formatUTC(data.resolvedTimestamp) + : "N/A"} @@ -78,8 +68,8 @@ const getProposalInfo = (data: ProposalStatusProps["data"]) => { return ( - {data.voteStart && data.voteEnd - ? `${formatUTC(data.voteStart)} - ${formatUTC(data.voteEnd)}` + {data.votingTime && data.votingEndTime + ? `${formatUTC(data.votingTime)} - ${formatUTC(data.votingEndTime)}` : "N/A"} @@ -106,7 +96,9 @@ const getProposalInfo = (data: ProposalStatusProps["data"]) => { - {data.resolvedDate ? formatUTC(data.resolvedDate) : "N/A"} + {data.resolvedTimestamp + ? formatUTC(data.resolvedTimestamp) + : "N/A"} @@ -136,12 +128,19 @@ export const ProposalInfo = ({ data }: ProposalStatusProps) => { - - - - - - + {data.createdTxHash && ( + + + + )} + {data.proposer && ( + + + + )} { - const isMobile = useMobile(); +interface ProposalTopProps { + id: number; + proposalData: ProposalData; +} +export const ProposalTop = ({ id, proposalData }: ProposalTopProps) => { + const isMobile = useMobile(); + const endpoint = useBaseApiRoute("proposals"); + const openApiPage = () => + openNewTab(`${endpoint}/${encodeURIComponent(id)}/info`); if (!id) return ; return ( @@ -27,8 +34,11 @@ export const ProposalTop = ({ id }: { id: number }) => { { text: `#${id.toString()}` }, ]} /> - - + + { variant={{ base: "h6", md: "h5" }} className={!isMobile ? "ellipsis" : ""} wordBreak="break-word" + color={proposalData.title ? "text.main" : "text.disabled"} > - #{id} - {" "} - - Regular Incentive adjustment for 2023-07-10 + {" "} + - {proposalData.title ? proposalData.title : "No title"} - {!isMobile && ( - - )} - - - - - Proposal Messages: - - - ProposalStoreCode / ProposalStoreCode / ProposalStoreCode / - ProposalStoreCode / ProposalStoreCode - - - {!isMobile && ( + - - Created Height: - - - - - {/* {formatUTC(blockData.timestamp)} */} timestamp + + Proposal Messages: + {proposalData.types.length ? ( + + {proposalData.types.map((msgType, index) => ( + + {index > 0 && ( + + {" / "} + + )} + {msgType} + + ))} + + ) : ( + + No Message + + )} - )} + {!isMobile && ( + + {proposalData.createdHeight && ( + <> + + Created Height: + + + + + )} + {proposalData.createdTimestamp && ( + + {formatUTC(proposalData.createdTimestamp)} + + )} + + )} + - {isMobile && ( - - )} + - - - - - - + ); }; diff --git a/src/lib/pages/proposal-details/components/__stories__/ProposalInfo.stories.ts b/src/lib/pages/proposal-details/components/__stories__/ProposalInfo.stories.ts deleted file mode 100644 index ba6e5a925..000000000 --- a/src/lib/pages/proposal-details/components/__stories__/ProposalInfo.stories.ts +++ /dev/null @@ -1,88 +0,0 @@ -import type { Meta, StoryObj } from "@storybook/react"; - -import { ProposalInfo } from "../ProposalInfo"; -import type { BechAddr } from "lib/types"; -import { ProposalStatus } from "lib/types"; - -const meta: Meta = { - component: ProposalInfo, - parameters: { - layout: "centered", - }, - tags: ["autodocs"], -}; - -export default meta; -type Story = StoryObj; - -export const DEPOSIT_PERIOD: Story = { - args: { - data: { - status: ProposalStatus.DEPOSIT_PERIOD, - createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", - proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, - depositStart: new Date(), - depositEnd: new Date(), - }, - }, -}; - -export const DEPOSIT_FAILED: Story = { - args: { - data: { - status: ProposalStatus.DEPOSIT_FAILED, - createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", - proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, - resolvedHeight: 123456, - resolvedDate: new Date(), - }, - }, -}; - -export const VOTING_PERIOD: Story = { - args: { - data: { - status: ProposalStatus.VOTING_PERIOD, - createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", - proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, - voteStart: new Date(), - voteEnd: new Date(), - }, - }, -}; - -export const PASSED: Story = { - args: { - data: { - status: ProposalStatus.PASSED, - createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", - proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, - resolvedHeight: 123456, - resolvedDate: new Date(), - }, - }, -}; - -export const REJECTED: Story = { - args: { - data: { - status: ProposalStatus.REJECTED, - createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", - proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, - resolvedHeight: 123456, - resolvedDate: new Date(), - }, - }, -}; - -export const FAILED: Story = { - args: { - data: { - status: ProposalStatus.FAILED, - createdTxHash: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p", - proposer: "osmo1acqpnvg2t4wmqfdv8hq47d3petfksjs5r9t45p" as BechAddr, - resolvedHeight: 123456, - resolvedDate: new Date(), - }, - }, -}; diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index 60a50b212..19aaf2e8b 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -6,6 +6,7 @@ import { useInternalNavigate } from "lib/app-provider"; import { CustomTab } from "lib/components/CustomTab"; import PageContainer from "lib/components/PageContainer"; import { InvalidState } from "lib/components/state"; +import { useProposalData } from "lib/services/proposalService"; import { ProposalTop } from "./components"; import { ProposalOverview } from "./components/ProposalOverview"; @@ -20,6 +21,7 @@ const ProposalDetailsBody = ({ }: ProposalDetailsQueryParams) => { const router = useRouter(); const navigate = useInternalNavigate(); + const { data } = useProposalData(id); const handleTabChange = useCallback( (nextTab: TabIndex) => () => { @@ -54,12 +56,14 @@ const ProposalDetailsBody = ({ } }, [router.isReady, tab, navigate, id]); - // TODO mock up data - if (id > 9999) return ; + if (!data || !data.info) + return ; + + const proposalData = data.info; return ( <> - + (({ messages, ...val }) => ({ - ...snakeToCamel(val), - messages, - })) + .transform( + ({ created_tx_hash, proposal_deposits, messages, ...val }) => ({ + ...snakeToCamel(val), + createdTxHash: created_tx_hash ? parseTxHash(created_tx_hash) : null, + proposalDeposits: proposal_deposits.map((deposit) => ({ + ...deposit, + txHash: parseTxHash(deposit.tx_hash), + })), + messages, + }) + ) .nullable(), }); export type ProposalDataResponse = z.infer; diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 8efbb6b56..54a0076bc 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -86,7 +86,7 @@ export interface ProposalData extends Proposal { proposalDeposits: ProposalDeposit[]; resolvedTimestamp: Nullable; submitTime: Date; - totalDeposit: Coin[]; + totalDeposit: Nullable; version: string; votingTime: Nullable; } From 7c8d1a60ad60e120ff4a1bb0560f003c53e86f4d Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Tue, 30 Jan 2024 15:56:35 +0700 Subject: [PATCH 038/531] fix(components): fix navigate link from proposal list --- src/lib/components/ExplorerLink.tsx | 11 +++-- .../proposals/ProposalsTableMobileCard.tsx | 45 +++++++---------- .../table/proposals/ProposalsTableRow.tsx | 48 +++++++------------ src/lib/pages/proposal-details/index.tsx | 11 +++-- 4 files changed, 47 insertions(+), 68 deletions(-) diff --git a/src/lib/components/ExplorerLink.tsx b/src/lib/components/ExplorerLink.tsx index a432dc981..3a13910af 100644 --- a/src/lib/components/ExplorerLink.tsx +++ b/src/lib/components/ExplorerLink.tsx @@ -21,7 +21,8 @@ export type LinkType = | "code_id" | "block_height" | "proposal_id" - | "pool_id"; + | "pool_id" + | "proposal_id"; interface ExplorerLinkProps extends BoxProps { value: string; @@ -75,13 +76,12 @@ export const getNavigationUrl = ({ url = "/blocks"; break; case "proposal_id": - url = - explorerConfig.proposal || - `${lcdEndpoint}/cosmos/gov/v1beta1/proposals`; + url = "/proposals"; break; case "pool_id": url = "/pools"; break; + case "invalid_address": return ""; default: @@ -189,7 +189,8 @@ export const ExplorerLink = ({ type === "user_address" || type === "tx_hash" || type === "block_height" || - type === "pool_id"; + type === "pool_id" || + type === "proposal_id"; const [hrefLink, textValue] = [ getNavigationUrl({ diff --git a/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx b/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx index 254ddae2f..2e9d83dee 100644 --- a/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx +++ b/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx @@ -3,11 +3,10 @@ import { Flex, Text } from "@chakra-ui/react"; import { MobileCardTemplate } from "../MobileCardTemplate"; import { MobileLabel } from "../MobileLabel"; import { trackMintScan } from "lib/amplitude"; -import { useBaseApiRoute, useCelatoneApp } from "lib/app-provider"; -import { ExplorerLink, getNavigationUrl } from "lib/components/ExplorerLink"; +import { useInternalNavigate } from "lib/app-provider"; +import { ExplorerLink } from "lib/components/ExplorerLink"; import type { Proposal } from "lib/types"; import { ProposalStatus } from "lib/types"; -import { openNewTab } from "lib/utils"; import { Proposer } from "./Proposer"; import { ResolvedHeight } from "./ResolvedHeight"; @@ -21,14 +20,17 @@ export interface ProposalsTableMobileCardProps { export const ProposalsTableMobileCard = ({ proposal, }: ProposalsTableMobileCardProps) => { - const isDepositFailed = proposal.status === ProposalStatus.DEPOSIT_FAILED; const isDepositOrVoting = proposal.status === ProposalStatus.DEPOSIT_PERIOD || proposal.status === ProposalStatus.VOTING_PERIOD; - const { - chainConfig: { explorerLink }, - } = useCelatoneApp(); - const lcdEndpoint = useBaseApiRoute("rest"); + + const navigate = useInternalNavigate(); + + const onCardSelect = (proposalId: number) => + navigate({ + pathname: "/proposals/[proposalId]", + query: { proposalId }, + }); return ( } - onClick={ - !isDepositFailed - ? () => { - trackMintScan("proposal-detail", { - types: proposal.types, - status: proposal.status, - }); - // TOOD: revisit retrieving url (make a proper hook) - openNewTab( - getNavigationUrl({ - type: "proposal_id", - explorerConfig: explorerLink, - value: proposal.id.toString(), - lcdEndpoint, - }) - ); - } - : undefined - } + onClick={() => { + trackMintScan("proposal-detail", { + types: proposal.types, + status: proposal.status, + }); + onCardSelect(proposal.id); + }} /> ); }; diff --git a/src/lib/components/table/proposals/ProposalsTableRow.tsx b/src/lib/components/table/proposals/ProposalsTableRow.tsx index a0f30c1d1..b8ceedce5 100644 --- a/src/lib/components/table/proposals/ProposalsTableRow.tsx +++ b/src/lib/components/table/proposals/ProposalsTableRow.tsx @@ -3,12 +3,11 @@ import { Grid } from "@chakra-ui/react"; import { TableRow, TableRowFreeze } from "../tableComponents"; import { trackMintScan } from "lib/amplitude"; -import { useBaseApiRoute, useCelatoneApp } from "lib/app-provider"; -import { ExplorerLink, getNavigationUrl } from "lib/components/ExplorerLink"; +import { useInternalNavigate } from "lib/app-provider"; +import { ExplorerLink } from "lib/components/ExplorerLink"; import { StopPropagationBox } from "lib/components/StopPropagationBox"; import type { Option, Proposal } from "lib/types"; import { ProposalStatus } from "lib/types"; -import { openNewTab } from "lib/utils"; import { ProposalTextCell } from "./ProposalTextCell"; import { Proposer } from "./Proposer"; @@ -27,52 +26,41 @@ export const ProposalsTableRow = ({ templateColumns, boxShadow, }: ProposalsTableRowProps) => { - const { - chainConfig: { explorerLink }, - } = useCelatoneApp(); - const lcdEndpoint = useBaseApiRoute("rest"); + const navigate = useInternalNavigate(); // TODO - Revisit split columnsWidth const columnsWidth = templateColumns?.toString().split(" "); - const isDepositFailed = proposal.status === ProposalStatus.DEPOSIT_FAILED; const isDepositOrVoting = proposal.status === ProposalStatus.DEPOSIT_PERIOD || proposal.status === ProposalStatus.VOTING_PERIOD; const hoverBg = (): Option => { if (proposal.isExpedited && isDepositOrVoting) return "primary.background"; - return isDepositFailed ? undefined : "gray.900"; + return "gray.900"; }; + const onRowSelect = (proposalId: number) => + navigate({ + pathname: "/proposals/[proposalId]", + query: { proposalId }, + }); + return ( div": { bgColor: hoverBg } }} - onClick={ - !isDepositFailed - ? () => { - trackMintScan("proposal-detail", { - types: proposal.types, - status: proposal.status, - }); - // TOOD: revisit retrieving url (make a proper hook) - openNewTab( - getNavigationUrl({ - type: "proposal_id", - explorerConfig: explorerLink, - value: proposal.id.toString(), - lcdEndpoint, - }) - ); - } - : undefined - } + onClick={() => { + trackMintScan("proposal-detail", { + types: proposal.types, + status: proposal.status, + }); + onRowSelect(proposal.id); + }} > { const router = useRouter(); const navigate = useInternalNavigate(); - const { data } = useProposalData(id); + const { data, isLoading } = useProposalData(id); const handleTabChange = useCallback( (nextTab: TabIndex) => () => { @@ -56,11 +57,11 @@ const ProposalDetailsBody = ({ } }, [router.isReady, tab, navigate, id]); - if (!data || !data.info) - return ; + if (isLoading) return ; + if (!data) return ; + if (!data.info) return ; const proposalData = data.info; - return ( <> From f5488f558dd5cff49afa2c4c479151915ef427f4 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Tue, 30 Jan 2024 16:11:29 +0700 Subject: [PATCH 039/531] fix(components): fix interchain ui version --- package.json | 4 +- pnpm-lock.yaml | 1866 ++++++++---------------------------------------- 2 files changed, 292 insertions(+), 1578 deletions(-) diff --git a/package.json b/package.json index 3e9ce19d1..55007f6ff 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "build-storybook": "storybook build" }, "resolutions": { - "@interchain-ui/react": "1.20.7", + "@interchain-ui/react": "1.11.4", "chakra-react-select": "^4.7.0" }, "dependencies": { @@ -71,7 +71,7 @@ "@graphql-typed-document-node/core": "^3.2.0", "@initia/initia.js": "0.1.12", "@initia/initia.proto": "0.1.12", - "@interchain-ui/react": "1.20.7", + "@interchain-ui/react": "1.11.4", "@monaco-editor/react": "^4.6.0", "@rjsf/chakra-ui": "v5.0.0-beta.10", "@rjsf/core": "v5.0.0-beta.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 161c1f440..bd936c53c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - '@interchain-ui/react': 1.20.7 + '@interchain-ui/react': 1.11.4 chakra-react-select: ^4.7.0 dependencies: @@ -71,7 +71,7 @@ dependencies: version: 2.7.2(@cosmjs/amino@0.32.2)(@cosmjs/proto-signing@0.32.2) '@cosmos-kit/react': specifier: 2.10.2 - version: 2.10.2(@interchain-ui/react@1.20.7)(react-dom@18.2.0)(react@18.2.0) + version: 2.10.2(@interchain-ui/react@1.11.4)(react-dom@18.2.0)(react@18.2.0) '@cosmos-kit/station': specifier: 2.5.2 version: 2.5.2(@cosmjs/amino@0.32.2)(@cosmjs/proto-signing@0.32.2)(@terra-money/terra.js@3.1.10)(axios@1.6.5) @@ -97,8 +97,8 @@ dependencies: specifier: 0.1.12 version: 0.1.12 '@interchain-ui/react': - specifier: 1.20.7 - version: 1.20.7(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + specifier: 1.11.4 + version: 1.11.4(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) '@monaco-editor/react': specifier: ^4.6.0 version: 4.6.0(monaco-editor@0.44.0)(react-dom@18.2.0)(react@18.2.0) @@ -3522,17 +3522,17 @@ packages: - utf-8-validate dev: false - /@cosmos-kit/react@2.10.2(@interchain-ui/react@1.20.7)(react-dom@18.2.0)(react@18.2.0): + /@cosmos-kit/react@2.10.2(@interchain-ui/react@1.11.4)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-+/YCETixxhMc1P/cyKdNbqjgT728Nn7Y0aWqH7VbTGANS5NvCIlk82VPlXH7ybYRApBdsG8rJ1Sc/n3kAgdk4g==} peerDependencies: - '@interchain-ui/react': 1.20.7 + '@interchain-ui/react': 1.11.4 react: ^18 react-dom: ^18 dependencies: '@chain-registry/types': 0.17.0 '@cosmos-kit/core': 2.8.2 '@cosmos-kit/react-lite': 2.6.2(react-dom@18.2.0)(react@18.2.0) - '@interchain-ui/react': 1.20.7(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@interchain-ui/react': 1.11.4(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) '@react-icons/all-files': 4.1.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4350,42 +4350,8 @@ packages: /@floating-ui/utils@0.2.1: resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} - /@formatjs/ecma402-abstract@1.18.2: - resolution: {integrity: sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==} - dependencies: - '@formatjs/intl-localematcher': 0.5.4 - tslib: 2.6.2 - dev: false - - /@formatjs/fast-memoize@2.2.0: - resolution: {integrity: sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==} - dependencies: - tslib: 2.6.2 - dev: false - - /@formatjs/icu-messageformat-parser@2.7.5: - resolution: {integrity: sha512-zCB53HdGDibh6/2ISEN3TGsFQruQ6gGKMFV94qHNyVrs0tNO6ncKhV0vq0n3Ydz8ipIQ2GaYAvfCoimNOVvKqA==} - dependencies: - '@formatjs/ecma402-abstract': 1.18.2 - '@formatjs/icu-skeleton-parser': 1.7.2 - tslib: 2.6.2 - dev: false - - /@formatjs/icu-skeleton-parser@1.7.2: - resolution: {integrity: sha512-nlIXVv280bjGW3ail5Np1+xgGKBnMhwQQIivgbk9xX0af8ESQO+y2VW9TOY7mCrs3WH786uVpZlLimXAlXH7SA==} - dependencies: - '@formatjs/ecma402-abstract': 1.18.2 - tslib: 2.6.2 - dev: false - - /@formatjs/intl-localematcher@0.5.4: - resolution: {integrity: sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==} - dependencies: - tslib: 2.6.2 - dev: false - - /@formkit/auto-animate@0.8.1: - resolution: {integrity: sha512-0/Z2cuNXWVVIG/l0SpcHAWFhGdvLJ8DRvEfRWvmojtmRWfEy+LWNwgDazbZqY0qQYtkHcoEK3jBLkhiZaB/4Ig==} + /@formkit/auto-animate@1.0.0-beta.6: + resolution: {integrity: sha512-PVDhLAlr+B4Xb7e+1wozBUWmXa6BFU8xUPR/W/E+TsQhPS1qkAdAsJ25keEnFrcePSnXHrOsh3tiFbEToOzV9w==} dev: false /@graphql-codegen/cli@5.0.0(@types/node@20.11.5)(graphql@16.8.1)(typescript@5.3.3): @@ -4918,8 +4884,8 @@ packages: zod: 3.22.4 dev: false - /@interchain-ui/react@1.20.7(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-356bhFYCWpokHcjXM5pYcWWsXjqG+fjnT8r3w9qjLmqMRVqJMp/m0vAB3OqlaejPKA0NIusnOfCSM6UwvdH09A==} + /@interchain-ui/react@1.11.4(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-jUx02LyyUjSKANcpNJ9DPOkVlD2nERmQZsqEnUeJQ6wsG4rgO5yd0jHDUgqotvwxkRisYSy8jqDGe3r4pYsNBw==} peerDependencies: react: ^18.x react-dom: ^18.x @@ -4927,53 +4893,27 @@ packages: '@fastify/deepmerge': 1.3.0 '@floating-ui/dom': 1.5.4 '@floating-ui/react': 0.26.6(react-dom@18.2.0)(react@18.2.0) - '@formkit/auto-animate': 0.8.1 - '@react-aria/utils': 3.23.0(react@18.2.0) + '@formkit/auto-animate': 1.0.0-beta.6 '@vanilla-extract/css': 1.14.0 + '@vanilla-extract/css-utils': 0.1.3 '@vanilla-extract/dynamic': 2.1.0 - '@vanilla-extract/recipes': 0.5.1(@vanilla-extract/css@1.14.0) + '@vanilla-extract/recipes': 0.4.0(@vanilla-extract/css@1.14.0) + '@zag-js/number-input': 0.15.0 + '@zag-js/react': 0.15.0(react-dom@18.2.0)(react@18.2.0) animejs: 3.2.2 bignumber.js: 9.1.2 - client-only: 0.0.1 clsx: 1.2.1 copy-to-clipboard: 3.3.3 immer: 9.0.21 lodash: 4.17.21 rainbow-sprinkles: 0.17.1(@vanilla-extract/css@1.14.0)(@vanilla-extract/dynamic@2.1.0) react: 18.2.0 - react-aria: 3.31.1(react-dom@18.2.0)(react@18.2.0) react-dom: 18.2.0(react@18.2.0) - react-stately: 3.29.1(react@18.2.0) zustand: 4.4.7(@types/react@18.2.48)(immer@9.0.21)(react@18.2.0) transitivePeerDependencies: - '@types/react' dev: false - /@internationalized/date@3.5.1: - resolution: {integrity: sha512-LUQIfwU9e+Fmutc/DpRTGXSdgYZLBegi4wygCWDSVmUdLTaMHsQyASDiJtREwanwKuQLq0hY76fCJ9J/9I2xOQ==} - dependencies: - '@swc/helpers': 0.5.2 - dev: false - - /@internationalized/message@3.1.1: - resolution: {integrity: sha512-ZgHxf5HAPIaR0th+w0RUD62yF6vxitjlprSxmLJ1tam7FOekqRSDELMg4Cr/DdszG5YLsp5BG3FgHgqquQZbqw==} - dependencies: - '@swc/helpers': 0.5.2 - intl-messageformat: 10.5.10 - dev: false - - /@internationalized/number@3.5.0: - resolution: {integrity: sha512-ZY1BW8HT9WKYvaubbuqXbbDdHhOUMfE2zHHFJeTppid0S+pc8HtdIxFxaYMsGjCb4UsF+MEJ4n2TfU7iHnUK8w==} - dependencies: - '@swc/helpers': 0.5.2 - dev: false - - /@internationalized/string@3.2.0: - resolution: {integrity: sha512-Xx3Sy3f2c9ctT+vh8c7euEaEHQZltp0euZ3Hy4UfT3E13r6lxpUS3kgKyumEjboJZSnaZv7JhqWz3D75v+IxQg==} - dependencies: - '@swc/helpers': 0.5.2 - dev: false - /@ioredis/commands@1.2.0: resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} dev: false @@ -6182,1450 +6122,232 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@radix-ui/react-slot@1.0.2(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - react: 18.2.0 - dev: true - - /@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-toggle': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true - - /@radix-ui/react-toggle@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true - - /@radix-ui/react-toolbar@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-tBgmM/O7a07xbaEkYJWYTXkIdU/1pW4/KZORR43toC/4XWyBCURK0ei9kMUdp+gTPPKBgYLxXmRSH1EVcIDp8Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-separator': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-toggle-group': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true - - /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 - react: 18.2.0 - dev: true - - /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - react: 18.2.0 - dev: true - - /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - react: 18.2.0 - dev: true - - /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 - react: 18.2.0 - dev: true - - /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 - react: 18.2.0 - dev: true - - /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/rect': 1.0.1 - '@types/react': 18.2.48 - react: 18.2.0 - dev: true - - /@radix-ui/react-use-size@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - react: 18.2.0 - dev: true - - /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true - - /@radix-ui/rect@1.0.1: - resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} - dependencies: - '@babel/runtime': 7.23.8 - dev: true - - /@react-aria/breadcrumbs@3.5.9(react@18.2.0): - resolution: {integrity: sha512-asbXTL5NjeHl1+YIF0K70y8tNHk8Lb6VneYH8yOkpLO49ejyNDYBK0tp0jtI9IZAQiTa2qkhYq58c9LloTwebQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/link': 3.6.3(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/breadcrumbs': 3.7.2(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/button@3.9.1(react@18.2.0): - resolution: {integrity: sha512-nAnLMUAnwIVcRkKzS1G2IU6LZSkIWPJGu9amz/g7Y02cGUwFp3lk5bEw2LdoaXiSDJNSX8g0SZFU8FROg57jfQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/toggle': 3.7.0(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/calendar@3.5.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-8k7khgea5kwfWriZJWCADNB0R2d7g5A6tTjUEktK4FFZcTb0RCubFejts4hRyzKlF9XHUro2dfh6sbZrzfMKDQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@internationalized/date': 3.5.1 - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/live-announcer': 3.3.1 - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/calendar': 3.4.3(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/calendar': 3.4.3(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/checkbox@3.13.0(react@18.2.0): - resolution: {integrity: sha512-eylJwtADIPKJ1Y5rITNJm/8JD8sXG2nhiZBIg1ko44Szxrpu+Le53NoGtg8nlrfh9vbUrXVvuFtf2jxbPXR5Jw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/form': 3.0.1(react@18.2.0) - '@react-aria/label': 3.7.4(react@18.2.0) - '@react-aria/toggle': 3.10.0(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/checkbox': 3.6.1(react@18.2.0) - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-stately/toggle': 3.7.0(react@18.2.0) - '@react-types/checkbox': 3.6.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/combobox@3.8.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-q8Kdw1mx6nSSydXqRagRuyKH1NPGvpSOFjUfgxdO8ZqaEEuZX3ObOoiO/DLtXDndViNc03dMbMpfuJoLYXfCtg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/listbox': 3.11.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/live-announcer': 3.3.1 - '@react-aria/menu': 3.12.0(react-dom@18.2.0)(react@18.2.0) - '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) - '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/textfield': 3.14.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/combobox': 3.8.1(react@18.2.0) - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/combobox': 3.10.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/datepicker@3.9.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-bdlY2H/zwe3hQf64Lp1oGTf7Va8ennDyAv4Ffowb+BOoL8+FB9smtGyONKe87zXu7VJL2M5xYAi4n7c004PM+w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@internationalized/date': 3.5.1 - '@internationalized/number': 3.5.0 - '@internationalized/string': 3.2.0 - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/form': 3.0.1(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/label': 3.7.4(react@18.2.0) - '@react-aria/spinbutton': 3.6.1(react-dom@18.2.0)(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/datepicker': 3.9.1(react@18.2.0) - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/calendar': 3.4.3(react@18.2.0) - '@react-types/datepicker': 3.7.1(react@18.2.0) - '@react-types/dialog': 3.5.7(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/dialog@3.5.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-H2BNVLOfaum6/4irH5XUU/wIcXSs/ymxmTPGmucRG1hzaUh8H3tupdl/qCZ+SsW9oYDFlphY172uM1nsPjBMiQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/dialog': 3.5.7(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/dnd@3.5.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-7OPGePdle+xNYHAIAUOvIETRMfnkRt7h/C0bCkxUR2GYefEbTzfraso4ppNH2JZ7fCRd0K/Qe+jvQklwusHAKA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@internationalized/string': 3.2.0 - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/live-announcer': 3.3.1 - '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/dnd': 3.2.7(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/focus@3.16.0(react@18.2.0): - resolution: {integrity: sha512-GP6EYI07E8NKQQcXHjpIocEU0vh0oi0Vcsd+/71fKS0NnTR0TUOEeil0JuuQ9ymkmPDTu51Aaaa4FxVsuN/23A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - clsx: 2.1.0 - react: 18.2.0 - dev: false - - /@react-aria/form@3.0.1(react@18.2.0): - resolution: {integrity: sha512-6586oODMDR4/ciGRwXjpvEAg7tWGSDrXE//waK0n5e5sMuzlPOo1DHc5SpPTvz0XdJsu6VDt2rHdVWVIC9LEyw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/grid@3.8.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-JlQDkdm5heG1FfRyy5KnB8b6s/hRqSI6Xt2xN2AccLX5kcbfFr2/d5KVxyf6ahfa4Gfd46alN6477ju5eTWJew==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/live-announcer': 3.3.1 - '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/grid': 3.8.4(react@18.2.0) - '@react-stately/selection': 3.14.2(react@18.2.0) - '@react-stately/virtualizer': 3.6.6(react@18.2.0) - '@react-types/checkbox': 3.6.0(react@18.2.0) - '@react-types/grid': 3.2.3(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/gridlist@3.7.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-rkkepYM7xJiebR0g3uC4zzkdR7a8z0fLaM+sg9lSTbdElHMLAlrebS2ytEyZnhiu9nbOnw13GN1OC4/ZenzbHQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/grid': 3.8.6(react-dom@18.2.0)(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/list': 3.10.2(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/i18n@3.10.0(react@18.2.0): - resolution: {integrity: sha512-sviD5Y1pLPG49HHRmVjR+5nONrp0HK219+nu9Y7cDfUhXu2EjyhMS9t/n9/VZ69hHChZ2PnHYLEE2visu9CuCg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@internationalized/date': 3.5.1 - '@internationalized/message': 3.1.1 - '@internationalized/number': 3.5.0 - '@internationalized/string': 3.2.0 - '@react-aria/ssr': 3.9.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/interactions@3.20.1(react@18.2.0): - resolution: {integrity: sha512-PLNBr87+SzRhe9PvvF9qvzYeP4ofTwfKSorwmO+hjr3qoczrSXf4LRQlb27wB6hF10C7ZE/XVbUI1lj4QQrZ/g==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/ssr': 3.9.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/label@3.7.4(react@18.2.0): - resolution: {integrity: sha512-3Y0yyrqpLzZdzHw+TOyzwuyx5wa2ujU5DGfKuL5GFnU9Ii4DtdwBGSYS7Yu7qadU+eQmG4OGhAgFVswbIgIwJw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/link@3.6.3(react@18.2.0): - resolution: {integrity: sha512-8kPWc4u/lDow3Ll0LDxeMgaxt9Y3sl8UldKLGli8tzRSltYFugNh/n+i9sCnmo4Qv9Tp9kYv+yxBK50Uk9sINw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/link': 3.5.2(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/listbox@3.11.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-PBrnldmyEYUUJvfDeljW8ITvZyBTfGpLNf0b5kfBPK3TDgRH4niEH2vYEcaZvSqb0FrpdvcunuTRXcOpfb+gCQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/label': 3.7.4(react@18.2.0) - '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/list': 3.10.2(react@18.2.0) - '@react-types/listbox': 3.4.6(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/live-announcer@3.3.1: - resolution: {integrity: sha512-hsc77U7S16trM86d+peqJCOCQ7/smO1cybgdpOuzXyiwcHQw8RQ4GrXrS37P4Ux/44E9nMZkOwATQRT2aK8+Ew==} - dependencies: - '@swc/helpers': 0.5.2 - dev: false - - /@react-aria/menu@3.12.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Nsujv3b61WR0gybDKnBjAeyxDVJOfPLMggRUf9SQDfPWnrPXEsAFxaPaVcAkzlfI4HiQs1IxNwsKFNpc3PPZTQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) - '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/menu': 3.6.0(react@18.2.0) - '@react-stately/tree': 3.7.5(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/menu': 3.9.6(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/meter@3.4.9(react@18.2.0): - resolution: {integrity: sha512-1/FHFmFmSyfQBJ2oH152lp4nps76v1UdhnFbIsmRIH+0g0IfMv1yDT2M9dIZ/b9DgVZSx527FmWOXm0eHGKD6w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/progress': 3.4.9(react@18.2.0) - '@react-types/meter': 3.3.6(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/numberfield@3.10.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-KjGTXq3lIhN4DEdEeHzfS/k9Qq0sDEpLgLr/hgSfGN4Q7Syu4Ck/n2HXmrDn//z08/wNvcukuP6Ioers138DcQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/spinbutton': 3.6.1(react-dom@18.2.0)(react@18.2.0) - '@react-aria/textfield': 3.14.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-stately/numberfield': 3.8.0(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/numberfield': 3.7.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/overlays@3.20.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-2m7MpRJL5UucbEuu08lMHsiFJoDowkJV4JAIFBZYK1NzVH0vF/A+w9HRNM7jRwx2DUxE+iIsZnl8yKV/7KY8OQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/ssr': 3.9.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-aria/visually-hidden': 3.8.8(react@18.2.0) - '@react-stately/overlays': 3.6.4(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/overlays': 3.8.4(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/progress@3.4.9(react@18.2.0): - resolution: {integrity: sha512-CME1ZLsJHOmSgK8IAPOC/+vYO5Oc614mkEw5MluT/yclw5rMyjAkK1XsHLjEXy81uwPeiRyoQQIMPKG2/sMxFQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/label': 3.7.4(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/progress': 3.5.1(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/radio@3.10.0(react@18.2.0): - resolution: {integrity: sha512-6NaKzdGymdcVWLYgHT0cHsVmNzPOp89o8r41w29OPBQWu8w2c9mxg4366OiIZn/uXIBS4abhQ4nL4toBRLgBrg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/form': 3.0.1(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/label': 3.7.4(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/radio': 3.10.1(react@18.2.0) - '@react-types/radio': 3.7.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/searchfield@3.7.1(react@18.2.0): - resolution: {integrity: sha512-ebhnV/reNByIZzpcQLHIo1RQ+BrYS8HdwX624i9R7dep1gxGHXYEaqL9aSY+RdngNerB4OeiWmB75em9beSpjQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/textfield': 3.14.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/searchfield': 3.5.0(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/searchfield': 3.5.2(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/select@3.14.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-pAy/+Xbj11Lx6bi/O1hWH0NSIDRxFb6V7N0ry2L8x7MALljh516VbpnAc5RgvbjbuKq0cHUAcdINOzOzpYWm4A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/form': 3.0.1(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/label': 3.7.4(react@18.2.0) - '@react-aria/listbox': 3.11.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/menu': 3.12.0(react-dom@18.2.0)(react@18.2.0) - '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-aria/visually-hidden': 3.8.8(react@18.2.0) - '@react-stately/select': 3.6.1(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/select': 3.9.1(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/selection@3.17.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-xl2sgeGH61ngQeE05WOWWPVpGRTPMjQEFmsAWEprArFi4Z7ihSZgpGX22l1w7uSmtXM/eN/v0W8hUYUju5iXlQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/selection': 3.14.2(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/separator@3.3.9(react@18.2.0): - resolution: {integrity: sha512-1wEXiaSJjq2+DR5TC0RKnUBsfZN+YXTzyI7XMzjQoc3YlclumX8wQtzPAOGOEjHB1JKUgo1Gw70FtupVXz58QQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/slider@3.7.4(react@18.2.0): - resolution: {integrity: sha512-OFJWeGSL2duVDFs/kcjlWsY6bqCVKZgM0aFn2QN4wmID+vfBvBnqGHAgWv3BCePTAPS3+GBjMN002TrftorjwQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/label': 3.7.4(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/slider': 3.5.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@react-types/slider': 3.7.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/spinbutton@3.6.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-u5GuOP3k4Zis055iY0fZJNHU7dUNCoSfUq5LKwJ1iNaCqDcavdstAnAg+X1a7rhpp5zCnJmAMseo3Qmzi9P+Ew==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/live-announcer': 3.3.1 - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/ssr@3.9.1(react@18.2.0): - resolution: {integrity: sha512-NqzkLFP8ZVI4GSorS0AYljC13QW2sc8bDqJOkBvkAt3M8gbcAXJWVRGtZBCRscki9RZF+rNlnPdg0G0jYkhJcg==} - engines: {node: '>= 12'} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/switch@3.6.0(react@18.2.0): - resolution: {integrity: sha512-YNWc5fGLNXE4XlmDAKyqAdllRiClGR7ki4KGFY7nL+xR5jxzjCGU3S3ToMK5Op3QSMGZLxY/aYmC4O+MvcoADQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/toggle': 3.10.0(react@18.2.0) - '@react-stately/toggle': 3.7.0(react@18.2.0) - '@react-types/switch': 3.5.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/table@3.13.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-AzmETpyxwNqISTzwHJPs85x9gujG40IIsSOBUdp49oKhB85RbPLvMwhadp4wCVAoHw3erOC/TJxHtVc7o2K1LA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/grid': 3.8.6(react-dom@18.2.0)(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/live-announcer': 3.3.1 - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-aria/visually-hidden': 3.8.8(react@18.2.0) - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/flags': 3.0.0 - '@react-stately/table': 3.11.4(react@18.2.0) - '@react-stately/virtualizer': 3.6.6(react@18.2.0) - '@react-types/checkbox': 3.6.0(react@18.2.0) - '@react-types/grid': 3.2.3(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@react-types/table': 3.9.2(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/tabs@3.8.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Plw0K/5Qv35vYq7pHZFfQB2BF5OClFx4Abzo9hLVx4oMy3qb7i5lxmLBVbt81yPX/MdjYeP4zO1EHGBl4zMRhA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/tabs': 3.6.3(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@react-types/tabs': 3.3.4(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/tag@3.3.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-w7d8sVZqxTo8VFfeg2ixLp5kawtrcguGznVY4mt5aE6K8LMJOeNVDqNNfolfyia80VjOWjeX+RpVdVJRdrv/GQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/gridlist': 3.7.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/label': 3.7.4(react@18.2.0) - '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/list': 3.10.2(react@18.2.0) - '@react-types/button': 3.9.1(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@react-aria/textfield@3.14.1(react@18.2.0): - resolution: {integrity: sha512-UMepuYtDdCgrUF4dMphNxrUm23xOmR54aZD1pbp9cJyfioVkJN35BTXZVkD0D07gHLn4RhxKIZxBortQQrLB9g==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/form': 3.0.1(react@18.2.0) - '@react-aria/label': 3.7.4(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@react-types/textfield': 3.9.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/toggle@3.10.0(react@18.2.0): - resolution: {integrity: sha512-6cUf4V9TuG2J7AvXUdU/GspEPFCubUOID3mrselSe563RViy+mMZk0vUEOdyoNanDcEXl58W4dE3SGWxFn71vg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/toggle': 3.7.0(react@18.2.0) - '@react-types/checkbox': 3.6.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/tooltip@3.7.0(react@18.2.0): - resolution: {integrity: sha512-+u9Sftkfe09IDyPEnbbreFKS50vh9X/WTa7n1u2y3PenI9VreLpUR6czyzda4BlvQ95e9jQz1cVxUjxTNaZmBw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-stately/tooltip': 3.4.6(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@react-types/tooltip': 3.4.6(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-aria/utils@3.23.0(react@18.2.0): - resolution: {integrity: sha512-fJA63/VU4iQNT8WUvrmll3kvToqMurD69CcgVmbQ56V7ZbvlzFi44E7BpnoaofScYLLtFWRjVdaHsohT6O/big==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/ssr': 3.9.1(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - clsx: 2.1.0 - react: 18.2.0 - dev: false - - /@react-aria/visually-hidden@3.8.8(react@18.2.0): - resolution: {integrity: sha512-Cn2PYKD4ijGDtF0+dvsh8qa4y7KTNAlkTG6h20r8Q+6UTyRNmtE2/26QEaApRF8CBiNy9/BZC/ZC4FK2OjvCoA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-icons/all-files@4.1.0(react@18.2.0): - resolution: {integrity: sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==} - peerDependencies: - react: '*' - dependencies: - react: 18.2.0 - dev: false - - /@react-stately/calendar@3.4.3(react@18.2.0): - resolution: {integrity: sha512-OrEcdskszDjnjVnFuSiDC2PVBJ6lWMCJROD5s6W1LUehUtBp8LX9wPavAGHV43LbhN9ldj560sxaQ4WCddrRCA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@internationalized/date': 3.5.1 - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/calendar': 3.4.3(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/checkbox@3.6.1(react@18.2.0): - resolution: {integrity: sha512-rOjFeVBy32edYwhKiHj3ZLdLeO+xZ2fnBwxnOBjcygnw4Neygm8FJH/dB1J0hdYYR349yby86ED2x0wRc84zPw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/checkbox': 3.6.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/collections@3.10.4(react@18.2.0): - resolution: {integrity: sha512-OHhCrItGt4zB2bSrgObRo0H2SC7QlkH8ReGxo+NVIWchXRLRoiWBP7S+IwleewEo5gOqDVPY3hqA9n4iiI8twg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/combobox@3.8.1(react@18.2.0): - resolution: {integrity: sha512-FaWkqTXQdWg7ptaeU4iPcqF/kxbRg2ZNUcvW/hiL/enciV5tRCsddvfNqvDvy1L30z9AUwlp9MWqzm/DhBITCw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-stately/list': 3.10.2(react@18.2.0) - '@react-stately/overlays': 3.6.4(react@18.2.0) - '@react-stately/select': 3.6.1(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/combobox': 3.10.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/data@3.11.0(react@18.2.0): - resolution: {integrity: sha512-0BlPT58WrAtUvpiEfUuyvIsGFTzp/9vA5y+pk53kGJhOdc5tqBGHi9cg40pYE/i1vdHJGMpyHGRD9nkQb8wN3Q==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/datepicker@3.9.1(react@18.2.0): - resolution: {integrity: sha512-o5xLvlZGJyAbTev2yruGlV2fzQyIDuYTgL19TTt0W0WCfjGGr/AAA9GjGXXmyoRA7sZMxqIPnnv7lNrdA38ofA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@internationalized/date': 3.5.1 - '@internationalized/string': 3.2.0 - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-stately/overlays': 3.6.4(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/datepicker': 3.7.1(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/dnd@3.2.7(react@18.2.0): - resolution: {integrity: sha512-QqSCvE9Rhp+Mr8Mt/SrByze24BFX1cy7gmXbwoqAYgHNIx3gWCVdBLqxfpfgYIhZdF9H72EWS8lQkfkZla06Ng==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/selection': 3.14.2(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/flags@3.0.0: - resolution: {integrity: sha512-e3i2ItHbIa0eEwmSXAnPdD7K8syW76JjGe8ENxwFJPW/H1Pu9RJfjkCb/Mq0WSPN/TpxBb54+I9TgrGhbCoZ9w==} - dependencies: - '@swc/helpers': 0.4.36 - dev: false - - /@react-stately/form@3.0.0(react@18.2.0): - resolution: {integrity: sha512-C8wkfFmtx1escizibhdka5JvTy9/Vp173CS9cakjvWTmnjYYC1nOlzwp7BsYWTgerCFbRY/BU/Cf/bJDxPiUKQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/grid@3.8.4(react@18.2.0): - resolution: {integrity: sha512-rwqV1K4lVhaiaqJkt4TfYqdJoVIyqvSm98rKAYfCNzrKcivVpoiCMJ2EMt6WlYCjDVBdEOQ7fMV1I60IV0pntA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/selection': 3.14.2(react@18.2.0) - '@react-types/grid': 3.2.3(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/list@3.10.2(react@18.2.0): - resolution: {integrity: sha512-INt+zofkIg2KN8B95xPi9pJG7ZFWAm30oIm/lCPBqM3K1Nm03/QaAbiQj2QeJcOsG3lb7oqI6D6iwTolwJkjIQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/selection': 3.14.2(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/menu@3.6.0(react@18.2.0): - resolution: {integrity: sha512-OB6CjNyfOkAuirqx1oTL8z8epS9WDzLyrXjmRnxdiCU9EgRXLGAQNECuO7VIpl58oDry8tgRJiJ8fn8FivWSQA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/overlays': 3.6.4(react@18.2.0) - '@react-types/menu': 3.9.6(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/numberfield@3.8.0(react@18.2.0): - resolution: {integrity: sha512-1XvB8tDOvZKcFnMM6qNLEaTVJcIc0jRFS/9jtS8MzalZvh8DbKi0Ucm1bGU7S5rkCx2QWqZ0rGOIm2h/RlcpkA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@internationalized/number': 3.5.0 - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/numberfield': 3.7.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/overlays@3.6.4(react@18.2.0): - resolution: {integrity: sha512-tHEaoAGpE9dSnsskqLPVKum59yGteoSqsniTopodM+miQozbpPlSjdiQnzGLroy5Afx5OZYClE616muNHUILXA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/overlays': 3.8.4(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/radio@3.10.1(react@18.2.0): - resolution: {integrity: sha512-MsBYbcLCvjKsqTAKe43T681F2XwKMsS7PLG0eplZgWP9210AMY78GeY1XPYZKHPAau8XkbYiuJqbqTerIJ3DBw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/radio': 3.7.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/searchfield@3.5.0(react@18.2.0): - resolution: {integrity: sha512-SStjChkn/33pEn40slKQPnBnmQYyxVazVwPjiBkdeVejC42lUVairUTrGJgF0PNoZTbxn0so2/XzjqTC9T8iCw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/searchfield': 3.5.2(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/select@3.6.1(react@18.2.0): - resolution: {integrity: sha512-e5ixtLiYLlFWM8z1msDqXWhflF9esIRfroptZsltMn1lt2iImUlDRlOTZlMtPQzUrDWoiHXRX88sSKUM/jXjQQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-stately/list': 3.10.2(react@18.2.0) - '@react-stately/overlays': 3.6.4(react@18.2.0) - '@react-types/select': 3.9.1(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/selection@3.14.2(react@18.2.0): - resolution: {integrity: sha512-mL7OoiUgVWaaF7ks5XSxgbXeShijYmD4G3bkBHhqkpugU600QH6BM2hloCq8KOUupk1y8oTljPtF9EmCv375DA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/slider@3.5.0(react@18.2.0): - resolution: {integrity: sha512-dOVpIxb7XKuiRxgpHt1bUSlsklciFki100tKIyBPR+Okar9iC/CwLYROYgVfLkGe77jEBNkor9tDLjDGEWcc1w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@react-types/slider': 3.7.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/table@3.11.4(react@18.2.0): - resolution: {integrity: sha512-dWINJIEOKQl4qq3moq+S8xCD3m+yJqBj0dahr+rOkS+t2uqORwzsusTM35D2T/ZHZi49S2GpE7QuDa+edCynPw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/flags': 3.0.0 - '@react-stately/grid': 3.8.4(react@18.2.0) - '@react-stately/selection': 3.14.2(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/grid': 3.2.3(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@react-types/table': 3.9.2(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/tabs@3.6.3(react@18.2.0): - resolution: {integrity: sha512-Nj+Gacwa2SIzYIvHW40GsyX4Q6c8kF7GOuXESeQswbCjnwqhrSbDBp+ngPcUPUJxqFh6JhDCVwAS3wMhUoyUwA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/list': 3.10.2(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@react-types/tabs': 3.3.4(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/toggle@3.7.0(react@18.2.0): - resolution: {integrity: sha512-TRksHkCJk/Xogq4181g3CYgJf+EfsJCqX5UZDSw1Z1Kgpvonjmdf6FAfQfCh9QR2OuXUL6hOLUDVLte5OPI+5g==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/checkbox': 3.6.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/tooltip@3.4.6(react@18.2.0): - resolution: {integrity: sha512-uL93bmsXf+OOgpKLPEKfpDH4z+MK2CuqlqVxx7rshN0vjWOSoezE5nzwgee90+RpDrLNNNWTNa7n+NkDRpI1jA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/overlays': 3.6.4(react@18.2.0) - '@react-types/tooltip': 3.4.6(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/tree@3.7.5(react@18.2.0): - resolution: {integrity: sha512-xTJVwvhAeY0N5rui4N/TxN7f8hjXdqApDuGDxMZeFAWoQz8Abf7LFKBVQ3OkT6qVr7P+23dgoisUDBhD5a45Hg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/selection': 3.14.2(react@18.2.0) - '@react-stately/utils': 3.9.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/utils@3.9.0(react@18.2.0): - resolution: {integrity: sha512-yPKFY1F88HxuZ15BG2qwAYxtpE4HnIU0Ofi4CuBE0xC6I8mwo4OQjDzi+DZjxQngM9D6AeTTD6F1V8gkozA0Gw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-stately/virtualizer@3.6.6(react@18.2.0): - resolution: {integrity: sha512-9hWvfITdE/028q4YFve6FxlmA3PdSMkUwpYA+vfaGCXI/4DFZIssBMspUeu4PTRJoV+k+m0z1wYHPmufrq6a3g==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - '@swc/helpers': 0.5.2 - react: 18.2.0 - dev: false - - /@react-types/breadcrumbs@3.7.2(react@18.2.0): - resolution: {integrity: sha512-esl6RucDW2CNMsApJxNYfMtDaUcfLlwKMPH/loYsOBbKxGl2HsgVLMcdpjEkTRs2HCTNCbBXWpeU8AY77t+bsw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/link': 3.5.2(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/button@3.9.1(react@18.2.0): - resolution: {integrity: sha512-bf9iTar3PtqnyV9rA+wyFyrskZKhwmOuOd/ifYIjPs56YNVXWH5Wfqj6Dx3xdFBgtKx8mEVQxVhoX+WkHX+rtw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/calendar@3.4.3(react@18.2.0): - resolution: {integrity: sha512-96x57ctX5wNEl+8et3sc2NQm8neOJayEeqOQQpyPtI7jyvst/xBrKCwysf9W/dhgPlUC+KeBAYFWfjd5hFVHYA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@internationalized/date': 3.5.1 - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/checkbox@3.6.0(react@18.2.0): - resolution: {integrity: sha512-vgbuJzQpVCNT5AZWV0OozXCnihqrXxoZKfJFIw0xro47pT2sn3t5UC4RA9wfjDGMoK4frw1K/4HQLsQIOsPBkw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/combobox@3.10.0(react@18.2.0): - resolution: {integrity: sha512-1IXSNS02TPbguyYopaW2snU6sZusbClHrEyVr4zPeexTV4kpUUBNXOzFQ+eSQRR0r2XW57Z0yRW4GJ6FGU0yCA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/datepicker@3.7.1(react@18.2.0): - resolution: {integrity: sha512-5juVDULOytNzkotqX8j5mYKJckeIpkgbHqVSGkPgLw0++FceIaSZ6RH56cqLup0pO45paqIt9zHh+QXBYX+syg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@internationalized/date': 3.5.1 - '@react-types/calendar': 3.4.3(react@18.2.0) - '@react-types/overlays': 3.8.4(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/dialog@3.5.7(react@18.2.0): - resolution: {integrity: sha512-geYoqAyQaTLG43AaXdMUVqZXYgkSifrD9cF7lR2kPAT0uGFv0YREi6ieU+aui8XJ83EW0xcxP+EPWd2YkN4D4w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/overlays': 3.8.4(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/grid@3.2.3(react@18.2.0): - resolution: {integrity: sha512-GQM4RDmYhstcYZ0Odjq+xUwh1fhLmRebG6qMM8OXHTPQ77nhl3wc1UTGRhZm6mzEionplSRx4GCpEMEHMJIU0w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/link@3.5.2(react@18.2.0): - resolution: {integrity: sha512-/s51/WejmpLiyxOgP89s4txgxYoGaPe8pVDItVo1h4+BhU1Puyvgv/Jx8t9dPvo6LUXbraaN+SgKk/QDxaiirw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/listbox@3.4.6(react@18.2.0): - resolution: {integrity: sha512-XOQvrTqNh5WIPDvKiWiep8T07RAsMfjAXTjDbnjxVlKACUXkcwpts9kFaLnJ9LJRFt6DwItfP+WMkzvmx63/NQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/menu@3.9.6(react@18.2.0): - resolution: {integrity: sha512-w/RbFInOf4nNayQDv5c2L8IMJbcFOkBhsT3xvvpTy+CHvJcQdjggwaV1sRiw7eF/PwB81k2CwigmidUzHJhKDg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-types/overlays': 3.8.4(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - - /@react-types/meter@3.3.6(react@18.2.0): - resolution: {integrity: sha512-1XYp1fA9UU0lO6kjf3TwVE8mppOJa64mBKAcLWtTyq1e/cYIAbx5o6CsuUx0YDpXKF6gdtvIWvfmxeWsmqJ1jQ==} + /@radix-ui/react-slot@1.0.2(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true dependencies: - '@react-types/progress': 3.5.1(react@18.2.0) + '@babel/runtime': 7.23.8 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 react: 18.2.0 - dev: false + dev: true - /@react-types/numberfield@3.7.0(react@18.2.0): - resolution: {integrity: sha512-gaGi+vqm1Y8LCWRsWYUjcGftPIzl+8W2VOfkgKMLM8y76nnwTPtmAqs+Ap1cg7sEJSfsiKMq93e9yvP3udrC2w==} + /@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) + '@babel/runtime': 7.23.8 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toggle': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 react: 18.2.0 - dev: false + react-dom: 18.2.0(react@18.2.0) + dev: true - /@react-types/overlays@3.8.4(react@18.2.0): - resolution: {integrity: sha512-pfgNlQnbF6RB/R2oSxyqAP3Uzz0xE/k5q4n5gUeCDNLjY5qxFHGE8xniZZ503nZYw6VBa9XMN1efDOKQyeiO0w==} + /@radix-ui/react-toggle@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) + '@babel/runtime': 7.23.8 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 react: 18.2.0 - dev: false + react-dom: 18.2.0(react@18.2.0) + dev: true - /@react-types/progress@3.5.1(react@18.2.0): - resolution: {integrity: sha512-CqsUjczUK/SfuFzDcajBBaXRTW0D3G9S/yqLDj9e8E0ii+lGDLt1PHj24t1J7E88U2rVYqmM9VL4NHTt8o3IYA==} + /@radix-ui/react-toolbar@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-tBgmM/O7a07xbaEkYJWYTXkIdU/1pW4/KZORR43toC/4XWyBCURK0ei9kMUdp+gTPPKBgYLxXmRSH1EVcIDp8Q==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) + '@babel/runtime': 7.23.8 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-separator': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toggle-group': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 react: 18.2.0 - dev: false + react-dom: 18.2.0(react@18.2.0) + dev: true - /@react-types/radio@3.7.0(react@18.2.0): - resolution: {integrity: sha512-EcwGAXzSHjSqpFZha7xn3IUrhPiJLj+0yb1Ip0qPmhWz0VVw2DwrkY7q/jfaKroVvQhTo2TbfGhcsAQrt0fRqg==} + /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) + '@babel/runtime': 7.23.8 + '@types/react': 18.2.48 react: 18.2.0 - dev: false + dev: true - /@react-types/searchfield@3.5.2(react@18.2.0): - resolution: {integrity: sha512-JAK2/Kg4Dr393FYfbRw0TlXKnJPX77sq1x/ZBxtO6p64+MuuIYKqw0i9PwDlo1PViw2QI5u8GFhKA2TgemY9uA==} + /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - '@react-types/textfield': 3.9.0(react@18.2.0) + '@babel/runtime': 7.23.8 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 react: 18.2.0 - dev: false + dev: true - /@react-types/select@3.9.1(react@18.2.0): - resolution: {integrity: sha512-EpKSxrnh8HdZvOF9dHQkjivAcdIp1K81FaxmvosH8Lygqh0iYXxAdZGtKLMyBoPI8YFhA+rotIzTcOqgCCnqWA==} + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) + '@babel/runtime': 7.23.8 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 react: 18.2.0 - dev: false + dev: true - /@react-types/shared@3.22.0(react@18.2.0): - resolution: {integrity: sha512-yVOekZWbtSmmiThGEIARbBpnmUIuePFlLyctjvCbgJgGhz8JnEJOipLQ/a4anaWfzAgzSceQP8j/K+VOOePleA==} + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true dependencies: + '@babel/runtime': 7.23.8 + '@types/react': 18.2.48 react: 18.2.0 - dev: false + dev: true - /@react-types/slider@3.7.0(react@18.2.0): - resolution: {integrity: sha512-uyQXUVFfqc9SPUW0LZLMan2n232F/OflRafiHXz9viLFa9tVOupVa7GhASRAoHojwkjoJ1LjFlPih7g5dOZ0/Q==} + /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) + '@babel/runtime': 7.23.8 + '@types/react': 18.2.48 react: 18.2.0 - dev: false + dev: true - /@react-types/switch@3.5.0(react@18.2.0): - resolution: {integrity: sha512-/wNmUGjk69bP6t5k2QkAdrNN5Eb9Rz4dOyp0pCPmoeE+5haW6sV5NmtkvWX1NSc4DQz1xL/a5b+A0vxPCP22Jw==} + /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) + '@babel/runtime': 7.23.8 + '@radix-ui/rect': 1.0.1 + '@types/react': 18.2.48 react: 18.2.0 - dev: false + dev: true - /@react-types/table@3.9.2(react@18.2.0): - resolution: {integrity: sha512-brw5JUANOzBa2rYNpN8AIl9nDZ9RwRZC6G/wTM/JhtirjC1S42oCtf8Ap5rWJBdmMG/5KOfcGNcAl/huyqb3gg==} + /@radix-ui/react-use-size@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true dependencies: - '@react-types/grid': 3.2.3(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) + '@babel/runtime': 7.23.8 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 react: 18.2.0 - dev: false + dev: true - /@react-types/tabs@3.3.4(react@18.2.0): - resolution: {integrity: sha512-4mCTtFrwMRypyGTZCvNYVT9CkknexO/UYvqwDm2jMYb8JgjRvxnomu776Yh7uyiYKWyql2upm20jqasEOm620w==} + /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) + '@babel/runtime': 7.23.8 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 react: 18.2.0 - dev: false + react-dom: 18.2.0(react@18.2.0) + dev: true - /@react-types/textfield@3.9.0(react@18.2.0): - resolution: {integrity: sha512-D/DiwzsfkwlAg3uv8hoIfwju+zhB/hWDEdTvxQbPkntDr0kmN/QfI17NMSzbOBCInC4ABX87ViXLGxr940ykGA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + /@radix-ui/rect@1.0.1: + resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} dependencies: - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false + '@babel/runtime': 7.23.8 + dev: true - /@react-types/tooltip@3.4.6(react@18.2.0): - resolution: {integrity: sha512-RaZewdER7ZcsNL99RhVHs8kSLyzIBkwc0W6eFZrxST2MD9J5GzkVWRhIiqtFOd5U1aYnxdJ6woq72Ef+le6Vfw==} + /@react-icons/all-files@4.1.0(react@18.2.0): + resolution: {integrity: sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react: '*' dependencies: - '@react-types/overlays': 3.8.4(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 dev: false @@ -9173,19 +7895,6 @@ packages: /@swc/counter@0.1.2: resolution: {integrity: sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==} - /@swc/helpers@0.4.14: - resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} - dependencies: - tslib: 2.6.2 - dev: false - - /@swc/helpers@0.4.36: - resolution: {integrity: sha512-5lxnyLEYFskErRPenYItLRSge5DjrJngYKdVjRSrWfza9G6KkgHEXi0vUZiyUeMU5JfXH1YnvXZzSp8ul88o2Q==} - dependencies: - legacy-swc-helpers: /@swc/helpers@0.4.14 - tslib: 2.6.2 - dev: false - /@swc/helpers@0.5.2: resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} dependencies: @@ -9938,6 +8647,10 @@ packages: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true + /@vanilla-extract/css-utils@0.1.3: + resolution: {integrity: sha512-PZAcHROlgtCUGI2y0JntdNwvPwCNyeVnkQu6KTYKdmxBbK3w72XJUmLFYapfaFfgami4I9CTLnrJTPdtmS3gpw==} + dev: false + /@vanilla-extract/css@1.14.0: resolution: {integrity: sha512-rYfm7JciWZ8PFzBM/HDiE2GLnKI3xJ6/vdmVJ5BSgcCZ5CxRlM9Cjqclni9lGzF3eMOijnUhCd/KV8TOzyzbMA==} dependencies: @@ -9964,8 +8677,8 @@ packages: resolution: {integrity: sha512-17kVyLq3ePTKOkveHxXuIJZtGYs+cSoev7BlP+Lf4916qfDhk/HBjvlYDe8egrea7LNPHKwSZJK/bzZC+Q6AwQ==} dev: false - /@vanilla-extract/recipes@0.5.1(@vanilla-extract/css@1.14.0): - resolution: {integrity: sha512-7dCuBgPQQ/89siQ0w2lkfjgkmToPUUDzFlHf5DRmt9ykiiycfA52tmPJ2RI/mr7jXi7U/vEN2aGP9QJSXEpGlA==} + /@vanilla-extract/recipes@0.4.0(@vanilla-extract/css@1.14.0): + resolution: {integrity: sha512-gFgB7BofUYbtbxINHK6DhMv1JDFDXp/YI/Xm+cqKar+1I/2dfxPepeDxSexL6YB4ftfeaDw8Kn5zydMvHcGOEQ==} peerDependencies: '@vanilla-extract/css': ^1.0.0 dependencies: @@ -10436,6 +9149,28 @@ packages: tslib: 1.14.1 dev: true + /@zag-js/anatomy@0.15.0: + resolution: {integrity: sha512-+lmu/JVQ6Q5M9Tmbt1sXVkp3CtP10JYOo/PU2L6w6mXpwazT5FUpsuorrBrBM9rhWOnxI7CVvFy7r/rxReDWgg==} + dev: false + + /@zag-js/core@0.15.0: + resolution: {integrity: sha512-eH3yx9nv0hMyoR+hWtJVJpCagpU5s61rOMHfLkdjMPTWSVjQZdp3SGEm6BTUjBlNbQkTZhUbPpg/FEqx1iPfJw==} + dependencies: + '@zag-js/store': 0.15.0 + klona: 2.0.6 + dev: false + + /@zag-js/dom-event@0.15.0: + resolution: {integrity: sha512-5Sw2pNCcX2PqSiz4Ntm2PDu+YARQLtUrAf6PBBSUIqMZ0X9pp7DWTY3IfpdqY2ADsRLRMIe1LqzM+/c0u3Gd1Q==} + dependencies: + '@zag-js/text-selection': 0.15.0 + '@zag-js/types': 0.15.0 + dev: false + + /@zag-js/dom-query@0.15.0: + resolution: {integrity: sha512-gxm7GefQ+ggJE+iN0/kHgbM90DPd4RZYoQC6TQOWy3nxij69IuoSI6goMakJ33hUckszWm9z86Sqe1U1puzssQ==} + dev: false + /@zag-js/dom-query@0.16.0: resolution: {integrity: sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ==} @@ -10447,6 +9182,70 @@ packages: dependencies: '@zag-js/dom-query': 0.16.0 + /@zag-js/form-utils@0.15.0: + resolution: {integrity: sha512-3gFzyF8x48wK2Fabt6rxjMETmhSlwTtCjF10XFrKscL1LZASc3Abl7lJcpTEmVJ5kb5D+50Zw+jlHjHrvddH6g==} + dependencies: + '@zag-js/mutation-observer': 0.15.0 + dev: false + + /@zag-js/mutation-observer@0.15.0: + resolution: {integrity: sha512-7e2d1RYA0nuKOAJknbYBw6XfywF5eFC/4oel/nINHmS14JtjZnjMq/8z/kdrMMJnlQHou+wnaoskOLv+4Sv7pw==} + dev: false + + /@zag-js/number-input@0.15.0: + resolution: {integrity: sha512-WyIGLI4gUm9+53OPCoOmzyZaqT32ALdfZl1QjTVLuDXzckoBgqxaowR0mJU1gDkJ89mSI02p0B0Q89SOiokUfQ==} + dependencies: + '@zag-js/anatomy': 0.15.0 + '@zag-js/core': 0.15.0 + '@zag-js/dom-event': 0.15.0 + '@zag-js/dom-query': 0.15.0 + '@zag-js/form-utils': 0.15.0 + '@zag-js/mutation-observer': 0.15.0 + '@zag-js/number-utils': 0.15.0 + '@zag-js/types': 0.15.0 + '@zag-js/utils': 0.15.0 + dev: false + + /@zag-js/number-utils@0.15.0: + resolution: {integrity: sha512-ebDPCv4UNl5qAe+x55NSUK5gMLbhlqh8mVVq6EnPUqPfbglcjUgNzht78TZ3d+0rdfgC3F8SI3pWaZk9DY4O1Q==} + dev: false + + /@zag-js/react@0.15.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Uygdyq29Y7q5GPOYv1VC9Ya5tdFOs+jdCZk5h5BKzFy3vCSDaVuZ8WT+w7JgvUWh6aQUKjUMLG8lXxWWnJA0Jg==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + dependencies: + '@zag-js/core': 0.15.0 + '@zag-js/store': 0.15.0 + '@zag-js/types': 0.15.0 + proxy-compare: 2.5.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@zag-js/store@0.15.0: + resolution: {integrity: sha512-xq4WFrd+fqJE+Y0Os3FhN2/ru2zxvIvV8IT9y5Ev+3VRZw+L6Ut4tEjOONk+zr+UpkRx3jflPqlekjLHtowp0w==} + dependencies: + proxy-compare: 2.5.1 + dev: false + + /@zag-js/text-selection@0.15.0: + resolution: {integrity: sha512-5i/MkTTBOJN17YylGgvRC+dyO5l3pgz2a/z0xBiIpimYqP1W66P0N1Yq0/5VZubs9TG41jKyEKuulKfcpLwmYg==} + dependencies: + '@zag-js/dom-query': 0.15.0 + dev: false + + /@zag-js/types@0.15.0: + resolution: {integrity: sha512-rkAwZDl6e5p2iXF9HknP03TQ/G9jfOto0x2r2rds4wsPbfVJBNGk0Mo6Jl9GXcpNiyOCOO74SoO9VjZTmMqVvw==} + dependencies: + csstype: 3.1.2 + dev: false + + /@zag-js/utils@0.15.0: + resolution: {integrity: sha512-aNjydiheTKMoIo1wASk3XgN3mbcCiCk2zAiUyldU4JCw9xWevMk5aSszW2v3A0yms6z+qhRb77Z50fejG7OlSA==} + dev: false + /JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -11675,11 +10474,6 @@ packages: engines: {node: '>=6'} dev: false - /clsx@2.1.0: - resolution: {integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==} - engines: {node: '>=6'} - dev: false - /cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} @@ -12185,6 +10979,10 @@ packages: engines: {node: '>=4'} hasBin: true + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + dev: false + /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -14734,15 +13532,6 @@ packages: side-channel: 1.0.4 dev: true - /intl-messageformat@10.5.10: - resolution: {integrity: sha512-3yzwX6t/my9WRtNiqP05r+/UkpWxwstQiwaHAiuHmDRt7ykzWJ+nceOVjNLZYYWGiSltY+C+Likd8OIVkASepw==} - dependencies: - '@formatjs/ecma402-abstract': 1.18.2 - '@formatjs/fast-memoize': 2.2.0 - '@formatjs/icu-messageformat-parser': 2.7.5 - tslib: 2.6.2 - dev: false - /invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} dependencies: @@ -15885,7 +14674,6 @@ packages: /klona@2.0.6: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} - dev: true /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} @@ -17624,6 +16412,10 @@ packages: ipaddr.js: 1.9.1 dev: true + /proxy-compare@2.5.1: + resolution: {integrity: sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==} + dev: false + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -17827,53 +16619,6 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /react-aria@3.31.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-q4jRCVDKO6V2o4Sgir5S2obssw/YnMx6QOy10+p0dYqROHpSnMFNkONrKT1w/nA+Nx4ptfPqZbaNra1hR1bUWg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@internationalized/string': 3.2.0 - '@react-aria/breadcrumbs': 3.5.9(react@18.2.0) - '@react-aria/button': 3.9.1(react@18.2.0) - '@react-aria/calendar': 3.5.4(react-dom@18.2.0)(react@18.2.0) - '@react-aria/checkbox': 3.13.0(react@18.2.0) - '@react-aria/combobox': 3.8.2(react-dom@18.2.0)(react@18.2.0) - '@react-aria/datepicker': 3.9.1(react-dom@18.2.0)(react@18.2.0) - '@react-aria/dialog': 3.5.10(react-dom@18.2.0)(react@18.2.0) - '@react-aria/dnd': 3.5.1(react-dom@18.2.0)(react@18.2.0) - '@react-aria/focus': 3.16.0(react@18.2.0) - '@react-aria/gridlist': 3.7.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/i18n': 3.10.0(react@18.2.0) - '@react-aria/interactions': 3.20.1(react@18.2.0) - '@react-aria/label': 3.7.4(react@18.2.0) - '@react-aria/link': 3.6.3(react@18.2.0) - '@react-aria/listbox': 3.11.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/menu': 3.12.0(react-dom@18.2.0)(react@18.2.0) - '@react-aria/meter': 3.4.9(react@18.2.0) - '@react-aria/numberfield': 3.10.2(react-dom@18.2.0)(react@18.2.0) - '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) - '@react-aria/progress': 3.4.9(react@18.2.0) - '@react-aria/radio': 3.10.0(react@18.2.0) - '@react-aria/searchfield': 3.7.1(react@18.2.0) - '@react-aria/select': 3.14.1(react-dom@18.2.0)(react@18.2.0) - '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/separator': 3.3.9(react@18.2.0) - '@react-aria/slider': 3.7.4(react@18.2.0) - '@react-aria/ssr': 3.9.1(react@18.2.0) - '@react-aria/switch': 3.6.0(react@18.2.0) - '@react-aria/table': 3.13.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/tabs': 3.8.3(react-dom@18.2.0)(react@18.2.0) - '@react-aria/tag': 3.3.1(react-dom@18.2.0)(react@18.2.0) - '@react-aria/textfield': 3.14.1(react@18.2.0) - '@react-aria/tooltip': 3.7.0(react@18.2.0) - '@react-aria/utils': 3.23.0(react@18.2.0) - '@react-aria/visually-hidden': 3.8.8(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - /react-clientside-effect@1.2.6(react@18.2.0): resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==} peerDependencies: @@ -18123,37 +16868,6 @@ packages: - '@types/react' dev: false - /react-stately@3.29.1(react@18.2.0): - resolution: {integrity: sha512-hc4ZHy/ahvMwr6z7XMjYJ7EgzNVrXhzM4l2Qj17rdRhERo7/ovWmQencf9pF7K8kD5TraEHxPHLrYzGN4fxfUQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 - dependencies: - '@react-stately/calendar': 3.4.3(react@18.2.0) - '@react-stately/checkbox': 3.6.1(react@18.2.0) - '@react-stately/collections': 3.10.4(react@18.2.0) - '@react-stately/combobox': 3.8.1(react@18.2.0) - '@react-stately/data': 3.11.0(react@18.2.0) - '@react-stately/datepicker': 3.9.1(react@18.2.0) - '@react-stately/dnd': 3.2.7(react@18.2.0) - '@react-stately/form': 3.0.0(react@18.2.0) - '@react-stately/list': 3.10.2(react@18.2.0) - '@react-stately/menu': 3.6.0(react@18.2.0) - '@react-stately/numberfield': 3.8.0(react@18.2.0) - '@react-stately/overlays': 3.6.4(react@18.2.0) - '@react-stately/radio': 3.10.1(react@18.2.0) - '@react-stately/searchfield': 3.5.0(react@18.2.0) - '@react-stately/select': 3.6.1(react@18.2.0) - '@react-stately/selection': 3.14.2(react@18.2.0) - '@react-stately/slider': 3.5.0(react@18.2.0) - '@react-stately/table': 3.11.4(react@18.2.0) - '@react-stately/tabs': 3.6.3(react@18.2.0) - '@react-stately/toggle': 3.7.0(react@18.2.0) - '@react-stately/tooltip': 3.4.6(react@18.2.0) - '@react-stately/tree': 3.7.5(react@18.2.0) - '@react-types/shared': 3.22.0(react@18.2.0) - react: 18.2.0 - dev: false - /react-style-singleton@2.2.1(@types/react@18.2.48)(react@18.2.0): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} From 0e0fca3d767b4c1e3f87b1ce974961b8078f83d6 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Tue, 30 Jan 2024 16:16:08 +0700 Subject: [PATCH 040/531] feat: proposal validator votes hook --- src/lib/app-provider/env.ts | 1 + src/lib/services/proposal.ts | 32 +++++++++++++++++++++++++++++ src/lib/services/proposalService.ts | 14 +++++++++++++ src/lib/types/proposal.ts | 15 +++++++++++++- 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/lib/app-provider/env.ts b/src/lib/app-provider/env.ts index d74ca2b0c..37ca09c71 100644 --- a/src/lib/app-provider/env.ts +++ b/src/lib/app-provider/env.ts @@ -52,6 +52,7 @@ export enum CELATONE_QUERY_KEYS { FAUCET_INFO = "CELATONE_QUERY_FAUCET_INFO", // X/GOV PROPOSAL_DATA = "CELATONE_QUERY_PROPOSAL_DATA", + PROPOSAL_VALIDATOR_VOTES = "CELATONE_QUERY_PROPOSAL_VALIDATOR_VOTES", RELATED_PROPOSALS_BY_CONTRACT_ADDRESS = "CELATONE_QUERY_RELATED_PROPOSALS_BY_CONTRACT_ADDRESS", PROPOSALS_BY_MODULE_ID = "CELATONE_QUERY_PROPOSALS_BY_MODULE_ID", PROPOSALS_COUNT_BY_MODULE_ID = "CELATONE_QUERY_PROPOSALS_COUNT_BY_MODULE_ID", diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 74f65099a..43c95ea3f 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -8,6 +8,7 @@ import { zProposalStatus, zProposalType, zUtcDate, + zValidator, } from "lib/types"; import type { AccessConfigPermission, @@ -20,6 +21,7 @@ import type { ProposalData, ProposalStatus, ProposalType, + ProposalVote, } from "lib/types"; import { snakeToCamel } from "lib/utils"; @@ -199,3 +201,33 @@ export const getProposalData = async ( axios .get(`${endpoint}/${encodeURIComponent(id)}/info`) .then(({ data }) => zProposalDataResponse.parse(data)); + +const zProposalVotesResponseItem = z + .object({ + proposal_id: z.number().nonnegative(), + abstain: z.number().nonnegative(), + no: z.number().nonnegative(), + no_with_veto: z.number().nonnegative(), + yes: z.number().nonnegative(), + is_vote_weighted: z.boolean(), + validator: zValidator, + voter: zBechAddr.nullable(), + timestamp: zUtcDate.nullable(), + tx_hash: z.string().nullable(), + }) + .transform(snakeToCamel); + +const zProposalVotesResponse = z.object({ + items: z.array(zProposalVotesResponseItem), + total: z.number().nonnegative(), +}); + +export type ProposalVotesResponse = z.infer; + +export const getProposalValidatorVotes = async ( + endpoint: string, + id: number +): Promise => + axios + .get(`${endpoint}/${encodeURIComponent(id)}/validator-votes`) + .then(({ data }) => zProposalVotesResponse.parse(data)); diff --git a/src/lib/services/proposalService.ts b/src/lib/services/proposalService.ts index db01582ea..65b4523a1 100644 --- a/src/lib/services/proposalService.ts +++ b/src/lib/services/proposalService.ts @@ -39,6 +39,7 @@ import { useMovePoolInfos } from "./move"; import type { DepositParamsInternal, ProposalDataResponse, + ProposalVotesResponse, ProposalsResponse, RelatedProposalsResponse, UploadAccess, @@ -53,6 +54,7 @@ import { getProposals, getProposalTypes, getProposalData, + getProposalValidatorVotes, } from "./proposal"; export const useProposals = ( @@ -323,3 +325,15 @@ export const useUploadAccessParams = (): UseQueryResult => { { keepPreviousData: true, refetchOnWindowFocus: false } ); }; + +export const useProposalValidatorVotes = ( + id: number +): UseQueryResult => { + const endpoint = useBaseApiRoute("proposals"); + + return useQuery( + [CELATONE_QUERY_KEYS.PROPOSAL_VALIDATOR_VOTES, endpoint, id], + async () => getProposalValidatorVotes(endpoint, id), + { retry: 1, refetchOnWindowFocus: false } + ); +}; diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 8efbb6b56..2277495d1 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -1,7 +1,7 @@ import type { Coin } from "@cosmjs/amino"; import { z } from "zod"; -import type { BechAddr, Nullable, Option } from "lib/types"; +import type { BechAddr, Nullable, Option, Validator } from "lib/types"; export enum ProposalStatus { DEPOSIT_PERIOD = "DepositPeriod", @@ -90,3 +90,16 @@ export interface ProposalData extends Proposal { version: string; votingTime: Nullable; } + +export interface ProposalVote { + proposalId: number; + abstain: number; + no: number; + noWithVeto: number; + yes: number; + isVoteWeighted: boolean; + validator: Validator; + voter: Nullable; + timestamp: Nullable; + txHash: Nullable; +} From 5bd1bbf701517f4361b963bcf96dbfa90ed22dfb Mon Sep 17 00:00:00 2001 From: evilpeach Date: Tue, 30 Jan 2024 16:18:11 +0700 Subject: [PATCH 041/531] docs: add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18ea575f7..6e7114500 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#758](https://github.com/alleslabs/celatone-frontend/pull/758) api v1 - proposal validator votes - [#757](https://github.com/alleslabs/celatone-frontend/pull/757) api v1 - proposal data - [#731](https://github.com/alleslabs/celatone-frontend/pull/731) Add proposal detail page structure - [#749](https://github.com/alleslabs/celatone-frontend/pull/749) Add multi-type proposals From fa37d6da812ca132b5e8ebcd6b599422b84a30df Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Wed, 31 Jan 2024 14:29:36 +0700 Subject: [PATCH 042/531] fix(components): add proposal description --- CHANGELOG.md | 1 + package.json | 3 + pnpm-lock.yaml | 780 +++++++++++++++++- src/lib/components/Markdown.tsx | 153 ++++ .../__stories__/Markdown.stories.ts | 139 ++++ .../components/ProposalOverview.tsx | 37 +- src/lib/pages/proposal-details/index.tsx | 2 +- 7 files changed, 1092 insertions(+), 23 deletions(-) create mode 100644 src/lib/components/Markdown.tsx create mode 100644 src/lib/components/__stories__/Markdown.stories.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f77e332a6..18b767835 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#759](https://github.com/alleslabs/celatone-frontend/pull/759) Add proposal description - [#745](https://github.com/alleslabs/celatone-frontend/pull/745) Add proposal top - [#757](https://github.com/alleslabs/celatone-frontend/pull/757) api v1 - proposal data - [#731](https://github.com/alleslabs/celatone-frontend/pull/731) Add proposal detail page structure diff --git a/package.json b/package.json index 55007f6ff..8ffec61ac 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "camelcase": "^7.0.0", "chain-registry": "1.20.0", "chakra-react-select": "^4.7.0", + "chakra-ui-markdown-renderer": "^4.1.0", "cosmjs-types": "^0.9.0", "dayjs": "^1.11.6", "file-saver": "^2.0.5", @@ -121,7 +122,9 @@ "react-hook-form": "^7.39.7", "react-icons": "^4.6.0", "react-linkify": "^1.0.0-alpha", + "react-markdown": "^9.0.1", "react-responsive": "^9.0.0", + "remark-gfm": "^4.0.0", "rxjs": "^7.5.7", "snake-case": "^3.0.4", "use-clamp-text": "^1.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd936c53c..b5d263d80 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -165,6 +165,9 @@ dependencies: chakra-react-select: specifier: ^4.7.0 version: 4.7.6(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/layout@2.3.1)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@emotion/react@11.11.3)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + chakra-ui-markdown-renderer: + specifier: ^4.1.0 + version: 4.1.0(@chakra-ui/react@2.8.2)(react-markdown@9.0.1) cosmjs-types: specifier: ^0.9.0 version: 0.9.0 @@ -246,9 +249,15 @@ dependencies: react-linkify: specifier: ^1.0.0-alpha version: 1.0.0-alpha + react-markdown: + specifier: ^9.0.1 + version: 9.0.1(@types/react@18.2.48)(react@18.2.0) react-responsive: specifier: ^9.0.0 version: 9.0.2(react@18.2.0) + remark-gfm: + specifier: ^4.0.0 + version: 4.0.0 rxjs: specifier: ^7.5.7 version: 7.8.1 @@ -8154,6 +8163,12 @@ packages: '@types/node': 20.11.5 dev: true + /@types/debug@4.1.12: + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + dependencies: + '@types/ms': 0.7.34 + dev: false + /@types/detect-port@1.3.5: resolution: {integrity: sha512-Rf3/lB9WkDfIL9eEKaSYKc+1L/rNVYBjThk22JTqQw0YozXarX8YljFAz+HCoC6h4B4KwCMsBPZHaFezwT4BNA==} dev: true @@ -8190,6 +8205,12 @@ packages: '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 + /@types/estree-jsx@1.0.3: + resolution: {integrity: sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==} + dependencies: + '@types/estree': 1.0.5 + dev: false + /@types/estree@0.0.51: resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} dev: true @@ -8229,6 +8250,12 @@ packages: '@types/node': 20.11.5 dev: true + /@types/hast@3.0.3: + resolution: {integrity: sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==} + dependencies: + '@types/unist': 2.0.10 + dev: false + /@types/html-minifier-terser@6.1.0: resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} dev: true @@ -8287,6 +8314,12 @@ packages: resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} dev: false + /@types/mdast@4.0.3: + resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==} + dependencies: + '@types/unist': 3.0.2 + dev: false + /@types/mdx@2.0.10: resolution: {integrity: sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg==} dev: true @@ -8307,6 +8340,10 @@ packages: resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} dev: true + /@types/ms@0.7.34: + resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + dev: false + /@types/node-fetch@2.6.11: resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} dependencies: @@ -8419,7 +8456,10 @@ packages: /@types/unist@2.0.10: resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} - dev: true + + /@types/unist@3.0.2: + resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} + dev: false /@types/uuid@9.0.7: resolution: {integrity: sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==} @@ -8645,7 +8685,6 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - dev: true /@vanilla-extract/css-utils@0.1.3: resolution: {integrity: sha512-PZAcHROlgtCUGI2y0JntdNwvPwCNyeVnkQu6KTYKdmxBbK3w72XJUmLFYapfaFfgami4I9CTLnrJTPdtmS3gpw==} @@ -9847,6 +9886,10 @@ packages: babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.7) dev: true + /bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + dev: false + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -10211,6 +10254,10 @@ packages: engines: {node: '>=4'} dev: true + /ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + dev: false + /chai@4.4.1: resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} engines: {node: '>=4'} @@ -10260,6 +10307,17 @@ packages: - '@types/react' dev: false + /chakra-ui-markdown-renderer@4.1.0(@chakra-ui/react@2.8.2)(react-markdown@9.0.1): + resolution: {integrity: sha512-kcRy5d2aSAEgLVvAQ3p/pMdOLY1sR6d/hOU2pl6zNXHuTzrUhjhGxEBDskyU0ffpIilsR/f1/NIAxMCXhSoREQ==} + peerDependencies: + '@chakra-ui/react': ^1.6.1 || ^2 + react-markdown: ^7 || ^8 + dependencies: + '@chakra-ui/react': 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0) + deepmerge: 4.3.1 + react-markdown: 9.0.1(@types/react@18.2.48)(react@18.2.0) + dev: false + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -10324,6 +10382,22 @@ packages: engines: {node: '>=10'} dev: true + /character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + dev: false + + /character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + dev: false + + /character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + dev: false + + /character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + dev: false + /chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} @@ -10532,6 +10606,10 @@ packages: dependencies: delayed-stream: 1.0.0 + /comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + dev: false + /commander@11.0.0: resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==} engines: {node: '>=16'} @@ -11074,6 +11152,12 @@ packages: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} dev: false + /decode-named-character-reference@1.0.2: + resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + dependencies: + character-entities: 2.0.2 + dev: false + /decode-uri-component@0.2.2: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} @@ -11220,7 +11304,6 @@ packages: /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - dev: true /des.js@1.1.0: resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} @@ -11286,6 +11369,12 @@ packages: - supports-color dev: true + /devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dependencies: + dequal: 2.0.3 + dev: false + /diff-match-patch@1.0.5: resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} dev: false @@ -11690,6 +11779,11 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + /escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + dev: false + /escodegen@2.1.0: resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} engines: {node: '>=6.0'} @@ -12177,6 +12271,10 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + /estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + dev: false + /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} dev: false @@ -12360,7 +12458,6 @@ packages: /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - dev: true /external-editor@3.1.0: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} @@ -13212,6 +13309,34 @@ packages: dependencies: function-bind: 1.1.2 + /hast-util-to-jsx-runtime@2.3.0: + resolution: {integrity: sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==} + dependencies: + '@types/estree': 1.0.5 + '@types/hast': 3.0.3 + '@types/unist': 3.0.2 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.0 + mdast-util-mdx-jsx: 3.0.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 6.4.1 + space-separated-tokens: 2.0.2 + style-to-object: 1.0.5 + unist-util-position: 5.0.0 + vfile-message: 4.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + dependencies: + '@types/hast': 3.0.3 + dev: false + /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -13284,6 +13409,10 @@ packages: engines: {node: '>=8'} dev: true + /html-url-attributes@3.0.0: + resolution: {integrity: sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow==} + dev: false + /html-webpack-plugin@5.6.0(webpack@5.89.0): resolution: {integrity: sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==} engines: {node: '>=10.13.0'} @@ -13482,6 +13611,10 @@ packages: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: true + /inline-style-parser@0.2.2: + resolution: {integrity: sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ==} + dev: false + /inquirer@8.2.5: resolution: {integrity: sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==} engines: {node: '>=12.0.0'} @@ -13577,6 +13710,17 @@ packages: engines: {node: '>=8'} dev: true + /is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + dev: false + + /is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + dev: false + /is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -13642,6 +13786,10 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + dev: false + /is-deflate@1.0.0: resolution: {integrity: sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==} dev: true @@ -13703,6 +13851,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + dev: false + /is-inside-container@1.0.0: resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} engines: {node: '>=14.16'} @@ -13768,6 +13920,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + dev: false + /is-plain-object@2.0.4: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} @@ -14979,6 +15136,10 @@ packages: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} dev: false + /longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + dev: false + /longest@2.0.1: resolution: {integrity: sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==} engines: {node: '>=0.10.0'} @@ -15092,6 +15253,10 @@ packages: resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} dev: true + /markdown-table@3.0.3: + resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + dev: false + /markdown-to-jsx@7.4.0(react@18.2.0): resolution: {integrity: sha512-zilc+MIkVVXPyTb4iIUTIz9yyqfcWjszGXnwF9K/aiBWcHXFcmdEMTkG01/oQhwSCH7SY1BnG6+ev5BzWmbPrg==} engines: {node: '>= 10'} @@ -15127,10 +15292,193 @@ packages: unist-util-visit: 2.0.3 dev: true + /mdast-util-find-and-replace@3.0.1: + resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==} + dependencies: + '@types/mdast': 4.0.3 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + dev: false + + /mdast-util-from-markdown@2.0.0: + resolution: {integrity: sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==} + dependencies: + '@types/mdast': 4.0.3 + '@types/unist': 3.0.2 + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.0 + micromark-util-decode-numeric-character-reference: 2.0.1 + micromark-util-decode-string: 2.0.0 + micromark-util-normalize-identifier: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm-autolink-literal@2.0.0: + resolution: {integrity: sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==} + dependencies: + '@types/mdast': 4.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.1 + micromark-util-character: 2.1.0 + dev: false + + /mdast-util-gfm-footnote@2.0.0: + resolution: {integrity: sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==} + dependencies: + '@types/mdast': 4.0.3 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + micromark-util-normalize-identifier: 2.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + dependencies: + '@types/mdast': 4.0.3 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + dependencies: + '@types/mdast': 4.0.3 + devlop: 1.1.0 + markdown-table: 3.0.3 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + dependencies: + '@types/mdast': 4.0.3 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm@3.0.0: + resolution: {integrity: sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==} + dependencies: + mdast-util-from-markdown: 2.0.0 + mdast-util-gfm-autolink-literal: 2.0.0 + mdast-util-gfm-footnote: 2.0.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-mdx-expression@2.0.0: + resolution: {integrity: sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==} + dependencies: + '@types/estree-jsx': 1.0.3 + '@types/hast': 3.0.3 + '@types/mdast': 4.0.3 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-mdx-jsx@3.0.0: + resolution: {integrity: sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA==} + dependencies: + '@types/estree-jsx': 1.0.3 + '@types/hast': 3.0.3 + '@types/mdast': 4.0.3 + '@types/unist': 3.0.2 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + parse-entities: 4.0.1 + stringify-entities: 4.0.3 + unist-util-remove-position: 5.0.0 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + dependencies: + '@types/estree-jsx': 1.0.3 + '@types/hast': 3.0.3 + '@types/mdast': 4.0.3 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-phrasing@4.0.0: + resolution: {integrity: sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==} + dependencies: + '@types/mdast': 4.0.3 + unist-util-is: 6.0.0 + dev: false + + /mdast-util-to-hast@13.1.0: + resolution: {integrity: sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==} + dependencies: + '@types/hast': 3.0.3 + '@types/mdast': 4.0.3 + '@ungap/structured-clone': 1.2.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.0 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.1 + dev: false + + /mdast-util-to-markdown@2.1.0: + resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==} + dependencies: + '@types/mdast': 4.0.3 + '@types/unist': 3.0.2 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.0.0 + mdast-util-to-string: 4.0.0 + micromark-util-decode-string: 2.0.0 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + dev: false + /mdast-util-to-string@1.1.0: resolution: {integrity: sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==} dev: true + /mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + dependencies: + '@types/mdast': 4.0.3 + dev: false + /media-query-parser@2.0.2: resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} dependencies: @@ -15208,6 +15556,253 @@ packages: engines: {node: '>= 0.6'} dev: true + /micromark-core-commonmark@2.0.0: + resolution: {integrity: sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==} + dependencies: + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + micromark-factory-destination: 2.0.0 + micromark-factory-label: 2.0.0 + micromark-factory-space: 2.0.0 + micromark-factory-title: 2.0.0 + micromark-factory-whitespace: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-chunked: 2.0.0 + micromark-util-classify-character: 2.0.0 + micromark-util-html-tag-name: 2.0.0 + micromark-util-normalize-identifier: 2.0.0 + micromark-util-resolve-all: 2.0.0 + micromark-util-subtokenize: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-autolink-literal@2.0.0: + resolution: {integrity: sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==} + dependencies: + micromark-util-character: 2.1.0 + micromark-util-sanitize-uri: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-footnote@2.0.0: + resolution: {integrity: sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==} + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.0 + micromark-factory-space: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-normalize-identifier: 2.0.0 + micromark-util-sanitize-uri: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==} + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.0 + micromark-util-classify-character: 2.0.0 + micromark-util-resolve-all: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-table@2.0.0: + resolution: {integrity: sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==} + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + dependencies: + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-task-list-item@2.0.1: + resolution: {integrity: sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==} + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + dependencies: + micromark-extension-gfm-autolink-literal: 2.0.0 + micromark-extension-gfm-footnote: 2.0.0 + micromark-extension-gfm-strikethrough: 2.0.0 + micromark-extension-gfm-table: 2.0.0 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.0.1 + micromark-util-combine-extensions: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-factory-destination@2.0.0: + resolution: {integrity: sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==} + dependencies: + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-factory-label@2.0.0: + resolution: {integrity: sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==} + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-factory-space@2.0.0: + resolution: {integrity: sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==} + dependencies: + micromark-util-character: 2.1.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-factory-title@2.0.0: + resolution: {integrity: sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==} + dependencies: + micromark-factory-space: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-factory-whitespace@2.0.0: + resolution: {integrity: sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==} + dependencies: + micromark-factory-space: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-util-character@2.1.0: + resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==} + dependencies: + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-util-chunked@2.0.0: + resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==} + dependencies: + micromark-util-symbol: 2.0.0 + dev: false + + /micromark-util-classify-character@2.0.0: + resolution: {integrity: sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==} + dependencies: + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-util-combine-extensions@2.0.0: + resolution: {integrity: sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==} + dependencies: + micromark-util-chunked: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-util-decode-numeric-character-reference@2.0.1: + resolution: {integrity: sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==} + dependencies: + micromark-util-symbol: 2.0.0 + dev: false + + /micromark-util-decode-string@2.0.0: + resolution: {integrity: sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==} + dependencies: + decode-named-character-reference: 1.0.2 + micromark-util-character: 2.1.0 + micromark-util-decode-numeric-character-reference: 2.0.1 + micromark-util-symbol: 2.0.0 + dev: false + + /micromark-util-encode@2.0.0: + resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==} + dev: false + + /micromark-util-html-tag-name@2.0.0: + resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==} + dev: false + + /micromark-util-normalize-identifier@2.0.0: + resolution: {integrity: sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==} + dependencies: + micromark-util-symbol: 2.0.0 + dev: false + + /micromark-util-resolve-all@2.0.0: + resolution: {integrity: sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==} + dependencies: + micromark-util-types: 2.0.0 + dev: false + + /micromark-util-sanitize-uri@2.0.0: + resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==} + dependencies: + micromark-util-character: 2.1.0 + micromark-util-encode: 2.0.0 + micromark-util-symbol: 2.0.0 + dev: false + + /micromark-util-subtokenize@2.0.0: + resolution: {integrity: sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==} + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-util-symbol@2.0.0: + resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==} + dev: false + + /micromark-util-types@2.0.0: + resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==} + dev: false + + /micromark@4.0.0: + resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==} + dependencies: + '@types/debug': 4.1.12 + debug: 4.3.4 + decode-named-character-reference: 1.0.2 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.0 + micromark-factory-space: 2.0.0 + micromark-util-character: 2.1.0 + micromark-util-chunked: 2.0.0 + micromark-util-combine-extensions: 2.0.0 + micromark-util-decode-numeric-character-reference: 2.0.1 + micromark-util-encode: 2.0.0 + micromark-util-normalize-identifier: 2.0.0 + micromark-util-resolve-all: 2.0.0 + micromark-util-sanitize-uri: 2.0.0 + micromark-util-subtokenize: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + transitivePeerDependencies: + - supports-color + dev: false + /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} @@ -15950,6 +16545,19 @@ packages: pbkdf2: 3.1.2 safe-buffer: 5.2.1 + /parse-entities@4.0.1: + resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==} + dependencies: + '@types/unist': 2.0.10 + character-entities: 2.0.2 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.0.2 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + dev: false + /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -16365,6 +16973,10 @@ packages: object-assign: 4.1.1 react-is: 16.13.1 + /property-information@6.4.1: + resolution: {integrity: sha512-OHYtXfu5aI2sS2LWFSN5rgJjrQ4pCy8i1jubJLe2QvMF8JJ++HXTUIVWFLfXJoaOfvYYjk2SN8J2wFUWIGXT4w==} + dev: false + /protobufjs@6.11.4: resolution: {integrity: sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==} hasBin: true @@ -16756,6 +17368,28 @@ packages: tlds: 1.248.0 dev: false + /react-markdown@9.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + dependencies: + '@types/hast': 3.0.3 + '@types/react': 18.2.48 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.0 + html-url-attributes: 3.0.0 + mdast-util-to-hast: 13.1.0 + react: 18.2.0 + remark-parse: 11.0.0 + remark-rehype: 11.1.0 + unified: 11.0.4 + unist-util-visit: 5.0.0 + vfile: 6.0.1 + transitivePeerDependencies: + - supports-color + dev: false + /react-refresh@0.14.0: resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} engines: {node: '>=0.10.0'} @@ -17091,6 +17725,40 @@ packages: unist-util-visit: 2.0.3 dev: true + /remark-gfm@4.0.0: + resolution: {integrity: sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==} + dependencies: + '@types/mdast': 4.0.3 + mdast-util-gfm: 3.0.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.4 + transitivePeerDependencies: + - supports-color + dev: false + + /remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + dependencies: + '@types/mdast': 4.0.3 + mdast-util-from-markdown: 2.0.0 + micromark-util-types: 2.0.0 + unified: 11.0.4 + transitivePeerDependencies: + - supports-color + dev: false + + /remark-rehype@11.1.0: + resolution: {integrity: sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==} + dependencies: + '@types/hast': 3.0.3 + '@types/mdast': 4.0.3 + mdast-util-to-hast: 13.1.0 + unified: 11.0.4 + vfile: 6.0.1 + dev: false + /remark-slug@6.1.0: resolution: {integrity: sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ==} dependencies: @@ -17099,6 +17767,14 @@ packages: unist-util-visit: 2.0.3 dev: true + /remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + dependencies: + '@types/mdast': 4.0.3 + mdast-util-to-markdown: 2.1.0 + unified: 11.0.4 + dev: false + /remedial@1.0.8: resolution: {integrity: sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg==} dev: false @@ -17641,6 +18317,10 @@ packages: resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} dev: true + /space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + dev: false + /spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: @@ -17875,6 +18555,13 @@ packages: dependencies: safe-buffer: 5.2.1 + /stringify-entities@4.0.3: + resolution: {integrity: sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==} + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + dev: false + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -17940,6 +18627,12 @@ packages: webpack: 5.89.0(@swc/core@1.3.104)(esbuild@0.18.20) dev: true + /style-to-object@1.0.5: + resolution: {integrity: sha512-rDRwHtoDD3UMMrmZ6BzOW0naTjMsVZLIjsGleSKS/0Oz+cgCfAPRspaqJuE8rDzpKha/nEvnM0IF4seEAZUTKQ==} + dependencies: + inline-style-parser: 0.2.2 + dev: false + /styled-jsx@5.1.1(@babel/core@7.23.7)(react@18.2.0): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} @@ -18273,11 +18966,19 @@ packages: /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + /trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + dev: false + /trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} dev: true + /trough@2.1.0: + resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} + dev: false + /ts-api-utils@1.0.3(typescript@5.3.3): resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} engines: {node: '>=16.13.0'} @@ -18624,6 +19325,18 @@ packages: engines: {node: '>=4'} dev: true + /unified@11.0.4: + resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==} + dependencies: + '@types/unist': 3.0.2 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.1.0 + vfile: 6.0.1 + dev: false + /unique-string@2.0.0: resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} engines: {node: '>=8'} @@ -18635,6 +19348,31 @@ packages: resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} dev: true + /unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + dependencies: + '@types/unist': 3.0.2 + dev: false + + /unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + dependencies: + '@types/unist': 3.0.2 + dev: false + + /unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + dependencies: + '@types/unist': 3.0.2 + unist-util-visit: 5.0.0 + dev: false + + /unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + dependencies: + '@types/unist': 3.0.2 + dev: false + /unist-util-visit-parents@3.1.1: resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==} dependencies: @@ -18642,6 +19380,13 @@ packages: unist-util-is: 4.1.0 dev: true + /unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + dependencies: + '@types/unist': 3.0.2 + unist-util-is: 6.0.0 + dev: false + /unist-util-visit@2.0.3: resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==} dependencies: @@ -18650,6 +19395,14 @@ packages: unist-util-visit-parents: 3.1.1 dev: true + /unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + dependencies: + '@types/unist': 3.0.2 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + dev: false + /universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -18959,6 +19712,21 @@ packages: engines: {node: '>= 0.8'} dev: true + /vfile-message@4.0.2: + resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + dependencies: + '@types/unist': 3.0.2 + unist-util-stringify-position: 4.0.0 + dev: false + + /vfile@6.0.1: + resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==} + dependencies: + '@types/unist': 3.0.2 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.2 + dev: false + /vm-browserify@1.1.2: resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} dev: true @@ -19365,3 +20133,7 @@ packages: react: 18.2.0 use-sync-external-store: 1.2.0(react@18.2.0) dev: false + + /zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + dev: false diff --git a/src/lib/components/Markdown.tsx b/src/lib/components/Markdown.tsx new file mode 100644 index 000000000..b7d849187 --- /dev/null +++ b/src/lib/components/Markdown.tsx @@ -0,0 +1,153 @@ +import { Box, Heading, List, ListItem, Text } from "@chakra-ui/react"; +import ChakraUIRenderer from "chakra-ui-markdown-renderer"; +import type { PropsWithChildren } from "react"; +import ReactMarkdown from "react-markdown"; +import remarkGfm from "remark-gfm"; + +const defaultTheme = { + h1: (props: PropsWithChildren) => { + const { children } = props; + return ( + + {children} + + ); + }, + h2: (props: PropsWithChildren) => { + const { children } = props; + return ( + + {children} + + ); + }, + h3: (props: PropsWithChildren) => { + const { children } = props; + return ( + + {children} + + ); + }, + h4: (props: PropsWithChildren) => { + const { children } = props; + return ( + + {children} + + ); + }, + h5: (props: PropsWithChildren) => { + const { children } = props; + return ( + + {children} + + ); + }, + h6: (props: PropsWithChildren) => { + const { children } = props; + return ( + + {children} + + ); + }, + p: (props: PropsWithChildren) => { + const { children } = props; + return ( + + {children} + + ); + }, + blockquote: (props: PropsWithChildren) => { + const { children } = props; + return ( + p": { marginBottom: 0 } }} + > + {children} + + ); + }, + code: (props: PropsWithChildren) => { + const { children } = props; + return ( + p": { marginBottom: 0 } }} + > + {children} + + ); + }, + pre: (props: PropsWithChildren) => { + const { children } = props; + return ( + p": { marginBottom: 0 } }} + > + {children} + + ); + }, + li: (props: PropsWithChildren) => { + const { children } = props; + return ( + + {children} + + ); + }, + ul: (props: PropsWithChildren) => { + const { children } = props; + return ( + + {children} + + ); + }, + ol: (props: PropsWithChildren) => { + const { children } = props; + return ( + + {children} + + ); + }, +}; + +export const Markdown = ({ markdown }: { markdown: string }) => { + return ( + + {markdown} + + ); +}; diff --git a/src/lib/components/__stories__/Markdown.stories.ts b/src/lib/components/__stories__/Markdown.stories.ts new file mode 100644 index 000000000..823144de2 --- /dev/null +++ b/src/lib/components/__stories__/Markdown.stories.ts @@ -0,0 +1,139 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { Markdown } from "../Markdown"; + +const meta: Meta = { + component: Markdown, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], +}; + +export default meta; +type Story = StoryObj; + +const heading = `# This is an H1 Header +## This is an H2 Header +### This is an H3 Header +#### This is an H4 Header +##### This is an H5 Header +###### This is an H6 Header`; + +const paragraph = `This is the first line of the paragraph. +And this is the second line on the same paragraph, separated by a line break. + +This is a new paragraph.`; + +const emphasis = `## Emphasis + +*This text will be italic* +_This will also be italic_ + +**This text will be bold** +__This will also be bold__ + +_You **can** combine them_ +`; + +const link = `## Links + +[This is a link](http://www.celat.one)`; + +const blockquote = `> This is a blockquote.`; + +const inlineCode = "This is an inline `code`."; + +const codeBlock = `\`\`\`javascript +function fibonacci(n) { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); +} + +for (let i = 0; i <= 10; i++) { + console.log(\`Fibonacci of \${i} is \${fibonacci(i)}\`); +} +\`\`\``; + +const list = ` +## Lists + +### Unordered + +* Item 1 +* Item 2 + * Item 2a + * Item 2b + +### Ordered + +1. Item 1 +2. Item 2 +3. Item 3 +`; + +const table = `# Example Markdown with Table + +This is an example of a table in a Markdown document: + +| Header 1 | Header 2 | Header 3 | +|-------------|-------------|-------------| +| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 | +| Row 2 Col 1 | Row 2 Col 2 | Row 2 Col 3 | +| Row 3 Col 1 | Row 3 Col 2 | Row 3 Col 3 |`; + +export const Heading: Story = { + args: { + markdown: heading, + }, +}; + +export const Paragraph: Story = { + args: { + markdown: paragraph, + }, +}; + +export const Link: Story = { + args: { + markdown: link, + }, +}; + +export const Blockquote: Story = { + args: { + markdown: blockquote, + }, +}; + +export const InlineCode: Story = { + args: { + markdown: inlineCode, + }, +}; + +export const CodeBlock: Story = { + args: { + markdown: codeBlock, + }, +}; + +export const Emphasis: Story = { + args: { + markdown: emphasis, + }, +}; + +export const List: Story = { + args: { + markdown: list, + }, +}; + +export const Table: Story = { + args: { + markdown: table, + }, +}; diff --git a/src/lib/pages/proposal-details/components/ProposalOverview.tsx b/src/lib/pages/proposal-details/components/ProposalOverview.tsx index d30ffbbd3..3d5a51126 100644 --- a/src/lib/pages/proposal-details/components/ProposalOverview.tsx +++ b/src/lib/pages/proposal-details/components/ProposalOverview.tsx @@ -1,4 +1,7 @@ -import { Flex, Grid, GridItem, Heading, Text } from "@chakra-ui/react"; +import { Flex, Grid, GridItem, Heading } from "@chakra-ui/react"; + +import { Markdown } from "lib/components/Markdown"; +import type { ProposalData } from "lib/types"; const ProposalStatus = () => { return ( @@ -13,7 +16,11 @@ const ProposalStatus = () => { ); }; -export const ProposalOverview = () => { + +interface ProposalOverviewProps { + proposalData: ProposalData; +} +export const ProposalOverview = ({ proposalData }: ProposalOverviewProps) => { return ( { Proposal Description - - This is a proposal to give the address - osmo1raa4kyx5ypz75qqk3566c6slx2mw3qzsu6rymw permission to upload - CosmWasm contracts to Osmosis without seeking governance approval - for subsequent uploads. Deploying this contract will allow Skip to - leverage Osmosis swap hooks to build a service that simplifies - cross-chain transfers, swaps, and fee management. Skip will - provide this functionality via our free API, which enables - applications anywhere in Cosmos to seamlessly draw on Osmosis - liquidity. While this proposal gives authority for - osmo1raa4kyx5ypz75qqk3566c6slx2mw3qzsu6rymw to permissionlessly - upload CosmWasm contracts to Osmosis, governance only signals - approval for contracts relating to the function of Skip API - service. Details can be seen in the Commonwealth thread: - https://gov.osmosis.zone/discussion/11973-skip-api-contract-upload - + + + - + From 4c860dc0d915695c42d56662fd0eb8ebd59dad6d Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Wed, 31 Jan 2024 15:22:43 +0700 Subject: [PATCH 043/531] fix(components): add metadata --- CHANGELOG.md | 2 +- .../components/ProposalOverview.tsx | 84 ++++++++++++++++--- 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18b767835..22d747baa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features -- [#759](https://github.com/alleslabs/celatone-frontend/pull/759) Add proposal description +- [#759](https://github.com/alleslabs/celatone-frontend/pull/759) Add proposal description and metadata - [#745](https://github.com/alleslabs/celatone-frontend/pull/745) Add proposal top - [#757](https://github.com/alleslabs/celatone-frontend/pull/757) api v1 - proposal data - [#731](https://github.com/alleslabs/celatone-frontend/pull/731) Add proposal detail page structure diff --git a/src/lib/pages/proposal-details/components/ProposalOverview.tsx b/src/lib/pages/proposal-details/components/ProposalOverview.tsx index 3d5a51126..db190fcb7 100644 --- a/src/lib/pages/proposal-details/components/ProposalOverview.tsx +++ b/src/lib/pages/proposal-details/components/ProposalOverview.tsx @@ -1,4 +1,4 @@ -import { Flex, Grid, GridItem, Heading } from "@chakra-ui/react"; +import { Flex, Grid, GridItem, Heading, Text, Box } from "@chakra-ui/react"; import { Markdown } from "lib/components/Markdown"; import type { ProposalData } from "lib/types"; @@ -17,10 +17,56 @@ const ProposalStatus = () => { ); }; +const isUrl = (metadata: string): boolean => { + const urlRegex = + // eslint-disable-next-line no-useless-escape + /[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/; + return urlRegex.test(metadata); +}; interface ProposalOverviewProps { proposalData: ProposalData; } export const ProposalOverview = ({ proposalData }: ProposalOverviewProps) => { + const renderMetadata = () => { + if (proposalData.metadata.length === 0) { + return ( + + Not Provided + + ); + } + + if (isUrl(proposalData.metadata)) { + return ( + + + {proposalData.metadata} + + + ); + } + + return ( + + {proposalData.metadata} + + ); + }; + return ( { Proposal Description - + Not Provided + + ) : ( + + + + )} + + + + Metadata + + - - + {renderMetadata()} + Date: Wed, 31 Jan 2024 15:30:25 +0700 Subject: [PATCH 044/531] fix(components): fix created block link --- .../proposal-details/components/ProposalTop.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib/pages/proposal-details/components/ProposalTop.tsx b/src/lib/pages/proposal-details/components/ProposalTop.tsx index 8fed5274f..00737137e 100644 --- a/src/lib/pages/proposal-details/components/ProposalTop.tsx +++ b/src/lib/pages/proposal-details/components/ProposalTop.tsx @@ -2,8 +2,8 @@ import { Button, Flex, Heading, Text } from "@chakra-ui/react"; import { useBaseApiRoute, useMobile } from "lib/app-provider"; import { Breadcrumb } from "lib/components/Breadcrumb"; -import { CopyLink } from "lib/components/CopyLink"; import { DotSeparator } from "lib/components/DotSeparator"; +import { ExplorerLink } from "lib/components/ExplorerLink"; import { CustomIcon } from "lib/components/icon"; import { InvalidState } from "lib/components/state"; import type { ProposalData } from "lib/types"; @@ -107,7 +107,7 @@ export const ProposalTop = ({ id, proposalData }: ProposalTopProps) => { ))} ) : ( - + No Message )} @@ -123,10 +123,12 @@ export const ProposalTop = ({ id, proposalData }: ProposalTopProps) => { Created Height: - + > + {proposalData.createdHeight.toString()} + )} From b60087f72e98c5d1a10e9cd41d1627bace802ab4 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Wed, 31 Jan 2024 16:02:40 +0700 Subject: [PATCH 045/531] fix(components): fix message mobile wrap --- src/lib/pages/proposal-details/components/ProposalTop.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/pages/proposal-details/components/ProposalTop.tsx b/src/lib/pages/proposal-details/components/ProposalTop.tsx index 00737137e..feab39dba 100644 --- a/src/lib/pages/proposal-details/components/ProposalTop.tsx +++ b/src/lib/pages/proposal-details/components/ProposalTop.tsx @@ -68,7 +68,6 @@ export const ProposalTop = ({ id, proposalData }: ProposalTopProps) => { @@ -87,7 +86,8 @@ export const ProposalTop = ({ id, proposalData }: ProposalTopProps) => { { style={{ color: "var(--chakra-colors-accent-main)", marginLeft: "4px", + fontWeight: 600, }} > {" / "} From 552d95f1cf21bc74740f34845af51423e753f26d Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Wed, 31 Jan 2024 16:18:50 +0700 Subject: [PATCH 046/531] fix(components): fix markdown render line break --- src/lib/components/Markdown.tsx | 16 +++++++++------- .../components/ProposalOverview.tsx | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/lib/components/Markdown.tsx b/src/lib/components/Markdown.tsx index b7d849187..a1cbcbeb3 100644 --- a/src/lib/components/Markdown.tsx +++ b/src/lib/components/Markdown.tsx @@ -142,12 +142,14 @@ const defaultTheme = { export const Markdown = ({ markdown }: { markdown: string }) => { return ( - - {markdown} - +
+ + {markdown} + +
); }; diff --git a/src/lib/pages/proposal-details/components/ProposalOverview.tsx b/src/lib/pages/proposal-details/components/ProposalOverview.tsx index db190fcb7..e17f2c008 100644 --- a/src/lib/pages/proposal-details/components/ProposalOverview.tsx +++ b/src/lib/pages/proposal-details/components/ProposalOverview.tsx @@ -88,7 +88,7 @@ export const ProposalOverview = ({ proposalData }: ProposalOverviewProps) => { Date: Wed, 31 Jan 2024 16:32:38 +0700 Subject: [PATCH 047/531] fix(components): fix show copy on hover proposal info --- .../components/ProposalInfo.tsx | 18 ++++++++++++----- .../components/ProposalTop.tsx | 20 +++++++++---------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/lib/pages/proposal-details/components/ProposalInfo.tsx b/src/lib/pages/proposal-details/components/ProposalInfo.tsx index a162e9cd1..f046ddb72 100644 --- a/src/lib/pages/proposal-details/components/ProposalInfo.tsx +++ b/src/lib/pages/proposal-details/components/ProposalInfo.tsx @@ -10,11 +10,12 @@ import { formatUTC } from "lib/utils"; interface InfoItemProps { label: string; children: ReactNode; + minW?: number; } -const InfoItem = ({ label, children }: InfoItemProps) => { +const InfoItem = ({ label, children, minW = 40 }: InfoItemProps) => { return ( - + {children} @@ -48,6 +49,7 @@ const getProposalInfo = (data: ProposalStatusProps["data"]) => { ) : ( @@ -87,6 +89,7 @@ const getProposalInfo = (data: ProposalStatusProps["data"]) => { ) : ( @@ -129,16 +132,21 @@ export const ProposalInfo = ({ data }: ProposalStatusProps) => { {data.createdTxHash && ( - + )} {data.proposer && ( - - + + )} diff --git a/src/lib/pages/proposal-details/components/ProposalTop.tsx b/src/lib/pages/proposal-details/components/ProposalTop.tsx index feab39dba..f058fca41 100644 --- a/src/lib/pages/proposal-details/components/ProposalTop.tsx +++ b/src/lib/pages/proposal-details/components/ProposalTop.tsx @@ -66,7 +66,7 @@ export const ProposalTop = ({ id, proposalData }: ProposalTopProps) => { - {proposalData.title ? proposalData.title : "No title"} - + {
)}
- {!isMobile && ( + {proposalData.createdHeight && ( - <> + Created Height: {proposalData.createdHeight.toString()} - - + {!isMobile && } + )} {proposalData.createdTimestamp && ( - + {formatUTC(proposalData.createdTimestamp)} )} - )} +
+ + + } /> ); From d676dcf5d28ceabf0b77f71073682f5532b0113a Mon Sep 17 00:00:00 2001 From: evilpeach Date: Thu, 1 Feb 2024 15:54:02 +0700 Subject: [PATCH 053/531] chore: refactor --- .../components/ProposalInfo.tsx | 98 +++++++++---------- .../components/ProposalTop.tsx | 9 +- src/lib/pages/proposal-details/index.tsx | 3 +- 3 files changed, 52 insertions(+), 58 deletions(-) diff --git a/src/lib/pages/proposal-details/components/ProposalInfo.tsx b/src/lib/pages/proposal-details/components/ProposalInfo.tsx index f046ddb72..528406766 100644 --- a/src/lib/pages/proposal-details/components/ProposalInfo.tsx +++ b/src/lib/pages/proposal-details/components/ProposalInfo.tsx @@ -13,14 +13,12 @@ interface InfoItemProps { minW?: number; } -const InfoItem = ({ label, children, minW = 40 }: InfoItemProps) => { - return ( - - - {children} - - ); -}; +const InfoItem = ({ label, children, minW = 40 }: InfoItemProps) => ( + + + {children} + +); interface ProposalStatusProps { data: ProposalData; @@ -115,48 +113,46 @@ const getProposalInfo = (data: ProposalStatusProps["data"]) => { } }; -export const ProposalInfo = ({ data }: ProposalStatusProps) => { - return ( - - - - - - - - {data.createdTxHash && ( - - - - )} - {data.proposer && ( - - - - )} +export const ProposalInfo = ({ data }: ProposalStatusProps) => ( + + + + - - {getProposalInfo(data)} + + + {data.createdTxHash && ( + + + + )} + {data.proposer && ( + + + + )} - ); -}; + + {getProposalInfo(data)} + +); diff --git a/src/lib/pages/proposal-details/components/ProposalTop.tsx b/src/lib/pages/proposal-details/components/ProposalTop.tsx index cf95d4456..1c80733b4 100644 --- a/src/lib/pages/proposal-details/components/ProposalTop.tsx +++ b/src/lib/pages/proposal-details/components/ProposalTop.tsx @@ -11,15 +11,14 @@ import { formatUTC, openNewTab } from "lib/utils"; import { ProposalInfo } from "./ProposalInfo"; interface ProposalTopProps { - id: number; proposalData: ProposalData; } -export const ProposalTop = ({ id, proposalData }: ProposalTopProps) => { +export const ProposalTop = ({ proposalData }: ProposalTopProps) => { const isMobile = useMobile(); const endpoint = useBaseApiRoute("proposals"); const openApiPage = () => - openNewTab(`${endpoint}/${encodeURIComponent(id)}/info`); + openNewTab(`${endpoint}/${encodeURIComponent(proposalData.id)}/info`); return ( @@ -29,7 +28,7 @@ export const ProposalTop = ({ id, proposalData }: ProposalTopProps) => { text: "Proposals", href: "/proposals", }, - { text: `#${id.toString()}` }, + { text: `#${proposalData.id.toString()}` }, ]} /> { color="accent.main" display="inline" > - #{id} + #{proposalData.id} {" "} - {proposalData.title ? proposalData.title : "No title"} diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index ed8b05b2b..0f6954d89 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -61,10 +61,9 @@ const ProposalDetailsBody = ({ if (!data) return ; if (!data.info) return ; - const proposalData = data.info; return ( <> - + Date: Thu, 1 Feb 2024 16:24:24 +0700 Subject: [PATCH 054/531] fix(components): fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4299fa8bd..8c1eb9e80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,7 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Bug fixes -- [#671](https://github.com/alleslabs/celatone-frontend/pull/671) Fix copy button tooltip alignment +- [#761](https://github.com/alleslabs/celatone-frontend/pull/761) Fix copy button tooltip alignment - [#754](https://github.com/alleslabs/celatone-frontend/pull/754) Fix mobile guard incorrect behavior - [#751](https://github.com/alleslabs/celatone-frontend/pull/751) Fix fail txs should have no logs and remove stone-12-1 From 5775070f8343c76612cc2b3767c019f7f58fa8a3 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Thu, 1 Feb 2024 16:33:50 +0700 Subject: [PATCH 055/531] fix: refactor and add todo --- .../table/proposals/ProposalsTableMobileCard.tsx | 7 +++---- .../components/table/proposals/ProposalsTableRow.tsx | 11 +++++------ .../pages/proposal-details/components/ProposalTop.tsx | 1 + 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx b/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx index 6b1cb05be..46e6d7bcd 100644 --- a/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx +++ b/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx @@ -19,10 +19,6 @@ export interface ProposalsTableMobileCardProps { export const ProposalsTableMobileCard = ({ proposal, }: ProposalsTableMobileCardProps) => { - const isDepositOrVoting = - proposal.status === ProposalStatus.DEPOSIT_PERIOD || - proposal.status === ProposalStatus.VOTING_PERIOD; - const navigate = useInternalNavigate(); const onCardSelect = (proposalId: number) => @@ -31,6 +27,9 @@ export const ProposalsTableMobileCard = ({ query: { proposalId }, }); + const isDepositOrVoting = + proposal.status === ProposalStatus.DEPOSIT_PERIOD || + proposal.status === ProposalStatus.VOTING_PERIOD; return ( { const navigate = useInternalNavigate(); - // TODO - Revisit split columnsWidth - const columnsWidth = templateColumns?.toString().split(" "); - const isDepositOrVoting = - proposal.status === ProposalStatus.DEPOSIT_PERIOD || - proposal.status === ProposalStatus.VOTING_PERIOD; - const onRowSelect = (proposalId: number) => navigate({ pathname: "/proposals/[proposalId]", query: { proposalId }, }); + // TODO - Revisit split columnsWidth + const columnsWidth = templateColumns?.toString().split(" "); + const isDepositOrVoting = + proposal.status === ProposalStatus.DEPOSIT_PERIOD || + proposal.status === ProposalStatus.VOTING_PERIOD; return ( { const isMobile = useMobile(); + // TODO: use LCD and gov config version const endpoint = useBaseApiRoute("proposals"); const openApiPage = () => openNewTab(`${endpoint}/${encodeURIComponent(proposalData.id)}/info`); From 334f95497fe0a9623d09c0bd4e00ef6eb2f2fd2f Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Thu, 1 Feb 2024 18:03:39 +0700 Subject: [PATCH 056/531] fix(components): fix copy template --- src/lib/components/copy/Copier.tsx | 28 +++++----- src/lib/components/copy/CopyButton.tsx | 54 +++++++++---------- src/lib/components/copy/CopyTemplate.tsx | 3 +- src/lib/components/token/UnsupportedToken.tsx | 15 ++++-- 4 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/lib/components/copy/Copier.tsx b/src/lib/components/copy/Copier.tsx index 59c2e9b6b..5f62d6023 100644 --- a/src/lib/components/copy/Copier.tsx +++ b/src/lib/components/copy/Copier.tsx @@ -1,4 +1,4 @@ -import { Flex, type IconProps, type LayoutProps } from "@chakra-ui/react"; +import type { IconProps, LayoutProps } from "@chakra-ui/react"; import { CustomIcon } from "../icon"; import { trackUseCopier } from "lib/amplitude"; @@ -26,20 +26,18 @@ export const Copier = ({ value={value} copyLabel={copyLabel} triggerElement={ - - trackUseCopier(type, amptrackSection)} - name="copy" - boxSize={3} - color="gray.600" - /> - + trackUseCopier(type, amptrackSection)} + name="copy" + boxSize={3} + color="gray.600" + /> } /> ); diff --git a/src/lib/components/copy/CopyButton.tsx b/src/lib/components/copy/CopyButton.tsx index d61b8f90b..c0f7b8863 100644 --- a/src/lib/components/copy/CopyButton.tsx +++ b/src/lib/components/copy/CopyButton.tsx @@ -1,4 +1,4 @@ -import { Button, Flex } from "@chakra-ui/react"; +import { Button } from "@chakra-ui/react"; import type { BoxProps, ButtonProps } from "@chakra-ui/react"; import { CustomIcon } from "../icon"; @@ -42,33 +42,31 @@ export const CopyButton = ({ ml={ml} w={w} triggerElement={ - - - + } /> ); diff --git a/src/lib/components/copy/CopyTemplate.tsx b/src/lib/components/copy/CopyTemplate.tsx index e353c53e4..a81230043 100644 --- a/src/lib/components/copy/CopyTemplate.tsx +++ b/src/lib/components/copy/CopyTemplate.tsx @@ -27,8 +27,7 @@ export const CopyTemplate = ({ return ( { onCopy(); e.stopPropagation(); diff --git a/src/lib/components/token/UnsupportedToken.tsx b/src/lib/components/token/UnsupportedToken.tsx index 8c1c694b8..a18ebf11a 100644 --- a/src/lib/components/token/UnsupportedToken.tsx +++ b/src/lib/components/token/UnsupportedToken.tsx @@ -85,15 +85,22 @@ export const UnsupportedToken = ({ token }: { token: TokenWithValue }) => { amptrackSection="unsupported_token_copy" /> + + + + {formatUTokenWithPrecision(token.amount, token.precision ?? 0, false)} + {!isMobile && ( - + {`${tokenType} Token`} )} - - {formatUTokenWithPrecision(token.amount, token.precision ?? 0, false)} - ); }; From f5f7324a0ad34d90aa3f264df2392ca13bd5f6de Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Thu, 1 Feb 2024 18:34:47 +0700 Subject: [PATCH 057/531] feat: api v1 proposal votes info --- CHANGELOG.md | 1 + src/lib/app-provider/env.ts | 1 + src/lib/services/proposal.ts | 29 +++++++++++++++++++++- src/lib/services/proposalService.ts | 38 ++++++++++++++++++----------- 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee1c30127..14810a4ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#762](https://github.com/alleslabs/celatone-frontend/pull/762) api v1 - proposal validator votes info - [#745](https://github.com/alleslabs/celatone-frontend/pull/745) Add proposal top - [#758](https://github.com/alleslabs/celatone-frontend/pull/758) api v1 - proposal validator votes - [#757](https://github.com/alleslabs/celatone-frontend/pull/757) api v1 - proposal data diff --git a/src/lib/app-provider/env.ts b/src/lib/app-provider/env.ts index 37ca09c71..d4ac54653 100644 --- a/src/lib/app-provider/env.ts +++ b/src/lib/app-provider/env.ts @@ -52,6 +52,7 @@ export enum CELATONE_QUERY_KEYS { FAUCET_INFO = "CELATONE_QUERY_FAUCET_INFO", // X/GOV PROPOSAL_DATA = "CELATONE_QUERY_PROPOSAL_DATA", + PROPOSAL_VALIDATOR_VOTES_INFO = "CELATONE_QUERY_PROPOSAL_VALIDATOR_VOTES_INFO", PROPOSAL_VALIDATOR_VOTES = "CELATONE_QUERY_PROPOSAL_VALIDATOR_VOTES", RELATED_PROPOSALS_BY_CONTRACT_ADDRESS = "CELATONE_QUERY_RELATED_PROPOSALS_BY_CONTRACT_ADDRESS", PROPOSALS_BY_MODULE_ID = "CELATONE_QUERY_PROPOSALS_BY_MODULE_ID", diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 442ab94dc..8bf099a2f 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -1,5 +1,6 @@ import type { Coin } from "@cosmjs/stargate"; import axios from "axios"; +import big from "big.js"; import { z } from "zod"; import { @@ -211,6 +212,33 @@ export const getProposalData = async ( .get(`${endpoint}/${encodeURIComponent(id)}/info`) .then(({ data }) => zProposalDataResponse.parse(data)); +const zProposalVotesInfoResponse = z + .object({ + yes: z.string(), + abstain: z.string(), + no: z.string(), + no_with_veto: z.string(), + total_voting_power: z.string(), + }) + .transform((val) => ({ + yes: big(val.yes), + abstain: big(val.abstain), + no: big(val.no), + noWithVeto: big(val.no_with_veto), + totalVotingPower: big(val.total_voting_power), + })); +export type ProposalVotesInfoResponse = z.infer< + typeof zProposalVotesInfoResponse +>; + +export const getProposalVotesInfo = async ( + endpoint: string, + id: number +): Promise => + axios + .get(`${endpoint}/${encodeURIComponent(id)}/votes-info`) + .then(({ data }) => zProposalVotesInfoResponse.parse(data)); + const zProposalVotesResponseItem = z .object({ proposal_id: z.number().nonnegative(), @@ -230,7 +258,6 @@ const zProposalVotesResponse = z.object({ items: z.array(zProposalVotesResponseItem), total: z.number().nonnegative(), }); - export type ProposalVotesResponse = z.infer; export const getProposalValidatorVotes = async ( diff --git a/src/lib/services/proposalService.ts b/src/lib/services/proposalService.ts index 65b4523a1..ef9482751 100644 --- a/src/lib/services/proposalService.ts +++ b/src/lib/services/proposalService.ts @@ -44,6 +44,7 @@ import type { RelatedProposalsResponse, UploadAccess, VotingParamsInternal, + ProposalVotesInfoResponse, } from "./proposal"; import { fetchGovVotingParams, @@ -55,6 +56,7 @@ import { getProposalTypes, getProposalData, getProposalValidatorVotes, + getProposalVotesInfo, } from "./proposal"; export const useProposals = ( @@ -226,16 +228,6 @@ export const useRelatedProposalsCountByModuleId = ( ); }; -export const useProposalData = (id: number) => { - const endpoint = useBaseApiRoute("proposals"); - - return useQuery( - [CELATONE_QUERY_KEYS.PROPOSAL_DATA, endpoint, id], - async () => getProposalData(endpoint, id), - { retry: 1, keepPreviousData: true } - ); -}; - export interface MinDeposit { amount: U>; denom: string; @@ -326,12 +318,30 @@ export const useUploadAccessParams = (): UseQueryResult => { ); }; -export const useProposalValidatorVotes = ( - id: number -): UseQueryResult => { +export const useProposalData = (id: number) => { const endpoint = useBaseApiRoute("proposals"); - return useQuery( + return useQuery( + [CELATONE_QUERY_KEYS.PROPOSAL_DATA, endpoint, id], + async () => getProposalData(endpoint, id), + { retry: 1, keepPreviousData: true } + ); +}; + +export const useProposalVotesInfo = (id: number) => { + const endpoint = useBaseApiRoute("proposals"); + + return useQuery( + [CELATONE_QUERY_KEYS.PROPOSAL_VALIDATOR_VOTES, endpoint, id], + async () => getProposalVotesInfo(endpoint, id), + { retry: 1, refetchOnWindowFocus: false } + ); +}; + +export const useProposalValidatorVotes = (id: number) => { + const endpoint = useBaseApiRoute("proposals"); + + return useQuery( [CELATONE_QUERY_KEYS.PROPOSAL_VALIDATOR_VOTES, endpoint, id], async () => getProposalValidatorVotes(endpoint, id), { retry: 1, refetchOnWindowFocus: false } From e022cdc77ec1bf36cce51fc54fa77272b2ca89ca Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Thu, 1 Feb 2024 18:50:11 +0700 Subject: [PATCH 058/531] fix(components): use zod to validate url --- .../components/__stories__/Markdown.stories.ts | 3 +-- .../components/ProposalOverview.tsx | 18 ++++-------------- src/lib/pages/proposal-details/index.tsx | 2 +- src/lib/utils/validate.ts | 10 ++++++++++ 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/lib/components/__stories__/Markdown.stories.ts b/src/lib/components/__stories__/Markdown.stories.ts index 823144de2..32de94124 100644 --- a/src/lib/components/__stories__/Markdown.stories.ts +++ b/src/lib/components/__stories__/Markdown.stories.ts @@ -57,8 +57,7 @@ for (let i = 0; i <= 10; i++) { } \`\`\``; -const list = ` -## Lists +const list = `## Lists ### Unordered diff --git a/src/lib/pages/proposal-details/components/ProposalOverview.tsx b/src/lib/pages/proposal-details/components/ProposalOverview.tsx index e17f2c008..bf4adbbff 100644 --- a/src/lib/pages/proposal-details/components/ProposalOverview.tsx +++ b/src/lib/pages/proposal-details/components/ProposalOverview.tsx @@ -2,6 +2,7 @@ import { Flex, Grid, GridItem, Heading, Text, Box } from "@chakra-ui/react"; import { Markdown } from "lib/components/Markdown"; import type { ProposalData } from "lib/types"; +import { isUrl } from "lib/utils"; const ProposalStatus = () => { return ( @@ -17,15 +18,10 @@ const ProposalStatus = () => { ); }; -const isUrl = (metadata: string): boolean => { - const urlRegex = - // eslint-disable-next-line no-useless-escape - /[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/; - return urlRegex.test(metadata); -}; interface ProposalOverviewProps { proposalData: ProposalData; } + export const ProposalOverview = ({ proposalData }: ProposalOverviewProps) => { const renderMetadata = () => { if (proposalData.metadata.length === 0) { @@ -47,6 +43,7 @@ export const ProposalOverview = ({ proposalData }: ProposalOverviewProps) => { textDecorationColor: "secondary.light", }} color="secondary.main" + wordBreak="break-all" > { ) : ( { Metadata - - {renderMetadata()} - + {renderMetadata()} - + diff --git a/src/lib/utils/validate.ts b/src/lib/utils/validate.ts index 537186f88..fa26c7f43 100644 --- a/src/lib/utils/validate.ts +++ b/src/lib/utils/validate.ts @@ -1,4 +1,5 @@ import { fromHex } from "@cosmjs/encoding"; +import { z } from "zod"; import { HEX_WALLET_ADDRESS_LENGTH, HEX_MODULE_ADDRESS_LENGTH } from "lib/data"; import type { HexAddr } from "lib/types"; @@ -27,6 +28,15 @@ export const isHex = (input: string): boolean => { export const isTxHash = (input: string): boolean => isHex(input) && input.length === 64; +export const isUrl = (string: string): boolean => { + try { + z.string().url().parse(string); + return true; + } catch (error) { + return false; + } +}; + const isHexAddress = (address: string, length: number): boolean => { const regex = new RegExp(`^0x[a-fA-F0-9]{1,${length}}$`); if (!regex.test(address)) { From 95788ba68ce31fb96f4d170f203e4df0efdf72b3 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 2 Feb 2024 14:59:13 +0700 Subject: [PATCH 059/531] feat: proposal status summary template --- CHANGELOG.md | 1 + .../components/ProposalOverview.tsx | 36 +++++++++++-------- .../proposal-details/components/index.ts | 2 ++ .../components/status-summary/ActiveDot.tsx | 22 ++++++++++++ .../components/status-summary/index.tsx | 30 ++++++++++++++++ src/lib/pages/proposal-details/index.tsx | 17 ++++++--- 6 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 src/lib/pages/proposal-details/components/status-summary/ActiveDot.tsx create mode 100644 src/lib/pages/proposal-details/components/status-summary/index.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 14810a4ab..e79e6050b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#763](https://github.com/alleslabs/celatone-frontend/pull/763) Proposal status summary - [#762](https://github.com/alleslabs/celatone-frontend/pull/762) api v1 - proposal validator votes info - [#745](https://github.com/alleslabs/celatone-frontend/pull/745) Add proposal top - [#758](https://github.com/alleslabs/celatone-frontend/pull/758) api v1 - proposal validator votes diff --git a/src/lib/pages/proposal-details/components/ProposalOverview.tsx b/src/lib/pages/proposal-details/components/ProposalOverview.tsx index d30ffbbd3..fbda352b7 100644 --- a/src/lib/pages/proposal-details/components/ProposalOverview.tsx +++ b/src/lib/pages/proposal-details/components/ProposalOverview.tsx @@ -1,19 +1,21 @@ import { Flex, Grid, GridItem, Heading, Text } from "@chakra-ui/react"; -const ProposalStatus = () => { - return ( - - Current Status component - - ); -}; -export const ProposalOverview = () => { +import type { ProposalVotesInfoResponse } from "lib/services/proposal"; +import type { Option, ProposalData } from "lib/types"; + +import { StatusSummary } from "./status-summary"; + +export interface ProposalOverviewProps { + proposalData: ProposalData; + votesInfo: Option; + isLoading: boolean; +} + +export const ProposalOverview = ({ + proposalData, + votesInfo, + isLoading, +}: ProposalOverviewProps) => { return ( { > - + Proposal Description diff --git a/src/lib/pages/proposal-details/components/index.ts b/src/lib/pages/proposal-details/components/index.ts index f3e755726..ebf9a89de 100644 --- a/src/lib/pages/proposal-details/components/index.ts +++ b/src/lib/pages/proposal-details/components/index.ts @@ -1 +1,3 @@ export * from "./ProposalTop"; +export * from "./ProposalOverview"; +export * from "./VoteDetail"; diff --git a/src/lib/pages/proposal-details/components/status-summary/ActiveDot.tsx b/src/lib/pages/proposal-details/components/status-summary/ActiveDot.tsx new file mode 100644 index 000000000..eb3de85eb --- /dev/null +++ b/src/lib/pages/proposal-details/components/status-summary/ActiveDot.tsx @@ -0,0 +1,22 @@ +import { MotionBox } from "lib/components/MotionBox"; +import { ProposalStatus } from "lib/types"; + +interface ActiveDotProps { + status: ProposalStatus; +} + +export const ActiveDot = ({ status }: ActiveDotProps) => + status !== ProposalStatus.DEPOSIT_PERIOD && + status !== ProposalStatus.VOTING_PERIOD ? null : ( + + ); diff --git a/src/lib/pages/proposal-details/components/status-summary/index.tsx b/src/lib/pages/proposal-details/components/status-summary/index.tsx new file mode 100644 index 000000000..b1a714e1b --- /dev/null +++ b/src/lib/pages/proposal-details/components/status-summary/index.tsx @@ -0,0 +1,30 @@ +import { Flex, Text } from "@chakra-ui/react"; + +import type { ProposalOverviewProps } from "../ProposalOverview"; +import { StatusChip } from "lib/components/table"; +import { ProposalStatus } from "lib/types"; + +import { ActiveDot } from "./ActiveDot"; + +export const StatusSummary = ({ proposalData }: ProposalOverviewProps) => { + return ( + + + + + Current proposal result: + + + + + ); +}; diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index 0f6954d89..d714942d5 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -7,11 +7,12 @@ import { CustomTab } from "lib/components/CustomTab"; import { Loading } from "lib/components/Loading"; import PageContainer from "lib/components/PageContainer"; import { ErrorFetching, InvalidState } from "lib/components/state"; -import { useProposalData } from "lib/services/proposalService"; +import { + useProposalData, + useProposalVotesInfo, +} from "lib/services/proposalService"; -import { ProposalTop } from "./components"; -import { ProposalOverview } from "./components/ProposalOverview"; -import { VoteDetail } from "./components/VoteDetail"; +import { ProposalTop, ProposalOverview, VoteDetail } from "./components"; import type { ProposalDetailsQueryParams } from "./type"; import { zProposalDetailsQueryParams, TabIndex } from "./type"; @@ -23,6 +24,8 @@ const ProposalDetailsBody = ({ const router = useRouter(); const navigate = useInternalNavigate(); const { data, isLoading } = useProposalData(id); + const { data: votesInfo, isLoading: isVotesInfoLoading } = + useProposalVotesInfo(id); const handleTabChange = useCallback( (nextTab: TabIndex) => () => { @@ -83,7 +86,11 @@ const ProposalDetailsBody = ({ - + From 25f17914824b754acb69f2a3c1030d1e4faea912 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 2 Feb 2024 17:15:41 +0700 Subject: [PATCH 060/531] feat: api v1 - proposal params --- CHANGELOG.md | 1 + src/lib/app-provider/env.ts | 1 + src/lib/services/proposal.ts | 36 +++++++++++++++++++++++++---- src/lib/services/proposalService.ts | 23 +++++++++++++----- src/lib/types/proposal.ts | 27 ++++++++++++++++++++++ 5 files changed, 77 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b938bc1db..ccfed9854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#764](https://github.com/alleslabs/celatone-frontend/pull/762) api v1 - proposal params - [#762](https://github.com/alleslabs/celatone-frontend/pull/762) api v1 - proposal validator votes info - [#745](https://github.com/alleslabs/celatone-frontend/pull/745) Add proposal top - [#758](https://github.com/alleslabs/celatone-frontend/pull/758) api v1 - proposal validator votes diff --git a/src/lib/app-provider/env.ts b/src/lib/app-provider/env.ts index d4ac54653..dfdcae140 100644 --- a/src/lib/app-provider/env.ts +++ b/src/lib/app-provider/env.ts @@ -59,6 +59,7 @@ export enum CELATONE_QUERY_KEYS { PROPOSALS_COUNT_BY_MODULE_ID = "CELATONE_QUERY_PROPOSALS_COUNT_BY_MODULE_ID", PROPOSALS_BY_ADDRESS = "CELATONE_QUERY_PROPOSALS_BY_ADDRESS", PROPOSALS = "CELATONE_QUERY_PROPOSALS", + PROPOSAL_PARAMS = "CELATONE_QUERY_PROPOSAL_PARAMS", PROPOSAL_TYPES = "CELATONE_QUERY_PROPOSAL_TYPES", GOV_PARAMS = "CELATONE_QUERY_GOV_PARAMS", UPLOAD_ACCESS_PARAMS = "CELATONE_QUERY_UPLOAD_ACCESS_PARAMS", diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 8bf099a2f..4dc4377d6 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -23,6 +23,8 @@ import type { ProposalStatus, ProposalType, ProposalVote, + ProposalParams, + ProposalVotesInfo, } from "lib/types"; import { parseTxHash, snakeToCamel } from "lib/utils"; @@ -77,6 +79,33 @@ export const fetchGovUploadAccessParams = async ( ): Promise => axios.get(`${lcdEndpoint}/upload_access`).then(({ data }) => data); +const zProposalParamsResponse = z + .object({ + min_deposit: zCoin.array(), + min_initial_deposit_ratio: z.coerce.number(), + max_deposit_period: z.string(), + voting_period: z.string(), + veto_threshold: z.coerce.number(), + quorum: z.coerce.number(), + threshold: z.coerce.number(), + // expedited + expedited_voting_period: z.string().optional(), + expedited_threshold: z.coerce.number().optional(), + expedited_min_deposit: zCoin.array().optional(), + expedited_quorum: z.string().optional(), // only in sei + // emergency - only in initia + emergency_min_deposit: zCoin.array().optional(), + emergency_tally_interval: z.string().optional(), + }) + .transform(snakeToCamel); + +export const getProposalParams = async ( + endpoint: string +): Promise => + axios + .get(`${endpoint}/params`) + .then(({ data }) => zProposalParamsResponse.parse(data)); + export const getProposalTypes = async (endpoint: string) => axios .get(`${endpoint}/types`) @@ -220,21 +249,18 @@ const zProposalVotesInfoResponse = z no_with_veto: z.string(), total_voting_power: z.string(), }) - .transform((val) => ({ + .transform((val) => ({ yes: big(val.yes), abstain: big(val.abstain), no: big(val.no), noWithVeto: big(val.no_with_veto), totalVotingPower: big(val.total_voting_power), })); -export type ProposalVotesInfoResponse = z.infer< - typeof zProposalVotesInfoResponse ->; export const getProposalVotesInfo = async ( endpoint: string, id: number -): Promise => +): Promise => axios .get(`${endpoint}/${encodeURIComponent(id)}/votes-info`) .then(({ data }) => zProposalVotesInfoResponse.parse(data)); diff --git a/src/lib/services/proposalService.ts b/src/lib/services/proposalService.ts index ef9482751..44bdb0835 100644 --- a/src/lib/services/proposalService.ts +++ b/src/lib/services/proposalService.ts @@ -15,6 +15,7 @@ import { } from "lib/query"; import { createQueryFnWithTimeout } from "lib/query-utils"; import type { + ProposalParams, Option, ProposalStatus, ProposalType, @@ -25,6 +26,7 @@ import type { BechAddr32, BechAddr, BechAddr20, + ProposalVotesInfo, } from "lib/types"; import { coinToTokenWithValue, @@ -44,19 +46,19 @@ import type { RelatedProposalsResponse, UploadAccess, VotingParamsInternal, - ProposalVotesInfoResponse, } from "./proposal"; import { fetchGovVotingParams, fetchGovDepositParams, fetchGovUploadAccessParams, getProposalsByAddress, - getRelatedProposalsByContractAddress, getProposals, - getProposalTypes, getProposalData, + getProposalParams, + getProposalTypes, getProposalValidatorVotes, getProposalVotesInfo, + getRelatedProposalsByContractAddress, } from "./proposal"; export const useProposals = ( @@ -95,9 +97,18 @@ export const useProposals = ( ); }; -export const useProposalTypes = (): UseQueryResult => { +export const useProposalParams = () => { const endpoint = useBaseApiRoute("proposals"); - return useQuery( + return useQuery( + [CELATONE_QUERY_KEYS.PROPOSAL_PARAMS, endpoint], + async () => getProposalParams(endpoint), + { retry: 1, refetchOnWindowFocus: false } + ); +}; + +export const useProposalTypes = () => { + const endpoint = useBaseApiRoute("proposals"); + return useQuery( [CELATONE_QUERY_KEYS.PROPOSAL_TYPES, endpoint], async () => getProposalTypes(endpoint), { retry: 1, refetchOnWindowFocus: false } @@ -331,7 +342,7 @@ export const useProposalData = (id: number) => { export const useProposalVotesInfo = (id: number) => { const endpoint = useBaseApiRoute("proposals"); - return useQuery( + return useQuery( [CELATONE_QUERY_KEYS.PROPOSAL_VALIDATOR_VOTES, endpoint, id], async () => getProposalVotesInfo(endpoint, id), { retry: 1, refetchOnWindowFocus: false } diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 29d8c17dd..480ae0d52 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -1,4 +1,5 @@ import type { Coin } from "@cosmjs/amino"; +import type Big from "big.js"; import { z } from "zod"; import type { BechAddr, Nullable, Option, Validator } from "lib/types"; @@ -69,6 +70,24 @@ export interface Proposal { isExpedited: boolean; } +export interface ProposalParams { + minDeposit: Coin[]; + minInitialDepositRatio: number; + maxDepositPeriod: string; + votingPeriod: string; + vetoThreshold: number; + quorum: number; + threshold: number; + // expedited + expeditedVotingPeriod?: string; + expeditedThreshold?: number; + expeditedMinDeposit?: Coin[]; + expeditedQuorum?: string; // only in sei + // emergency - only in initia + emergencyMinDeposit?: Coin[]; + emergencyTallyInterval?: string; +} + export interface ProposalDeposit { amount: Coin[]; depositor: BechAddr; @@ -91,6 +110,14 @@ export interface ProposalData extends Proposal { votingTime: Nullable; } +export interface ProposalVotesInfo { + yes: Big; + abstain: Big; + no: Big; + noWithVeto: Big; + totalVotingPower: Big; +} + export interface ProposalVote { proposalId: number; abstain: number; From 580294c49578e5b61bf3c61625ecbfe2bc1aafe5 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 2 Feb 2024 17:17:04 +0700 Subject: [PATCH 061/531] fix: changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccfed9854..38257eb5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features -- [#764](https://github.com/alleslabs/celatone-frontend/pull/762) api v1 - proposal params +- [#764](https://github.com/alleslabs/celatone-frontend/pull/764) api v1 - proposal params - [#762](https://github.com/alleslabs/celatone-frontend/pull/762) api v1 - proposal validator votes info - [#745](https://github.com/alleslabs/celatone-frontend/pull/745) Add proposal top - [#758](https://github.com/alleslabs/celatone-frontend/pull/758) api v1 - proposal validator votes From ad60058352c37c72f1edb26be1c96d5ab683d205 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 2 Feb 2024 17:46:23 +0700 Subject: [PATCH 062/531] feat: proposal cancelled status --- CHANGELOG.md | 1 + .../components/table/proposals/StatusChip.tsx | 6 +- .../components/ProposalInfo.tsx | 158 ------------------ .../components/ProposalTop.tsx | 2 +- .../components/proposal-info/InfoItem.tsx | 16 ++ .../components/proposal-info/TimeInfoItem.tsx | 104 ++++++++++++ .../components/proposal-info/index.tsx | 56 +++++++ src/lib/types/proposal.ts | 27 +++ 8 files changed, 209 insertions(+), 161 deletions(-) delete mode 100644 src/lib/pages/proposal-details/components/ProposalInfo.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-info/InfoItem.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-info/TimeInfoItem.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-info/index.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index b938bc1db..4ba879d68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#765](https://github.com/alleslabs/celatone-frontend/pull/765) Support Proposal Cancelled status - [#762](https://github.com/alleslabs/celatone-frontend/pull/762) api v1 - proposal validator votes info - [#745](https://github.com/alleslabs/celatone-frontend/pull/745) Add proposal top - [#758](https://github.com/alleslabs/celatone-frontend/pull/758) api v1 - proposal validator votes diff --git a/src/lib/components/table/proposals/StatusChip.tsx b/src/lib/components/table/proposals/StatusChip.tsx index a2c0b7a73..e8a2261ac 100644 --- a/src/lib/components/table/proposals/StatusChip.tsx +++ b/src/lib/components/table/proposals/StatusChip.tsx @@ -11,13 +11,15 @@ const getBgColor = ( switch (status) { case ProposalStatus.DEPOSIT_PERIOD: return "secondary.darker"; + case ProposalStatus.VOTING_PERIOD: + return "primary.dark"; case ProposalStatus.FAILED: case ProposalStatus.REJECTED: return "error.dark"; case ProposalStatus.PASSED: return "success.dark"; - case ProposalStatus.VOTING_PERIOD: - return "primary.dark"; + case ProposalStatus.CANCELLED: + return "error.background"; case ProposalStatus.DEPOSIT_FAILED: default: return "gray.700"; diff --git a/src/lib/pages/proposal-details/components/ProposalInfo.tsx b/src/lib/pages/proposal-details/components/ProposalInfo.tsx deleted file mode 100644 index 528406766..000000000 --- a/src/lib/pages/proposal-details/components/ProposalInfo.tsx +++ /dev/null @@ -1,158 +0,0 @@ -import { Divider, Flex, Text } from "@chakra-ui/react"; -import type { ReactNode } from "react"; - -import { ExplorerLink } from "lib/components/ExplorerLink"; -import { MobileLabel, StatusChip } from "lib/components/table"; -import type { ProposalData } from "lib/types"; -import { ProposalStatus } from "lib/types"; -import { formatUTC } from "lib/utils"; - -interface InfoItemProps { - label: string; - children: ReactNode; - minW?: number; -} - -const InfoItem = ({ label, children, minW = 40 }: InfoItemProps) => ( - - - {children} - -); - -interface ProposalStatusProps { - data: ProposalData; -} - -const getProposalInfo = (data: ProposalStatusProps["data"]) => { - switch (data.status) { - case ProposalStatus.DEPOSIT_PERIOD: - return ( - - - {data.submitTime && data.depositEndTime - ? `${formatUTC(data.submitTime)} - ${formatUTC(data.depositEndTime)}` - : "N/A"} - - - ); - case ProposalStatus.DEPOSIT_FAILED: - return ( - - - {data.resolvedHeight ? ( - - ) : ( - - N/A - - )} - - - - {data.resolvedTimestamp - ? formatUTC(data.resolvedTimestamp) - : "N/A"} - - - - ); - case ProposalStatus.VOTING_PERIOD: - return ( - - - {data.votingTime && data.votingEndTime - ? `${formatUTC(data.votingTime)} - ${formatUTC(data.votingEndTime)}` - : "N/A"} - - - ); - case ProposalStatus.PASSED: - case ProposalStatus.FAILED: - case ProposalStatus.REJECTED: - return ( - - - {data.resolvedHeight ? ( - - ) : ( - - N/A - - )} - - - - {data.resolvedTimestamp - ? formatUTC(data.resolvedTimestamp) - : "N/A"} - - - - ); - default: - return ( - - N/A - - ); - } -}; - -export const ProposalInfo = ({ data }: ProposalStatusProps) => ( - - - - - - - - {data.createdTxHash && ( - - - - )} - {data.proposer && ( - - - - )} - - - {getProposalInfo(data)} - -); diff --git a/src/lib/pages/proposal-details/components/ProposalTop.tsx b/src/lib/pages/proposal-details/components/ProposalTop.tsx index d0dbc259c..7b7ff2ef6 100644 --- a/src/lib/pages/proposal-details/components/ProposalTop.tsx +++ b/src/lib/pages/proposal-details/components/ProposalTop.tsx @@ -8,7 +8,7 @@ import { CustomIcon } from "lib/components/icon"; import type { ProposalData } from "lib/types"; import { formatUTC, openNewTab } from "lib/utils"; -import { ProposalInfo } from "./ProposalInfo"; +import { ProposalInfo } from "./proposal-info"; interface ProposalTopProps { proposalData: ProposalData; diff --git a/src/lib/pages/proposal-details/components/proposal-info/InfoItem.tsx b/src/lib/pages/proposal-details/components/proposal-info/InfoItem.tsx new file mode 100644 index 000000000..0aa26e062 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-info/InfoItem.tsx @@ -0,0 +1,16 @@ +import { Flex } from "@chakra-ui/react"; + +import { MobileLabel } from "lib/components/table"; + +interface InfoItemProps { + label: string; + children: JSX.Element; + minW?: number; +} + +export const InfoItem = ({ label, children, minW = 40 }: InfoItemProps) => ( + + + {children} + +); diff --git a/src/lib/pages/proposal-details/components/proposal-info/TimeInfoItem.tsx b/src/lib/pages/proposal-details/components/proposal-info/TimeInfoItem.tsx new file mode 100644 index 000000000..e416a05c6 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-info/TimeInfoItem.tsx @@ -0,0 +1,104 @@ +import { Flex, Text } from "@chakra-ui/react"; + +import { ExplorerLink } from "lib/components/ExplorerLink"; +import { ProposalStatus, type ProposalData } from "lib/types"; +import { formatUTC } from "lib/utils"; + +import { InfoItem } from "./InfoItem"; + +interface TimeInfoItemProps { + data: ProposalData; +} + +const ResolvedTimeInfoItems = ({ + resolvedHeightLabel, + resolvedTimestampLabel, + resolvedHeight, + resolvedTimestamp, +}: { + resolvedHeightLabel: string; + resolvedTimestampLabel: string; + resolvedHeight: ProposalData["resolvedHeight"]; + resolvedTimestamp: ProposalData["resolvedTimestamp"]; +}) => ( + + + {resolvedHeight ? ( + + ) : ( + + N/A + + )} + + + + {resolvedTimestamp ? formatUTC(resolvedTimestamp) : "N/A"} + + + +); + +export const TimeInfoItem = ({ data }: TimeInfoItemProps) => { + switch (data.status) { + case ProposalStatus.DEPOSIT_PERIOD: + return ( + + + {data.submitTime && data.depositEndTime + ? `${formatUTC(data.submitTime)} - ${formatUTC(data.depositEndTime)}` + : "N/A"} + + + ); + case ProposalStatus.DEPOSIT_FAILED: + return ( + + ); + case ProposalStatus.VOTING_PERIOD: + return ( + + + {data.votingTime && data.votingEndTime + ? `${formatUTC(data.votingTime)} - ${formatUTC(data.votingEndTime)}` + : "N/A"} + + + ); + case ProposalStatus.PASSED: + case ProposalStatus.FAILED: + case ProposalStatus.REJECTED: + return ( + + ); + case ProposalStatus.CANCELLED: + return ( + + ); + default: + return ( + + N/A + + ); + } +}; diff --git a/src/lib/pages/proposal-details/components/proposal-info/index.tsx b/src/lib/pages/proposal-details/components/proposal-info/index.tsx new file mode 100644 index 000000000..53a3d273f --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-info/index.tsx @@ -0,0 +1,56 @@ +import { Divider, Flex } from "@chakra-ui/react"; + +import { ExplorerLink } from "lib/components/ExplorerLink"; +import { StatusChip } from "lib/components/table"; +import type { ProposalData } from "lib/types"; + +import { InfoItem } from "./InfoItem"; +import { TimeInfoItem } from "./TimeInfoItem"; + +interface ProposalStatusProps { + data: ProposalData; +} + +export const ProposalInfo = ({ data }: ProposalStatusProps) => ( + + + + + + + + {data.createdTxHash && ( + + + + )} + {data.proposer && ( + + + + )} + + + + +); diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 29d8c17dd..2659ab426 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -10,6 +10,7 @@ export enum ProposalStatus { REJECTED = "Rejected", FAILED = "Failed", DEPOSIT_FAILED = "Inactive", + CANCELLED = "Cancelled", } export const zProposalStatus = z.nativeEnum(ProposalStatus); @@ -69,6 +70,24 @@ export interface Proposal { isExpedited: boolean; } +export interface ProposalParams { + minDeposit: Coin[]; + minInitialDepositRatio: number; + maxDepositPeriod: string; + votingPeriod: string; + vetoThreshold: number; + quorum: number; + threshold: number; + // expedited + expeditedVotingPeriod?: string; + expeditedThreshold?: number; + expeditedMinDeposit?: Coin[]; + expeditedQuorum?: string; // only in sei + // emergency - only in initia + emergencyMinDeposit?: Coin[]; + emergencyTallyInterval?: string; +} + export interface ProposalDeposit { amount: Coin[]; depositor: BechAddr; @@ -91,6 +110,14 @@ export interface ProposalData extends Proposal { votingTime: Nullable; } +export interface ProposalVotesInfo { + yes: Big; + abstain: Big; + no: Big; + noWithVeto: Big; + totalVotingPower: Big; +} + export interface ProposalVote { proposalId: number; abstain: number; From b6b16f81f6a5ffb1ccf80700df89b32eee8add98 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 2 Feb 2024 18:34:20 +0700 Subject: [PATCH 063/531] fix: no types --- .../table/proposals/ProposalTextCell.tsx | 20 +++++++++------- .../proposals/ProposalsTableMobileCard.tsx | 24 ++++++++++++------- .../components/ProposalTop.tsx | 5 ++-- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/lib/components/table/proposals/ProposalTextCell.tsx b/src/lib/components/table/proposals/ProposalTextCell.tsx index e6dcf1b25..4f1325504 100644 --- a/src/lib/components/table/proposals/ProposalTextCell.tsx +++ b/src/lib/components/table/proposals/ProposalTextCell.tsx @@ -70,16 +70,18 @@ export const ProposalTextCell = ({ maxW={showName ? undefined : "full"} className={showName ? undefined : "ellipsis"} > - {types.map((msgType, index) => ( - - {index > 0 && ( - - {" / "} + {types.length + ? types.map((msgType, index) => ( + + {index > 0 && ( + + {" / "} + + )} + {msgType} - )} - {msgType} - - ))} + )) + : "(No message)"} diff --git a/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx b/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx index 46e6d7bcd..f9671285f 100644 --- a/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx +++ b/src/lib/components/table/proposals/ProposalsTableMobileCard.tsx @@ -52,16 +52,22 @@ export const ProposalsTableMobileCard = ({ {proposal.title} - {proposal.types.map((msgType, index) => ( - - {msgType} + {proposal.types.length ? ( + proposal.types.map((msgType, index) => ( + + {msgType} + + )) + ) : ( + + (No message) - ))} + )} diff --git a/src/lib/pages/proposal-details/components/ProposalTop.tsx b/src/lib/pages/proposal-details/components/ProposalTop.tsx index d0dbc259c..0d7b10bf7 100644 --- a/src/lib/pages/proposal-details/components/ProposalTop.tsx +++ b/src/lib/pages/proposal-details/components/ProposalTop.tsx @@ -68,6 +68,7 @@ export const ProposalTop = ({ proposalData }: ProposalTopProps) => { { ))} ) : ( - - No Message + + (No Message) )} From bf7dd620f7f3f9d7127435faa8491ae6c4cd709e Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Mon, 5 Feb 2024 11:47:53 +0700 Subject: [PATCH 064/531] fix(components): fix order in validate ts --- src/lib/utils/validate.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib/utils/validate.ts b/src/lib/utils/validate.ts index fa26c7f43..6f26643a7 100644 --- a/src/lib/utils/validate.ts +++ b/src/lib/utils/validate.ts @@ -15,6 +15,15 @@ export const isPosDecimal = (input: string): boolean => { export const isId = (input: string): boolean => input.length <= 7 && isPosDecimal(input); +export const isUrl = (string: string): boolean => { + try { + z.string().url().parse(string); + return true; + } catch (error) { + return false; + } +}; + export const isHex = (input: string): boolean => { if (input.trim() === "") return false; try { @@ -28,15 +37,6 @@ export const isHex = (input: string): boolean => { export const isTxHash = (input: string): boolean => isHex(input) && input.length === 64; -export const isUrl = (string: string): boolean => { - try { - z.string().url().parse(string); - return true; - } catch (error) { - return false; - } -}; - const isHexAddress = (address: string, length: number): boolean => { const regex = new RegExp(`^0x[a-fA-F0-9]{1,${length}}$`); if (!regex.test(address)) { From 983608584a47cbad056705a5f4486302970ec5eb Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Mon, 5 Feb 2024 11:59:09 +0700 Subject: [PATCH 065/531] fix(components): fix render metadata --- .../__stories__/Markdown.stories.ts | 140 ++++++++---------- .../components/ProposalOverview.tsx | 76 +++++----- 2 files changed, 98 insertions(+), 118 deletions(-) diff --git a/src/lib/components/__stories__/Markdown.stories.ts b/src/lib/components/__stories__/Markdown.stories.ts index 32de94124..2b1038bb8 100644 --- a/src/lib/components/__stories__/Markdown.stories.ts +++ b/src/lib/components/__stories__/Markdown.stories.ts @@ -13,126 +13,108 @@ const meta: Meta = { export default meta; type Story = StoryObj; -const heading = `# This is an H1 Header -## This is an H2 Header -### This is an H3 Header -#### This is an H4 Header -##### This is an H5 Header -###### This is an H6 Header`; - -const paragraph = `This is the first line of the paragraph. -And this is the second line on the same paragraph, separated by a line break. - -This is a new paragraph.`; - -const emphasis = `## Emphasis - -*This text will be italic* -_This will also be italic_ - -**This text will be bold** -__This will also be bold__ - -_You **can** combine them_ -`; - -const link = `## Links - -[This is a link](http://www.celat.one)`; - -const blockquote = `> This is a blockquote.`; - -const inlineCode = "This is an inline `code`."; - -const codeBlock = `\`\`\`javascript -function fibonacci(n) { - if (n <= 1) { - return n; - } - return fibonacci(n - 1) + fibonacci(n - 2); -} - -for (let i = 0; i <= 10; i++) { - console.log(\`Fibonacci of \${i} is \${fibonacci(i)}\`); -} -\`\`\``; - -const list = `## Lists - -### Unordered - -* Item 1 -* Item 2 - * Item 2a - * Item 2b - -### Ordered - -1. Item 1 -2. Item 2 -3. Item 3 -`; - -const table = `# Example Markdown with Table - -This is an example of a table in a Markdown document: - -| Header 1 | Header 2 | Header 3 | -|-------------|-------------|-------------| -| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 | -| Row 2 Col 1 | Row 2 Col 2 | Row 2 Col 3 | -| Row 3 Col 1 | Row 3 Col 2 | Row 3 Col 3 |`; - export const Heading: Story = { args: { - markdown: heading, + markdown: `# This is an H1 Header + ## This is an H2 Header + ### This is an H3 Header + #### This is an H4 Header + ##### This is an H5 Header + ###### This is an H6 Header`, }, }; export const Paragraph: Story = { args: { - markdown: paragraph, + markdown: `This is the first line of the paragraph. + And this is the second line on the same paragraph, separated by a line break. + + This is a new paragraph.`, }, }; export const Link: Story = { args: { - markdown: link, + markdown: `## Links + + [This is a link](http://www.celat.one)`, }, }; export const Blockquote: Story = { args: { - markdown: blockquote, + markdown: `> This is a blockquote.`, }, }; export const InlineCode: Story = { args: { - markdown: inlineCode, + markdown: "This is an inline `code`.", }, }; export const CodeBlock: Story = { args: { - markdown: codeBlock, + markdown: `\`\`\`javascript + function fibonacci(n) { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); + } + + for (let i = 0; i <= 10; i++) { + console.log(\`Fibonacci of \${i} is \${fibonacci(i)}\`); + } + \`\`\``, }, }; export const Emphasis: Story = { args: { - markdown: emphasis, + markdown: `## Emphasis + + *This text will be italic* + _This will also be italic_ + + **This text will be bold** + __This will also be bold__ + + _You **can** combine them_ + `, }, }; export const List: Story = { args: { - markdown: list, + markdown: `## Lists + + ### Unordered + + * Item 1 + * Item 2 + * Item 2a + * Item 2b + + ### Ordered + + 1. Item 1 + 2. Item 2 + 3. Item 3 + `, }, }; export const Table: Story = { args: { - markdown: table, + markdown: `# Example Markdown with Table + + This is an example of a table in a Markdown document: + + | Header 1 | Header 2 | Header 3 | + |-------------|-------------|-------------| + | Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 | + | Row 2 Col 1 | Row 2 Col 2 | Row 2 Col 3 | + | Row 3 Col 1 | Row 3 Col 2 | Row 3 Col 3 |`, }, }; diff --git a/src/lib/pages/proposal-details/components/ProposalOverview.tsx b/src/lib/pages/proposal-details/components/ProposalOverview.tsx index bf4adbbff..d80af3c73 100644 --- a/src/lib/pages/proposal-details/components/ProposalOverview.tsx +++ b/src/lib/pages/proposal-details/components/ProposalOverview.tsx @@ -22,48 +22,46 @@ interface ProposalOverviewProps { proposalData: ProposalData; } -export const ProposalOverview = ({ proposalData }: ProposalOverviewProps) => { - const renderMetadata = () => { - if (proposalData.metadata.length === 0) { - return ( - - Not Provided - - ); - } - - if (isUrl(proposalData.metadata)) { - return ( - - - {proposalData.metadata} - - - ); - } - +const RenderMetadata = ({ proposalData }: ProposalOverviewProps) => { + if (proposalData.metadata.length === 0) { return ( - - {proposalData.metadata} + + Not Provided ); - }; + } + if (isUrl(proposalData.metadata)) { + return ( + + + {proposalData.metadata} + + + ); + } + return ( + + {proposalData.metadata} + + ); +}; +export const ProposalOverview = ({ proposalData }: ProposalOverviewProps) => { return ( { Metadata - {renderMetadata()} + Date: Mon, 5 Feb 2024 15:44:00 +0700 Subject: [PATCH 066/531] fix(components): add to do --- src/lib/types/proposal.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index c70027da5..a602331cc 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -95,6 +95,7 @@ export interface ProposalDeposit { txHash: string; } +// TODO: combine with MsgBody in services/tx.ts interface Message { "@type": string; [key: string]: unknown; From 14bc0cba7810286c563e3c9dc9396f36454ecea3 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Mon, 5 Feb 2024 15:49:53 +0700 Subject: [PATCH 067/531] fix(components): move json info component --- .../components => components/json}/JsonInfo.tsx | 5 +++-- src/lib/pages/contract-details/index.tsx | 2 +- .../pages/proposal-details/components/ProposalOverview.tsx | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) rename src/lib/{pages/contract-details/components => components/json}/JsonInfo.tsx (91%) diff --git a/src/lib/pages/contract-details/components/JsonInfo.tsx b/src/lib/components/json/JsonInfo.tsx similarity index 91% rename from src/lib/pages/contract-details/components/JsonInfo.tsx rename to src/lib/components/json/JsonInfo.tsx index 62947783b..7106a8c16 100644 --- a/src/lib/pages/contract-details/components/JsonInfo.tsx +++ b/src/lib/components/json/JsonInfo.tsx @@ -1,8 +1,9 @@ import { Flex, Heading } from "@chakra-ui/react"; import { useState } from "react"; -import { CustomIcon } from "lib/components/icon"; -import JsonReadOnly from "lib/components/json/JsonReadOnly"; +import { CustomIcon } from "../icon"; + +import JsonReadOnly from "./JsonReadOnly"; interface JsonInfoProps { header: string; diff --git a/src/lib/pages/contract-details/index.tsx b/src/lib/pages/contract-details/index.tsx index cf5a7e1ab..c264563a1 100644 --- a/src/lib/pages/contract-details/index.tsx +++ b/src/lib/pages/contract-details/index.tsx @@ -22,6 +22,7 @@ import { AssetsSection } from "lib/components/asset"; import { CustomTab } from "lib/components/CustomTab"; import { DelegationsSection } from "lib/components/delegations"; import { CustomIcon } from "lib/components/icon"; +import { JsonInfo } from "lib/components/json/JsonInfo"; import { Loading } from "lib/components/Loading"; import PageContainer from "lib/components/PageContainer"; import { ErrorFetching, InvalidState } from "lib/components/state"; @@ -34,7 +35,6 @@ import { ContractDesc } from "./components/contract-description"; import { ContractStates } from "./components/contract-states"; import { ContractTop } from "./components/ContractTop"; import { InstantiateInfo } from "./components/InstantiateInfo"; -import { JsonInfo } from "./components/JsonInfo"; import { ContractTables } from "./components/tables"; import { useContractData } from "./data"; import { TabIndex, zContractDetailsQueryParams } from "./types"; diff --git a/src/lib/pages/proposal-details/components/ProposalOverview.tsx b/src/lib/pages/proposal-details/components/ProposalOverview.tsx index bd133bd98..dd82a065b 100644 --- a/src/lib/pages/proposal-details/components/ProposalOverview.tsx +++ b/src/lib/pages/proposal-details/components/ProposalOverview.tsx @@ -1,7 +1,7 @@ import { Flex, Grid, GridItem, Heading, Text, Box } from "@chakra-ui/react"; +import { JsonInfo } from "lib/components/json/JsonInfo"; import { Markdown } from "lib/components/Markdown"; -import { JsonInfo } from "lib/pages/contract-details/components/JsonInfo"; import type { ProposalData } from "lib/types"; import { isUrl, jsonPrettify } from "lib/utils"; From c1782ece77497076cf2b583bab909e2a02843f37 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Mon, 5 Feb 2024 17:18:48 +0700 Subject: [PATCH 068/531] fix: pull data --- .../components/proposal-overview/index.tsx | 10 +++++++++- src/lib/pages/proposal-details/index.tsx | 5 ++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/index.tsx index 0a7c75bb4..372f60fe4 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/index.tsx @@ -1,6 +1,11 @@ import { Flex, Grid, GridItem, Heading } from "@chakra-ui/react"; -import type { ProposalData, Option, ProposalVotesInfo } from "lib/types"; +import type { + ProposalData, + Option, + ProposalVotesInfo, + ProposalParams, +} from "lib/types"; import { ProposalDescription } from "./ProposalDescription"; import { ProposalMessages } from "./ProposalMessages"; @@ -10,12 +15,14 @@ import { StatusSummary } from "./status-summary"; export interface ProposalOverviewProps { proposalData: ProposalData; votesInfo: Option; + params: Option; isLoading: boolean; } export const ProposalOverview = ({ proposalData, votesInfo, + params, isLoading, }: ProposalOverviewProps) => ( diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index d714942d5..81c4d1092 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -9,6 +9,7 @@ import PageContainer from "lib/components/PageContainer"; import { ErrorFetching, InvalidState } from "lib/components/state"; import { useProposalData, + useProposalParams, useProposalVotesInfo, } from "lib/services/proposalService"; @@ -26,6 +27,7 @@ const ProposalDetailsBody = ({ const { data, isLoading } = useProposalData(id); const { data: votesInfo, isLoading: isVotesInfoLoading } = useProposalVotesInfo(id); + const { data: params, isLoading: isParamsLoading } = useProposalParams(); const handleTabChange = useCallback( (nextTab: TabIndex) => () => { @@ -89,7 +91,8 @@ const ProposalDetailsBody = ({ From 4ed85e09957603d59d5eed60a9e3cfd258ffde5a Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 6 Feb 2024 14:11:01 +0700 Subject: [PATCH 069/531] feat: add countdown --- CHANGELOG.md | 2 +- src/lib/components/Markdown.tsx | 2 +- .../proposal-overview/ProposalDescription.tsx | 8 +-- .../status-summary/Countdown.tsx | 49 +++++++++++++ .../status-summary/SummaryStatusChip.tsx | 0 .../status-summary/SummaryStatusTime.tsx | 52 ++++++++++++++ .../status-summary/index.tsx | 53 +++++++++++--- src/lib/pages/proposal-details/data.ts | 72 +++++++++++++++++++ src/lib/pages/proposal-details/index.tsx | 8 ++- src/lib/services/proposal.ts | 2 +- src/lib/types/proposal.ts | 21 ++++-- src/lib/utils/date.ts | 10 +-- 12 files changed, 245 insertions(+), 34 deletions(-) create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx create mode 100644 src/lib/pages/proposal-details/data.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index e477e4f74..8ade62ce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features -- [#763](https://github.com/alleslabs/celatone-frontend/pull/763) Proposal status summary +- [#763](https://github.com/alleslabs/celatone-frontend/pull/763) Proposal status summary top - [#765](https://github.com/alleslabs/celatone-frontend/pull/765) Support Proposal Cancelled status - [#760](https://github.com/alleslabs/celatone-frontend/pull/760) Add proposal messages - [#764](https://github.com/alleslabs/celatone-frontend/pull/764) api v1 - proposal params diff --git a/src/lib/components/Markdown.tsx b/src/lib/components/Markdown.tsx index b11efe3bd..ee408eea5 100644 --- a/src/lib/components/Markdown.tsx +++ b/src/lib/components/Markdown.tsx @@ -152,7 +152,7 @@ export const Markdown = ({ markdown }: { markdown: string }) => { skipHtml remarkPlugins={[remarkGfm]} > - {markdown} + {markdown.replace(/\\n/g, "\n")} ); diff --git a/src/lib/pages/proposal-details/components/proposal-overview/ProposalDescription.tsx b/src/lib/pages/proposal-details/components/proposal-overview/ProposalDescription.tsx index 65b7b36bc..d36580a33 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/ProposalDescription.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/ProposalDescription.tsx @@ -19,13 +19,7 @@ export const ProposalDescription = ({ Not Provided ) : ( - + )} diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx new file mode 100644 index 000000000..a980045eb --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx @@ -0,0 +1,49 @@ +import { Spinner } from "@chakra-ui/react"; +import dayjs from "dayjs"; +import plur from "plur"; +import { useMemo, useState } from "react"; + +import { getCurrentDate } from "lib/utils"; + +const formatNumber = (num: number) => + num.toLocaleString("en-US", { + minimumIntegerDigits: 2, + useGrouping: false, + }); + +interface CountdownProps { + endTime: Date; +} + +export const Countdown = ({ endTime }: CountdownProps) => { + const [time, setTime] = useState(); + + useMemo(() => { + const currentTime = getCurrentDate(); + const diffTime = dayjs(endTime).diff(currentTime, "seconds"); + let duration = dayjs.duration(diffTime, "seconds"); + + const interval = 1000; + setInterval(() => { + duration = duration.subtract({ seconds: 1 }); + const days = duration.days(); + const timestamp = ( + <> + {days && ( + <> + {days} + {plur("day", days)} + + )} + + {duration.hours()}:{formatNumber(duration.minutes())}: + {formatNumber(duration.seconds())} + + + ); + setTime(timestamp); + }, interval); + }, [endTime]); + + return time; +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx new file mode 100644 index 000000000..ac235accf --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx @@ -0,0 +1,52 @@ +import { Text } from "@chakra-ui/react"; + +import type { ProposalData } from "lib/types"; +import { ProposalStatus } from "lib/types"; +import { formatUTC } from "lib/utils"; + +import { Countdown } from "./Countdown"; + +interface StatusTimeProps { + proposalData: ProposalData; +} + +const getResolvedPrefix = (status: ProposalStatus) => { + switch (status) { + case ProposalStatus.DEPOSIT_FAILED: + return "Failed on"; + case ProposalStatus.CANCELLED: + return "Cancelled on"; + default: + return "Voting ended on"; + } +}; + +export const SummaryStatusTime = ({ proposalData }: StatusTimeProps) => { + if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) + return ( + + Deposit ends in + + ); + + if (proposalData.status === ProposalStatus.VOTING_PERIOD) + return ( + + Voting ends in{" "} + {proposalData.votingEndTime ? ( + + ) : ( + "N/A" + )} + + ); + + return ( + + {getResolvedPrefix(proposalData.status)}{" "} + {proposalData.resolvedTimestamp + ? formatUTC(proposalData.resolvedTimestamp) + : "N/A"} + + ); +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx index c8a35619e..850b83b81 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx @@ -1,29 +1,60 @@ import { Flex, Text } from "@chakra-ui/react"; +import type { CSSProperties } from "react"; import type { ProposalOverviewProps } from ".."; import { StatusChip } from "lib/components/table"; import { ProposalStatus } from "lib/types"; import { ActiveDot } from "./ActiveDot"; +import { SummaryStatusTime } from "./SummaryStatusTime"; + +const getStatusSummaryBorderColor = ( + status: ProposalStatus +): CSSProperties["backgroundColor"] => { + switch (status) { + case ProposalStatus.DEPOSIT_PERIOD: + return "secondary.darker"; + case ProposalStatus.VOTING_PERIOD: + return "accent.main"; + case ProposalStatus.FAILED: + case ProposalStatus.REJECTED: + return "error.dark"; + case ProposalStatus.PASSED: + return "success.dark"; + case ProposalStatus.CANCELLED: + return "error.background"; + case ProposalStatus.DEPOSIT_FAILED: + default: + return "gray.700"; + } +}; export const StatusSummary = ({ proposalData }: ProposalOverviewProps) => { + const isOngoing = + proposalData.status === ProposalStatus.DEPOSIT_PERIOD || + proposalData.status === ProposalStatus.VOTING_PERIOD; return ( - - - - Current proposal result: - - + + + + + {isOngoing ? "Current" : "Final"} proposal result: + + + + ); diff --git a/src/lib/pages/proposal-details/data.ts b/src/lib/pages/proposal-details/data.ts new file mode 100644 index 000000000..2aa692ac3 --- /dev/null +++ b/src/lib/pages/proposal-details/data.ts @@ -0,0 +1,72 @@ +import { useAssetInfos } from "lib/services/assetService"; +import { useMovePoolInfos } from "lib/services/move"; +import { useProposalData } from "lib/services/proposalService"; +import type { Nullable, Option, ProposalData } from "lib/types"; +import { coinToTokenWithValue } from "lib/utils"; + +interface DerivedProposalDataResponse { + data: Option<{ + info: Nullable; + }>; + isLoading: boolean; +} + +export const useDerivedProposalData = ( + id: number +): DerivedProposalDataResponse => { + const { data, isLoading } = useProposalData(id); + const { data: assetInfos, isLoading: isAssetInfosLoading } = useAssetInfos({ + withPrices: false, + }); + const { data: movePoolInfos, isLoading: isMovePoolInfosLoading } = + useMovePoolInfos({ withPrices: false }); + + if (isLoading || isAssetInfosLoading || isMovePoolInfosLoading) + return { + data: undefined, + isLoading: isLoading || isAssetInfosLoading || isMovePoolInfosLoading, + }; + + if (!data) + return { + data: undefined, + isLoading: false, + }; + + if (!data.info) + return { + data: { + info: null, + }, + isLoading: false, + }; + + return { + data: { + info: { + ...data.info, + proposalDeposits: data.info.proposalDeposits.map((deposit) => ({ + ...deposit, + amount: deposit.amount.map((coin) => + coinToTokenWithValue( + coin.denom, + coin.amount, + assetInfos, + movePoolInfos + ) + ), + })), + totalDeposit: + data.info.totalDeposit?.map((coin) => + coinToTokenWithValue( + coin.denom, + coin.amount, + assetInfos, + movePoolInfos + ) + ) ?? null, + }, + }, + isLoading: false, + }; +}; diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index 81c4d1092..1a55456e7 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -2,18 +2,18 @@ import { TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"; import { useRouter } from "next/router"; import { useCallback, useEffect } from "react"; -import { useInternalNavigate } from "lib/app-provider"; +import { useGovConfig, useInternalNavigate } from "lib/app-provider"; import { CustomTab } from "lib/components/CustomTab"; import { Loading } from "lib/components/Loading"; import PageContainer from "lib/components/PageContainer"; import { ErrorFetching, InvalidState } from "lib/components/state"; import { - useProposalData, useProposalParams, useProposalVotesInfo, } from "lib/services/proposalService"; import { ProposalTop, ProposalOverview, VoteDetail } from "./components"; +import { useDerivedProposalData } from "./data"; import type { ProposalDetailsQueryParams } from "./type"; import { zProposalDetailsQueryParams, TabIndex } from "./type"; @@ -22,9 +22,11 @@ const ProposalDetailsBody = ({ tab, // voteTab, }: ProposalDetailsQueryParams) => { + useGovConfig({ shouldRedirect: true }); + const router = useRouter(); const navigate = useInternalNavigate(); - const { data, isLoading } = useProposalData(id); + const { data, isLoading } = useDerivedProposalData(id); const { data: votesInfo, isLoading: isVotesInfoLoading } = useProposalVotesInfo(id); const { data: params, isLoading: isParamsLoading } = useProposalParams(); diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index eb0ee1d62..33bce99a0 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -222,7 +222,7 @@ const zProposalDataResponse = z.object({ version: z.string(), voting_time: zUtcDate.nullable(), }) - .transform( + .transform>( ({ created_tx_hash, proposal_deposits, messages, ...val }) => ({ ...snakeToCamel(val), createdTxHash: created_tx_hash ? parseTxHash(created_tx_hash) : null, diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index f57d51328..ba18ffd35 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -2,7 +2,13 @@ import type { Coin } from "@cosmjs/amino"; import type Big from "big.js"; import { z } from "zod"; -import type { BechAddr, Nullable, Option, Validator } from "lib/types"; +import type { + BechAddr, + Nullable, + Option, + TokenWithValue, + Validator, +} from "lib/types"; export enum ProposalStatus { DEPOSIT_PERIOD = "DepositPeriod", @@ -89,8 +95,10 @@ export interface ProposalParams { emergencyTallyInterval?: string; } -export interface ProposalDeposit { - amount: Coin[]; +export interface ProposalDeposit< + T extends Coin | TokenWithValue = TokenWithValue, +> { + amount: T[]; depositor: BechAddr; timestamp: Date; txHash: string; @@ -102,17 +110,18 @@ interface Message { [key: string]: unknown; } -export interface ProposalData extends Proposal { +export interface ProposalData + extends Proposal { createdHeight: Nullable; createdTimestamp: Nullable; createdTxHash: Nullable; description: string; messages: Nullable; metadata: string; - proposalDeposits: ProposalDeposit[]; + proposalDeposits: ProposalDeposit[]; resolvedTimestamp: Nullable; submitTime: Date; - totalDeposit: Nullable; + totalDeposit: Nullable; version: string; votingTime: Nullable; } diff --git a/src/lib/utils/date.ts b/src/lib/utils/date.ts index 22fb49c85..c95670607 100644 --- a/src/lib/utils/date.ts +++ b/src/lib/utils/date.ts @@ -1,15 +1,17 @@ import big from "big.js"; import dayjs from "dayjs"; -import relativeTime from "dayjs/plugin/relativeTime"; -import utc from "dayjs/plugin/utc"; +import pluginDuration from "dayjs/plugin/duration"; +import pluginRelativeTime from "dayjs/plugin/relativeTime"; +import pluginUtc from "dayjs/plugin/utc"; import plur from "plur"; import type { Option } from "lib/types"; import { isNumeric } from "./number"; -dayjs.extend(relativeTime); -dayjs.extend(utc); +dayjs.extend(pluginDuration); +dayjs.extend(pluginRelativeTime); +dayjs.extend(pluginUtc); export const getDefaultDate = (): Date => dayjs.utc(0).toDate(); From 556a9073b3ee29ebda7a089c1f41643d16ae9060 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 6 Feb 2024 14:21:06 +0700 Subject: [PATCH 070/531] fix: countdown --- .../status-summary/Countdown.tsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx index a980045eb..db2e8c636 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx @@ -1,5 +1,6 @@ import { Spinner } from "@chakra-ui/react"; import dayjs from "dayjs"; +import { useRouter } from "next/router"; import plur from "plur"; import { useMemo, useState } from "react"; @@ -16,16 +17,17 @@ interface CountdownProps { } export const Countdown = ({ endTime }: CountdownProps) => { + const router = useRouter(); const [time, setTime] = useState(); useMemo(() => { - const currentTime = getCurrentDate(); - const diffTime = dayjs(endTime).diff(currentTime, "seconds"); - let duration = dayjs.duration(diffTime, "seconds"); - - const interval = 1000; setInterval(() => { - duration = duration.subtract({ seconds: 1 }); + const diffTime = Math.max( + dayjs(endTime).diff(getCurrentDate(), "seconds"), + 0 + ); + + const duration = dayjs.duration(diffTime, "seconds"); const days = duration.days(); const timestamp = ( <> @@ -41,9 +43,10 @@ export const Countdown = ({ endTime }: CountdownProps) => { ); + if (diffTime === 0) router.reload(); setTime(timestamp); - }, interval); - }, [endTime]); + }, 1000); + }, [endTime, router]); return time; }; From 1ccf4203dc362e382195a3963d46a9cb9df52367 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 6 Feb 2024 14:22:57 +0700 Subject: [PATCH 071/531] fix: countdown --- .../proposal-overview/status-summary/Countdown.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx index db2e8c636..f2fe97a9b 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx @@ -23,11 +23,11 @@ export const Countdown = ({ endTime }: CountdownProps) => { useMemo(() => { setInterval(() => { const diffTime = Math.max( - dayjs(endTime).diff(getCurrentDate(), "seconds"), - 0 + 0, + dayjs(endTime).diff(getCurrentDate(), "seconds") ); - const duration = dayjs.duration(diffTime, "seconds"); + const days = duration.days(); const timestamp = ( <> From 4fa9a2a9661aa6b73bdd31f5b57c3196bc71a90e Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 6 Feb 2024 14:48:00 +0700 Subject: [PATCH 072/531] fix: date --- .../status-summary/SummaryStatusTime.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx index ac235accf..e4dcd835f 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx @@ -13,11 +13,11 @@ interface StatusTimeProps { const getResolvedPrefix = (status: ProposalStatus) => { switch (status) { case ProposalStatus.DEPOSIT_FAILED: - return "Failed on"; + return "Failed"; case ProposalStatus.CANCELLED: - return "Cancelled on"; + return "Cancelled"; default: - return "Voting ended on"; + return "Voting ended"; } }; @@ -43,7 +43,8 @@ export const SummaryStatusTime = ({ proposalData }: StatusTimeProps) => { return ( - {getResolvedPrefix(proposalData.status)}{" "} + {getResolvedPrefix(proposalData.status)} + {" at "} {proposalData.resolvedTimestamp ? formatUTC(proposalData.resolvedTimestamp) : "N/A"} From 955822b0d270ebbdf27bf43f574e764b3f8faed3 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Tue, 6 Feb 2024 16:00:35 +0700 Subject: [PATCH 073/531] test(utils): add testing fee validation --- src/lib/utils/fee.test.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/lib/utils/fee.test.ts diff --git a/src/lib/utils/fee.test.ts b/src/lib/utils/fee.test.ts new file mode 100644 index 000000000..01c950d14 --- /dev/null +++ b/src/lib/utils/fee.test.ts @@ -0,0 +1,30 @@ +import { feeFromStr } from "./fee"; + +describe("fee validation", () => { + test("standard case", () => { + const fee = feeFromStr("10000uosmo"); + + expect(fee).toEqual({ + amount: [{ denom: "uosmo", amount: "10000" }], + gas: "0", + }); + }); + + test("undefined input handling", () => { + const fee = feeFromStr(undefined); + + expect(fee).toBeUndefined(); + }); + + test("multiple coin types", () => { + const fee = feeFromStr("10000uosmo,89999ustake"); + + expect(fee).toEqual({ + amount: [ + { denom: "uosmo", amount: "10000" }, + { denom: "ustake", amount: "89999" }, + ], + gas: "0", + }); + }); +}); From 37cd68504a184586e2673e6a6ae48badd3b6b944 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Tue, 6 Feb 2024 16:04:51 +0700 Subject: [PATCH 074/531] docs(utils): update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b0b1e4f7..9ff356795 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#767](https://github.com/alleslabs/celatone-frontend/pull/767) Add test validation for Fee.ts - [#756](https://github.com/alleslabs/celatone-frontend/pull/756) Redirect usei to homepage - [#750](https://github.com/alleslabs/celatone-frontend/pull/750) api v1 - recent codes list - [#752](https://github.com/alleslabs/celatone-frontend/pull/752) Support contract state's key as base64 From c3c56216adffd45f559a14f76d897a9564112f82 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Tue, 6 Feb 2024 16:27:19 +0700 Subject: [PATCH 075/531] test(utils): add unit test for truncate util function --- src/lib/utils/truncate.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/lib/utils/truncate.test.ts diff --git a/src/lib/utils/truncate.test.ts b/src/lib/utils/truncate.test.ts new file mode 100644 index 000000000..410d3b897 --- /dev/null +++ b/src/lib/utils/truncate.test.ts @@ -0,0 +1,18 @@ +import { truncate } from "./truncate"; + +describe("truncate validation", () => { + test("standard case", () => { + const result = truncate("osmo102cykl9ng6m9e7ytku25r632shfdk3ux4eayz4"); + + expect(result).toBe("osmo10...4eayz4"); + }); + + test("custom head and tail length", () => { + const result = truncate( + "osmo102cykl9ng6m9e7ytku25r632shfdk3ux4eayz4", + [10, 4] + ); + + expect(result).toBe("osmo102cyk...ayz4"); + }); +}); From e1ce7133e314637f6b06fcdc6ecb8e4c6e39caac Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Tue, 6 Feb 2024 16:31:43 +0700 Subject: [PATCH 076/531] docs: update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca6f2a59d..07dbd4fea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,7 +53,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements -- [#767](https://github.com/alleslabs/celatone-frontend/pull/767) Add test validation for Fee.ts +- [#768](https://github.com/alleslabs/celatone-frontend/pull/768) Add unit test for truncate.test.ts +- [#767](https://github.com/alleslabs/celatone-frontend/pull/767) Add unit test for fee.test.ts - [#756](https://github.com/alleslabs/celatone-frontend/pull/756) Redirect usei to homepage - [#750](https://github.com/alleslabs/celatone-frontend/pull/750) api v1 - recent codes list - [#752](https://github.com/alleslabs/celatone-frontend/pull/752) Support contract state's key as base64 From 1b2692ba1d82307430a277f28acafb9f97c44e8c Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Tue, 6 Feb 2024 16:40:32 +0700 Subject: [PATCH 077/531] test(utils): add unit test for format.test.ts on shorten name function --- CHANGELOG.md | 1 + src/lib/utils/format.test.ts | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/lib/utils/format.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 07dbd4fea..79a8c2933 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#769](https://github.com/alleslabs/celatone-frontend/pull/768) Add unit test for format.test.ts on shortenName function - [#768](https://github.com/alleslabs/celatone-frontend/pull/768) Add unit test for truncate.test.ts - [#767](https://github.com/alleslabs/celatone-frontend/pull/767) Add unit test for fee.test.ts - [#756](https://github.com/alleslabs/celatone-frontend/pull/756) Redirect usei to homepage diff --git a/src/lib/utils/format.test.ts b/src/lib/utils/format.test.ts new file mode 100644 index 000000000..112039515 --- /dev/null +++ b/src/lib/utils/format.test.ts @@ -0,0 +1,21 @@ +import { shortenName } from "./format"; + +describe("shortenName validation", () => { + test("standard case", () => { + const name = shortenName("Generate my sentence"); + + expect(name).toBe("Generate m..."); + }); + + test("custom truncate length", () => { + const name = shortenName("Hello World!", 5); + + expect(name).toBe("Hello..."); + }); + + test("custom truncate length with longer than input string", () => { + const name = shortenName("Hello", 20); + + expect(name).toBe("Hello"); + }); +}); From 213a9f6688d22edb1068ac0767ab5618c5524525 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Wed, 7 Feb 2024 10:14:46 +0700 Subject: [PATCH 078/531] docs: update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79a8c2933..a69012617 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,7 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements -- [#769](https://github.com/alleslabs/celatone-frontend/pull/768) Add unit test for format.test.ts on shortenName function +- [#769](https://github.com/alleslabs/celatone-frontend/pull/769) Add unit test for format.test.ts on shortenName function - [#768](https://github.com/alleslabs/celatone-frontend/pull/768) Add unit test for truncate.test.ts - [#767](https://github.com/alleslabs/celatone-frontend/pull/767) Add unit test for fee.test.ts - [#756](https://github.com/alleslabs/celatone-frontend/pull/756) Redirect usei to homepage From 5572fce1bade14e912efa466f391af8a125a5efb Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:24:32 +0700 Subject: [PATCH 079/531] feat: add detail body --- .../components/table/proposals/StatusChip.tsx | 8 +- .../__stories__/StatusChip.stories.ts | 7 + .../status-summary/ActiveDot.tsx | 4 +- .../status-summary/Countdown.tsx | 4 +- .../status-summary/SummaryStatusBody.tsx | 44 ++++++ .../status-summary/SummaryStatusChip.tsx | 51 +++++++ .../status-summary/index.tsx | 9 +- .../components/proposal-top/index.tsx | 30 ++-- src/lib/pages/proposal-details/data.ts | 64 ++++++++- src/lib/pages/proposal-details/index.tsx | 10 +- src/lib/pages/proposal-details/utils.ts | 54 ++++++++ src/lib/services/proposal.ts | 6 +- src/lib/services/proposalService.ts | 3 +- src/lib/types/proposal.ts | 12 +- src/lib/utils/assetValue.ts | 6 + .../formatter/formatTokenWithValue.test.ts | 129 ++++++++++++++++++ .../utils/formatter/formatTokenWithValue.ts | 10 ++ 17 files changed, 412 insertions(+), 39 deletions(-) create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx create mode 100644 src/lib/pages/proposal-details/utils.ts create mode 100644 src/lib/utils/formatter/formatTokenWithValue.test.ts diff --git a/src/lib/components/table/proposals/StatusChip.tsx b/src/lib/components/table/proposals/StatusChip.tsx index e8a2261ac..d3a0b51b7 100644 --- a/src/lib/components/table/proposals/StatusChip.tsx +++ b/src/lib/components/table/proposals/StatusChip.tsx @@ -28,9 +28,11 @@ const getBgColor = ( export const StatusChip = ({ status, + isTransparent = false, hasCloseBtn = false, }: { status: Proposal["status"]; + isTransparent?: boolean; hasCloseBtn?: boolean; }) => { const formatStatus = @@ -38,7 +40,11 @@ export const StatusChip = ({ ? "Deposit Failed" : status.replace(/([A-Z])/g, " $1").trim(); return ( - + {formatStatus} {hasCloseBtn && } diff --git a/src/lib/components/table/proposals/__stories__/StatusChip.stories.ts b/src/lib/components/table/proposals/__stories__/StatusChip.stories.ts index c44067dc8..c96fc9510 100644 --- a/src/lib/components/table/proposals/__stories__/StatusChip.stories.ts +++ b/src/lib/components/table/proposals/__stories__/StatusChip.stories.ts @@ -20,6 +20,13 @@ export const NormalChip: Story = { }, }; +export const TransparentChip: Story = { + args: { + status: ProposalStatus.DEPOSIT_PERIOD, + isTransparent: true, + }, +}; + export const FilterChip: Story = { args: { status: ProposalStatus.DEPOSIT_PERIOD, diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx index eb3de85eb..acff34b22 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx @@ -12,10 +12,10 @@ export const ActiveDot = ({ status }: ActiveDotProps) => boxSize={3} borderRadius="50%" bgColor="accent.main" - animate={{ opacity: [1, 0, 1] }} + animate={{ opacity: [1, 0.25, 1] }} // @ts-expect-error no problem in operation, although type error appears. transition={{ - duration: 1, + duration: 1.5, repeat: Infinity, }} /> diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx index f2fe97a9b..310b139a8 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx @@ -18,7 +18,9 @@ interface CountdownProps { export const Countdown = ({ endTime }: CountdownProps) => { const router = useRouter(); - const [time, setTime] = useState(); + const [time, setTime] = useState( + + ); useMemo(() => { setInterval(() => { diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx new file mode 100644 index 000000000..c62589bb0 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx @@ -0,0 +1,44 @@ +import { Text } from "@chakra-ui/react"; +import type Big from "big.js"; + +import type { ProposalOverviewProps } from ".."; +import { ErrorFetching } from "lib/components/state"; +import { extractParams, mapDeposit } from "lib/pages/proposal-details/utils"; +import type { Token, TokenWithValue, U } from "lib/types"; +import { ProposalStatus } from "lib/types"; +import { formatTokenWithValueList } from "lib/utils"; + +export const SummaryStatusBody = ({ + proposalData, + params, + votesInfo, +}: ProposalOverviewProps) => { + if (!params || !votesInfo) + return ; + + const { minDeposit } = extractParams(params, proposalData.isExpedited); + + if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) { + const required = mapDeposit(proposalData.totalDeposit, minDeposit).reduce< + TokenWithValue[] + >((prev, pair) => { + if (pair.current.amount.lt(pair.min.amount)) + prev.push({ + ...pair.min, + amount: pair.min.amount.sub(pair.current.amount) as U>, + }); + return prev; + }, []); + + return ( + + The proposal is currently in the deposit period and requires an + additional deposit of {formatTokenWithValueList(required)} to advance to + the voting period. Failure to make the required deposit will result in + the rejection of the proposal. + + ); + } + + return Detail; +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx index e69de29bb..b5ea91163 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx @@ -0,0 +1,51 @@ +import { Spinner, Text } from "@chakra-ui/react"; + +import type { ProposalOverviewProps } from ".."; +import { StatusChip } from "lib/components/table"; +import { + extractParams, + normalizeVotesInfo, +} from "lib/pages/proposal-details/utils"; +import { ProposalStatus } from "lib/types"; + +export const SummaryStatusChip = ({ + proposalData, + params, + votesInfo, + isLoading, +}: ProposalOverviewProps) => { + if (isLoading) return ; + + if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) + return ; + + if (proposalData.status === ProposalStatus.VOTING_PERIOD) { + if (!params || !votesInfo) + return ( + + N/A + + ); + + const { yes, noWithVeto, currentTotalVotes } = + normalizeVotesInfo(votesInfo); + const { quorum, threshold, vetoThreshold } = extractParams( + params, + proposalData.isExpedited + ); + return ( + + ); + } + + return ; +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx index 850b83b81..73583a11c 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx @@ -2,10 +2,10 @@ import { Flex, Text } from "@chakra-ui/react"; import type { CSSProperties } from "react"; import type { ProposalOverviewProps } from ".."; -import { StatusChip } from "lib/components/table"; import { ProposalStatus } from "lib/types"; import { ActiveDot } from "./ActiveDot"; +import { SummaryStatusChip } from "./SummaryStatusChip"; import { SummaryStatusTime } from "./SummaryStatusTime"; const getStatusSummaryBorderColor = ( @@ -29,7 +29,10 @@ const getStatusSummaryBorderColor = ( } }; -export const StatusSummary = ({ proposalData }: ProposalOverviewProps) => { +export const StatusSummary = ({ + proposalData, + ...props +}: ProposalOverviewProps) => { const isOngoing = proposalData.status === ProposalStatus.DEPOSIT_PERIOD || proposalData.status === ProposalStatus.VOTING_PERIOD; @@ -52,7 +55,7 @@ export const StatusSummary = ({ proposalData }: ProposalOverviewProps) => { {isOngoing ? "Current" : "Final"} proposal result: - + diff --git a/src/lib/pages/proposal-details/components/proposal-top/index.tsx b/src/lib/pages/proposal-details/components/proposal-top/index.tsx index 65041c9a5..5bfeca15b 100644 --- a/src/lib/pages/proposal-details/components/proposal-top/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-top/index.tsx @@ -3,6 +3,7 @@ import { Button, Flex, Heading, Text } from "@chakra-ui/react"; import { useBaseApiRoute, useMobile } from "lib/app-provider"; import { Breadcrumb } from "lib/components/Breadcrumb"; import { DotSeparator } from "lib/components/DotSeparator"; +import { Expedited } from "lib/components/Expedited"; import { ExplorerLink } from "lib/components/ExplorerLink"; import { CustomIcon } from "lib/components/icon"; import type { ProposalData } from "lib/types"; @@ -37,31 +38,32 @@ export const ProposalTop = ({ proposalData }: ProposalTopProps) => { direction={{ base: "column", md: "row" }} > - + - + #{proposalData.id} - {" "} + {" "} - {proposalData.title ? proposalData.title : "No title"} + {proposalData.isExpedited && ( + + + + )} diff --git a/src/lib/pages/proposal-details/data.ts b/src/lib/pages/proposal-details/data.ts index 2aa692ac3..677b20c45 100644 --- a/src/lib/pages/proposal-details/data.ts +++ b/src/lib/pages/proposal-details/data.ts @@ -1,8 +1,66 @@ import { useAssetInfos } from "lib/services/assetService"; import { useMovePoolInfos } from "lib/services/move"; -import { useProposalData } from "lib/services/proposalService"; -import type { Nullable, Option, ProposalData } from "lib/types"; -import { coinToTokenWithValue } from "lib/utils"; +import { + useProposalData, + useProposalParams, +} from "lib/services/proposalService"; +import type { Nullable, Option, ProposalData, ProposalParams } from "lib/types"; +import { coinToTokenWithValue, compareTokenWithValues } from "lib/utils"; + +export const useDerivedProposalParams = (): { + data: Option; + isLoading: boolean; +} => { + const { data, isLoading } = useProposalParams(); + const { data: assetInfos, isLoading: isAssetInfosLoading } = useAssetInfos({ + withPrices: false, + }); + const { data: movePoolInfos, isLoading: isMovePoolInfosLoading } = + useMovePoolInfos({ withPrices: false }); + + if (isLoading || isAssetInfosLoading || isMovePoolInfosLoading || !data) + return { + data: undefined, + isLoading: isLoading || isAssetInfosLoading || isMovePoolInfosLoading, + }; + + return { + data: { + ...data, + minDeposit: data.minDeposit + .map((coin) => + coinToTokenWithValue( + coin.denom, + coin.amount, + assetInfos, + movePoolInfos + ) + ) + .sort(compareTokenWithValues), + expeditedMinDeposit: data.expeditedMinDeposit + ?.map((coin) => + coinToTokenWithValue( + coin.denom, + coin.amount, + assetInfos, + movePoolInfos + ) + ) + .sort(compareTokenWithValues), + emergencyMinDeposit: data.emergencyMinDeposit + ?.map((coin) => + coinToTokenWithValue( + coin.denom, + coin.amount, + assetInfos, + movePoolInfos + ) + ) + .sort(compareTokenWithValues), + }, + isLoading: false, + }; +}; interface DerivedProposalDataResponse { data: Option<{ diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index 1a55456e7..ec349a5c5 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -7,13 +7,10 @@ import { CustomTab } from "lib/components/CustomTab"; import { Loading } from "lib/components/Loading"; import PageContainer from "lib/components/PageContainer"; import { ErrorFetching, InvalidState } from "lib/components/state"; -import { - useProposalParams, - useProposalVotesInfo, -} from "lib/services/proposalService"; +import { useProposalVotesInfo } from "lib/services/proposalService"; import { ProposalTop, ProposalOverview, VoteDetail } from "./components"; -import { useDerivedProposalData } from "./data"; +import { useDerivedProposalData, useDerivedProposalParams } from "./data"; import type { ProposalDetailsQueryParams } from "./type"; import { zProposalDetailsQueryParams, TabIndex } from "./type"; @@ -29,7 +26,8 @@ const ProposalDetailsBody = ({ const { data, isLoading } = useDerivedProposalData(id); const { data: votesInfo, isLoading: isVotesInfoLoading } = useProposalVotesInfo(id); - const { data: params, isLoading: isParamsLoading } = useProposalParams(); + const { data: params, isLoading: isParamsLoading } = + useDerivedProposalParams(); const handleTabChange = useCallback( (nextTab: TabIndex) => () => { diff --git a/src/lib/pages/proposal-details/utils.ts b/src/lib/pages/proposal-details/utils.ts new file mode 100644 index 000000000..b68824aff --- /dev/null +++ b/src/lib/pages/proposal-details/utils.ts @@ -0,0 +1,54 @@ +import type Big from "big.js"; +import big from "big.js"; + +import type { + Nullable, + ProposalParams, + ProposalVotesInfo, + Token, + TokenWithValue, + U, +} from "lib/types"; + +export const normalizeVotesInfo = (votesInfo: ProposalVotesInfo) => { + const yes = votesInfo.yes.div(votesInfo.totalVotingPower); + const abstain = votesInfo.abstain.div(votesInfo.totalVotingPower); + const no = votesInfo.no.div(votesInfo.totalVotingPower); + const noWithVeto = votesInfo.noWithVeto.div(votesInfo.totalVotingPower); + + return { + yes, + abstain, + no, + noWithVeto, + currentTotalVotes: yes.add(abstain).add(no).add(noWithVeto), + }; +}; + +export const extractParams = ( + params: ProposalParams, + isExpedited: boolean +) => ({ + minDeposit: (isExpedited && params.expeditedMinDeposit) || params.minDeposit, + quorum: (isExpedited && params.expeditedQuorum) || params.quorum, + threshold: (isExpedited && params.expeditedThreshold) || params.threshold, + vetoThreshold: params.vetoThreshold, +}); + +export const mapDeposit = ( + deposit: Nullable, + minDeposit: TokenWithValue[] +) => + minDeposit.map((min) => { + const current: TokenWithValue = deposit?.find( + (token) => token.denom === min.denom + ) ?? { + ...min, + amount: big(0) as U>, + }; + + return { + current, + min, + }; + }); diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 33bce99a0..4fa226606 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -92,16 +92,16 @@ const zProposalParamsResponse = z expedited_voting_period: z.string().optional(), expedited_threshold: z.coerce.number().optional(), expedited_min_deposit: zCoin.array().optional(), - expedited_quorum: z.string().optional(), // only in sei + expedited_quorum: z.coerce.number().optional(), // only in sei // emergency - only in initia emergency_min_deposit: zCoin.array().optional(), emergency_tally_interval: z.string().optional(), }) - .transform(snakeToCamel); + .transform>(snakeToCamel); export const getProposalParams = async ( endpoint: string -): Promise => +): Promise> => axios .get(`${endpoint}/params`) .then(({ data }) => zProposalParamsResponse.parse(data)); diff --git a/src/lib/services/proposalService.ts b/src/lib/services/proposalService.ts index 44bdb0835..e867de4ad 100644 --- a/src/lib/services/proposalService.ts +++ b/src/lib/services/proposalService.ts @@ -1,3 +1,4 @@ +import type { Coin } from "@cosmjs/amino"; import type { UseQueryResult } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query"; import type { Big } from "big.js"; @@ -99,7 +100,7 @@ export const useProposals = ( export const useProposalParams = () => { const endpoint = useBaseApiRoute("proposals"); - return useQuery( + return useQuery>( [CELATONE_QUERY_KEYS.PROPOSAL_PARAMS, endpoint], async () => getProposalParams(endpoint), { retry: 1, refetchOnWindowFocus: false } diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index ba18ffd35..846a11df7 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -77,8 +77,10 @@ export interface Proposal { isExpedited: boolean; } -export interface ProposalParams { - minDeposit: Coin[]; +export interface ProposalParams< + T extends Coin | TokenWithValue = TokenWithValue, +> { + minDeposit: T[]; minInitialDepositRatio: number; maxDepositPeriod: string; votingPeriod: string; @@ -88,10 +90,10 @@ export interface ProposalParams { // expedited expeditedVotingPeriod?: string; expeditedThreshold?: number; - expeditedMinDeposit?: Coin[]; - expeditedQuorum?: string; // only in sei + expeditedMinDeposit?: T[]; + expeditedQuorum?: number; // only in sei // emergency - only in initia - emergencyMinDeposit?: Coin[]; + emergencyMinDeposit?: T[]; emergencyTallyInterval?: string; } diff --git a/src/lib/utils/assetValue.ts b/src/lib/utils/assetValue.ts index 5fd89a2ee..af52fa36e 100644 --- a/src/lib/utils/assetValue.ts +++ b/src/lib/utils/assetValue.ts @@ -145,5 +145,11 @@ export const compareTokenWithValues = ( if (token1.value && token2.value) return token2.value.cmp(token1.value); if (token1.value && !token2.value) return -1; if (!token1.value && token2.value) return 1; + + if (token1.symbol && token2.symbol) + return token1.symbol.localeCompare(token2.symbol); + if (token1.symbol && !token2.symbol) return -1; + if (!token1.symbol && token2.symbol) return 1; + return token1.denom.localeCompare(token2.denom); }; diff --git a/src/lib/utils/formatter/formatTokenWithValue.test.ts b/src/lib/utils/formatter/formatTokenWithValue.test.ts new file mode 100644 index 000000000..f4ee78ada --- /dev/null +++ b/src/lib/utils/formatter/formatTokenWithValue.test.ts @@ -0,0 +1,129 @@ +import big from "big.js"; + +import type { Token, TokenWithValue, U } from "lib/types"; + +import { + formatTokenWithValue, + formatTokenWithValueList, +} from "./formatTokenWithValue"; + +describe("formatTokenWithValue", () => { + test("coin only", () => { + const token: TokenWithValue = { + isLPToken: false, + amount: big(1000000) as U>, + denom: "denom", + symbol: undefined, + precision: undefined, + price: undefined, + value: undefined, + logo: undefined, + }; + + expect(formatTokenWithValue(token)).toBe("1,000,000 denom"); + expect(formatTokenWithValue(token, 2)).toBe("1,000,000.00 denom"); + }); + + test("coin with precision", () => { + const token: TokenWithValue = { + isLPToken: false, + amount: big(1000000) as U>, + denom: "denom", + symbol: undefined, + precision: 6, + price: undefined, + value: undefined, + logo: undefined, + }; + + expect(formatTokenWithValue(token)).toBe("1.000000 denom"); + expect(formatTokenWithValue(token, 2)).toBe("1.00 denom"); + }); + + test("coin with symbol", () => { + const token: TokenWithValue = { + isLPToken: false, + amount: big(1000000) as U>, + denom: "denom", + symbol: "CLTN", + precision: undefined, + price: undefined, + value: undefined, + logo: undefined, + }; + + expect(formatTokenWithValue(token)).toBe("1,000,000 CLTN"); + expect(formatTokenWithValue(token, 2)).toBe("1,000,000.00 CLTN"); + }); + + test("coin with precision and symbol", () => { + const token: TokenWithValue = { + isLPToken: false, + amount: big(1000000) as U>, + denom: "denom", + symbol: "CLTN", + precision: 6, + price: undefined, + value: undefined, + logo: undefined, + }; + + expect(formatTokenWithValue(token)).toBe("1.000000 CLTN"); + expect(formatTokenWithValue(token, 2)).toBe("1.00 CLTN"); + }); +}); + +describe("formatTokenWithValueList", () => { + const tokens: TokenWithValue[] = [ + { + isLPToken: false, + amount: big(1000000) as U>, + denom: "denom1", + symbol: "CLTN1", + precision: 6, + price: undefined, + value: undefined, + logo: undefined, + }, + { + isLPToken: false, + amount: big(2000000) as U>, + denom: "denom2", + symbol: "CLTN2", + precision: 6, + price: undefined, + value: undefined, + logo: undefined, + }, + { + isLPToken: false, + amount: big(3000000) as U>, + denom: "denom3", + symbol: "CLTN3", + precision: 6, + price: undefined, + value: undefined, + logo: undefined, + }, + ]; + + test("empty array", () => { + expect(formatTokenWithValueList([])).toBe(""); + }); + + test("1 token", () => { + expect(formatTokenWithValueList(tokens.slice(0, 1))).toBe("1.00 CLTN1"); + }); + + test("2 tokens", () => { + expect(formatTokenWithValueList(tokens.slice(0, 2))).toBe( + "1.00 CLTN1 and 2.00 CLTN2" + ); + }); + + test("more than 2 tokens", () => { + expect(formatTokenWithValueList(tokens)).toBe( + "1.00 CLTN1, 2.00 CLTN2, and 3.00 CLTN3" + ); + }); +}); diff --git a/src/lib/utils/formatter/formatTokenWithValue.ts b/src/lib/utils/formatter/formatTokenWithValue.ts index d1e2980d1..0519e732f 100644 --- a/src/lib/utils/formatter/formatTokenWithValue.ts +++ b/src/lib/utils/formatter/formatTokenWithValue.ts @@ -13,3 +13,13 @@ export const formatTokenWithValue = ( false, decimalPoints )} ${getTokenLabel(token.denom, token.symbol)}`; + +export const formatTokenWithValueList = (tokens: TokenWithValue[]) => { + if (tokens.length <= 2) + return tokens.map((token) => formatTokenWithValue(token, 2)).join(" and "); + + return `${tokens + .slice(0, -1) + .map((token) => formatTokenWithValue(token, 2)) + .join(", ")}, and ${formatTokenWithValue(tokens[tokens.length - 1], 2)}`; +}; From f817d91016593edb93fc28bbcb888be5f2dac84a Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:44:32 +0700 Subject: [PATCH 080/531] fix: clear interval --- .../proposal-overview/status-summary/Countdown.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx index f2fe97a9b..8685c0903 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx @@ -2,7 +2,7 @@ import { Spinner } from "@chakra-ui/react"; import dayjs from "dayjs"; import { useRouter } from "next/router"; import plur from "plur"; -import { useMemo, useState } from "react"; +import { useEffect, useState } from "react"; import { getCurrentDate } from "lib/utils"; @@ -20,8 +20,8 @@ export const Countdown = ({ endTime }: CountdownProps) => { const router = useRouter(); const [time, setTime] = useState(); - useMemo(() => { - setInterval(() => { + useEffect(() => { + const intervalId = setInterval(() => { const diffTime = Math.max( 0, dayjs(endTime).diff(getCurrentDate(), "seconds") @@ -46,6 +46,7 @@ export const Countdown = ({ endTime }: CountdownProps) => { if (diffTime === 0) router.reload(); setTime(timestamp); }, 1000); + return () => clearInterval(intervalId); }, [endTime, router]); return time; From 86a8796b1a11c6b570cb342c297cf27dee783450 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Wed, 7 Feb 2024 13:43:32 +0700 Subject: [PATCH 081/531] test(utils): add unit test for account store (mobx) --- src/lib/stores/account.test.ts | 67 ++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/lib/stores/account.test.ts diff --git a/src/lib/stores/account.test.ts b/src/lib/stores/account.test.ts new file mode 100644 index 000000000..d4e50e404 --- /dev/null +++ b/src/lib/stores/account.test.ts @@ -0,0 +1,67 @@ +import { zBechAddr } from "lib/types"; + +import { AccountStore } from "./account"; + +jest.mock("mobx-persist-store", () => ({ + isHydrated: jest.fn().mockReturnValue(true), + makePersistable: jest.fn(), +})); + +describe("accountStore", () => { + let accountStore: AccountStore; + + beforeEach(() => { + accountStore = new AccountStore(); + }); + + test("user key management", () => { + expect(accountStore.isAccountUserKeyExist()).toBeFalsy(); + + accountStore.setAccountUserKey("user-key"); + + expect(accountStore.isAccountUserKeyExist()).toBeTruthy(); + }); + + test("account info", () => { + expect( + accountStore.getAccountLocalInfo(zBechAddr.parse("address")) + ).toBeUndefined(); + + accountStore.updateAccountLocalInfo( + zBechAddr.parse("address"), + "name", + "description" + ); + + expect( + accountStore.getAccountLocalInfo(zBechAddr.parse("address")) + ).toEqual({ + address: zBechAddr.parse("address"), + name: "name", + description: "description", + }); + }); + + test("saved account", () => { + expect(accountStore.savedAccounts).toEqual({}); + expect(accountStore.isAccountSaved(zBechAddr.parse("address"))).toBeFalsy(); + + accountStore.updateAccountLocalInfo( + zBechAddr.parse("address"), + "name", + "description" + ); + + expect( + accountStore.isAccountSaved(zBechAddr.parse("address")) + ).toBeTruthy(); + + expect(accountStore.getSavedAccounts()).toEqual([ + { + address: zBechAddr.parse("address"), + name: "name", + description: "description", + }, + ]); + }); +}); From 7db7f82dfb9d1fa1ac8c977ede38f113f2975827 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Wed, 7 Feb 2024 13:45:43 +0700 Subject: [PATCH 082/531] fix(components): adjust proposal detail --- CHANGELOG.md | 1 + src/lib/components/json/JsonInfo.tsx | 6 +-- .../components/proposal-info/TimeInfoItem.tsx | 40 ++++++++++++------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a69012617..eea9400cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#770](https://github.com/alleslabs/celatone-frontend/pull/770) Adjust proposal detail - [#769](https://github.com/alleslabs/celatone-frontend/pull/769) Add unit test for format.test.ts on shortenName function - [#768](https://github.com/alleslabs/celatone-frontend/pull/768) Add unit test for truncate.test.ts - [#767](https://github.com/alleslabs/celatone-frontend/pull/767) Add unit test for fee.test.ts diff --git a/src/lib/components/json/JsonInfo.tsx b/src/lib/components/json/JsonInfo.tsx index 7106a8c16..135aa68fe 100644 --- a/src/lib/components/json/JsonInfo.tsx +++ b/src/lib/components/json/JsonInfo.tsx @@ -1,4 +1,4 @@ -import { Flex, Heading } from "@chakra-ui/react"; +import { Flex, Text } from "@chakra-ui/react"; import { useState } from "react"; import { CustomIcon } from "../icon"; @@ -31,9 +31,9 @@ export const JsonInfo = ({ cursor="pointer" onClick={() => setExpand((prev) => !prev)} > - + {header} - + { switch (data.status) { case ProposalStatus.DEPOSIT_PERIOD: return ( - - - {data.submitTime && data.depositEndTime - ? `${formatUTC(data.submitTime)} - ${formatUTC(data.depositEndTime)}` - : "N/A"} - - + <> + + + {data.submitTime ? `${formatUTC(data.submitTime)}` : "N/A"} + + + + + {data.depositEndTime + ? `${formatUTC(data.depositEndTime)}` + : "N/A"} + + + ); case ProposalStatus.DEPOSIT_FAILED: return ( @@ -66,13 +73,18 @@ export const TimeInfoItem = ({ data }: TimeInfoItemProps) => { ); case ProposalStatus.VOTING_PERIOD: return ( - - - {data.votingTime && data.votingEndTime - ? `${formatUTC(data.votingTime)} - ${formatUTC(data.votingEndTime)}` - : "N/A"} - - + <> + + + {data.votingTime ? `${formatUTC(data.votingTime)}` : "N/A"} + + + + + {data.votingEndTime ? `${formatUTC(data.votingEndTime)}` : "N/A"} + + + ); case ProposalStatus.PASSED: case ProposalStatus.FAILED: From 076e024e0c935bd2d26cb6a55c6e463e78d0da3c Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Wed, 7 Feb 2024 13:47:58 +0700 Subject: [PATCH 083/531] docs: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a69012617..9385b17a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#770](https://github.com/alleslabs/celatone-frontend/pull/770) Add unit test for account store (mobx) - [#769](https://github.com/alleslabs/celatone-frontend/pull/769) Add unit test for format.test.ts on shortenName function - [#768](https://github.com/alleslabs/celatone-frontend/pull/768) Add unit test for truncate.test.ts - [#767](https://github.com/alleslabs/celatone-frontend/pull/767) Add unit test for fee.test.ts From cd3a7aebd829cdf80c12e167b208f6f0bf61047a Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Wed, 7 Feb 2024 13:55:28 +0700 Subject: [PATCH 084/531] test(utils): update unit test for account store mobx --- src/lib/stores/account.test.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/lib/stores/account.test.ts b/src/lib/stores/account.test.ts index d4e50e404..8c13eab36 100644 --- a/src/lib/stores/account.test.ts +++ b/src/lib/stores/account.test.ts @@ -2,11 +2,6 @@ import { zBechAddr } from "lib/types"; import { AccountStore } from "./account"; -jest.mock("mobx-persist-store", () => ({ - isHydrated: jest.fn().mockReturnValue(true), - makePersistable: jest.fn(), -})); - describe("accountStore", () => { let accountStore: AccountStore; From 291c3fffbf5b9d688cf8c2a1bb922d3b488e1954 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 7 Feb 2024 16:55:00 +0700 Subject: [PATCH 085/531] feat: proposal status --- .../status-summary/Countdown.tsx | 2 +- .../status-summary/SummaryStatusBody.tsx | 168 +++++++++++++++++- .../status-summary/SummaryStatusChip.tsx | 4 +- .../status-summary/index.tsx | 4 + 4 files changed, 171 insertions(+), 7 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx index 310b139a8..3a2c012b6 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx @@ -33,7 +33,7 @@ export const Countdown = ({ endTime }: CountdownProps) => { const days = duration.days(); const timestamp = ( <> - {days && ( + {!!days && ( <> {days} {plur("day", days)} diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx index c62589bb0..7ff96fc4c 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx @@ -1,22 +1,57 @@ -import { Text } from "@chakra-ui/react"; +/* eslint-disable sonarjs/cognitive-complexity */ +import { SkeletonText, Text } from "@chakra-ui/react"; import type Big from "big.js"; +import { roundHalfUp } from "big.js"; import type { ProposalOverviewProps } from ".."; import { ErrorFetching } from "lib/components/state"; -import { extractParams, mapDeposit } from "lib/pages/proposal-details/utils"; +import { + extractParams, + mapDeposit, + normalizeVotesInfo, +} from "lib/pages/proposal-details/utils"; import type { Token, TokenWithValue, U } from "lib/types"; import { ProposalStatus } from "lib/types"; import { formatTokenWithValueList } from "lib/utils"; +const Passed = () => ( + + passed + +); + +const Rejected = () => ( + + rejected + +); + export const SummaryStatusBody = ({ proposalData, params, votesInfo, + isLoading, }: ProposalOverviewProps) => { + if (isLoading) + return ; if (!params || !votesInfo) return ; - const { minDeposit } = extractParams(params, proposalData.isExpedited); + const { minDeposit, quorum, threshold, vetoThreshold } = extractParams( + params, + proposalData.isExpedited + ); + const { yes, noWithVeto, currentTotalVotes } = normalizeVotesInfo(votesInfo); if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) { const required = mapDeposit(proposalData.totalDeposit, minDeposit).reduce< @@ -40,5 +75,130 @@ export const SummaryStatusBody = ({ ); } - return Detail; + if (proposalData.status === ProposalStatus.VOTING_PERIOD) { + if (currentTotalVotes.lt(quorum)) + return ( + + As of now, the proposal has not yet reached the required quorum. If + the voting period concludes without attaining the quorum, the proposal + will be . + + ); + + if (noWithVeto.lt(vetoThreshold)) + return ( + + The proposal has successfully met the voting quorum. However, if the + voting period concludes with a{" "} + + “No with veto” vote surpassing{" "} + {Math.round(vetoThreshold * 10000) / 100}% + + , the proposal will be regardless of other votes. + + ); + + if (yes.lt(threshold)) + return ( + + The proposal has{" "} + + successfully met + {" "} + the voting quorum. However, if the current voting tally remains + unchanged when the voting period ends, the proposal will be{" "} + . + + ); + + return ( + + The proposal has successfully met the voting quorum. If the current + voting tally remains unchanged when the voting period ends, the proposal + will be , and its content will be promptly implemented. + + ); + } + + if (proposalData.status === ProposalStatus.FAILED) + return ( + + Although the proposal successfully reached the voting quorum with a + {yes.mul(100).round(2, roundHalfUp).toNumber()}% “Yes&rdqui; rate, + it was not implemented due to technical reasons. + + ); + + if (proposalData.status === ProposalStatus.REJECTED) { + if (currentTotalVotes.lt(quorum)) + return ( + + This proposal did not meet the required quorum, resulting in its + rejection regardless of the voting outcomes. + + ); + + if (noWithVeto.lt(vetoThreshold)) + return ( + + This proposal has{" "} + + reached + {" "} + the voting quorum. But the voting period ended with “No with + veto” more than {Math.round(vetoThreshold * 10000) / 100}%, the + proposal will be regardless of other votes. + + ); + + return ( + + The proposal has reached the voting quorum but fell short of reaching + the “Yes” votes threshold, resulting in its rejection. + + ); + } + + if (proposalData.status === ProposalStatus.PASSED) + return ( + + The proposal has successfully met the voting quorum with a{" "} + + {yes.mul(100).round(2, roundHalfUp).toNumber()}% of “Yes&rdqui; + {" "} + rate. As a result, the proposal has been passed, and its content will + now be implemented. + + ); + + if (proposalData.status === ProposalStatus.CANCELLED) + return ( + + The proposal was cancelled by the proposer before the governance process + is complete. + + ); + + return ( + + The voting for this proposal did not reach the required quorum. As a + result, the proposal is not considered valid and rejected. + + ); }; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx index b5ea91163..0c1fd13c7 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx @@ -1,4 +1,4 @@ -import { Spinner, Text } from "@chakra-ui/react"; +import { Skeleton, Text } from "@chakra-ui/react"; import type { ProposalOverviewProps } from ".."; import { StatusChip } from "lib/components/table"; @@ -14,7 +14,7 @@ export const SummaryStatusChip = ({ votesInfo, isLoading, }: ProposalOverviewProps) => { - if (isLoading) return ; + if (isLoading) return ; if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) return ; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx index 73583a11c..f695f5153 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx @@ -5,6 +5,7 @@ import type { ProposalOverviewProps } from ".."; import { ProposalStatus } from "lib/types"; import { ActiveDot } from "./ActiveDot"; +import { SummaryStatusBody } from "./SummaryStatusBody"; import { SummaryStatusChip } from "./SummaryStatusChip"; import { SummaryStatusTime } from "./SummaryStatusTime"; @@ -38,6 +39,8 @@ export const StatusSummary = ({ proposalData.status === ProposalStatus.VOTING_PERIOD; return ( + ); }; From 970be099402147ae07eee4e9d2584b2728857b5b Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 7 Feb 2024 16:57:32 +0700 Subject: [PATCH 086/531] fix: quotation --- .../proposal-overview/status-summary/SummaryStatusBody.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx index 7ff96fc4c..00e708ef3 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx @@ -132,7 +132,7 @@ export const SummaryStatusBody = ({ return ( Although the proposal successfully reached the voting quorum with a - {yes.mul(100).round(2, roundHalfUp).toNumber()}% “Yes&rdqui; rate, + {yes.mul(100).round(2, roundHalfUp).toNumber()}% “Yes” rate, it was not implemented due to technical reasons. ); @@ -180,7 +180,7 @@ export const SummaryStatusBody = ({ fontWeight: 700, }} > - {yes.mul(100).round(2, roundHalfUp).toNumber()}% of “Yes&rdqui; + {yes.mul(100).round(2, roundHalfUp).toNumber()}% of “Yes” {" "} rate. As a result, the proposal has been passed, and its content will now be implemented. From fc01f10be66878ab4b1a52496f04c2f505f9abda Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 7 Feb 2024 17:12:34 +0700 Subject: [PATCH 087/531] fix: ongoing rejected chip --- .../proposal-overview/status-summary/SummaryStatusChip.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx index 0c1fd13c7..61ad04705 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx @@ -40,7 +40,7 @@ export const SummaryStatusChip = ({ yes.gte(threshold) && noWithVeto.lt(vetoThreshold) ? ProposalStatus.PASSED - : ProposalStatus.FAILED + : ProposalStatus.REJECTED } isTransparent /> From 0425741eb5f22e22b50be77ee809f38cf2fca9f7 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 7 Feb 2024 17:18:11 +0700 Subject: [PATCH 088/531] fix: changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24f6afece..7c50dc329 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#766](https://github.com/alleslabs/celatone-frontend/pull/766) Proposal status summary body - [#763](https://github.com/alleslabs/celatone-frontend/pull/763) Proposal status summary top - [#765](https://github.com/alleslabs/celatone-frontend/pull/765) Support Proposal Cancelled status - [#760](https://github.com/alleslabs/celatone-frontend/pull/760) Add proposal messages From 1b052ba87aa658f62bfa9c4ac95c6cd966c81e0b Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Wed, 7 Feb 2024 17:20:29 +0700 Subject: [PATCH 089/531] fix(components): fix pr number --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eea9400cd..0a9d69b45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,7 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements -- [#770](https://github.com/alleslabs/celatone-frontend/pull/770) Adjust proposal detail +- [#771](https://github.com/alleslabs/celatone-frontend/pull/771) Adjust proposal detail - [#769](https://github.com/alleslabs/celatone-frontend/pull/769) Add unit test for format.test.ts on shortenName function - [#768](https://github.com/alleslabs/celatone-frontend/pull/768) Add unit test for truncate.test.ts - [#767](https://github.com/alleslabs/celatone-frontend/pull/767) Add unit test for fee.test.ts From 970fa43302ba45f4b0bb59a4d49ffdcc15ca0b0e Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Wed, 7 Feb 2024 18:40:37 +0700 Subject: [PATCH 090/531] feat: add status summary stories --- package.json | 3 +- pnpm-lock.yaml | 1880 ++++++++++++++--- .../__stories__/StatusSummary.stories.ts | 314 +++ .../status-summary/SummaryStatusBody.tsx | 20 +- .../status-summary/SummaryStatusChip.tsx | 5 +- src/lib/pages/proposal-details/utils.ts | 9 + 6 files changed, 1920 insertions(+), 311 deletions(-) create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts diff --git a/package.json b/package.json index ae75a77cd..4607cc5eb 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "build-storybook": "storybook build" }, "resolutions": { - "@interchain-ui/react": "1.11.4", "chakra-react-select": "^4.7.0" }, "dependencies": { @@ -71,7 +70,7 @@ "@graphql-typed-document-node/core": "^3.2.0", "@initia/initia.js": "0.1.12", "@initia/initia.proto": "0.1.12", - "@interchain-ui/react": "1.11.4", + "@interchain-ui/react": "1.21.18", "@monaco-editor/react": "^4.6.0", "@rjsf/chakra-ui": "v5.0.0-beta.10", "@rjsf/core": "v5.0.0-beta.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a7578f93f..39ba30a15 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,6 @@ settings: excludeLinksFromLockfile: false overrides: - '@interchain-ui/react': 1.11.4 chakra-react-select: ^4.7.0 dependencies: @@ -71,7 +70,7 @@ dependencies: version: 2.7.2(@cosmjs/amino@0.32.2)(@cosmjs/proto-signing@0.32.2) '@cosmos-kit/react': specifier: 2.10.2 - version: 2.10.2(@interchain-ui/react@1.11.4)(react-dom@18.2.0)(react@18.2.0) + version: 2.10.2(@interchain-ui/react@1.21.18)(react-dom@18.2.0)(react@18.2.0) '@cosmos-kit/station': specifier: 2.5.2 version: 2.5.2(@cosmjs/amino@0.32.2)(@cosmjs/proto-signing@0.32.2)(@terra-money/terra.js@3.1.10)(axios@1.6.5) @@ -97,8 +96,8 @@ dependencies: specifier: 0.1.12 version: 0.1.12 '@interchain-ui/react': - specifier: 1.11.4 - version: 1.11.4(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + specifier: 1.21.18 + version: 1.21.18(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) '@monaco-editor/react': specifier: ^4.6.0 version: 4.6.0(monaco-editor@0.44.0)(react-dom@18.2.0)(react@18.2.0) @@ -3528,17 +3527,17 @@ packages: - utf-8-validate dev: false - /@cosmos-kit/react@2.10.2(@interchain-ui/react@1.11.4)(react-dom@18.2.0)(react@18.2.0): + /@cosmos-kit/react@2.10.2(@interchain-ui/react@1.21.18)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-+/YCETixxhMc1P/cyKdNbqjgT728Nn7Y0aWqH7VbTGANS5NvCIlk82VPlXH7ybYRApBdsG8rJ1Sc/n3kAgdk4g==} peerDependencies: - '@interchain-ui/react': 1.11.4 + '@interchain-ui/react': ^1.16.6 react: ^18 react-dom: ^18 dependencies: '@chain-registry/types': 0.17.0 '@cosmos-kit/core': 2.8.2 '@cosmos-kit/react-lite': 2.6.2(react-dom@18.2.0)(react@18.2.0) - '@interchain-ui/react': 1.11.4(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@interchain-ui/react': 1.21.18(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) '@react-icons/all-files': 4.1.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4356,8 +4355,42 @@ packages: /@floating-ui/utils@0.2.1: resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} - /@formkit/auto-animate@1.0.0-beta.6: - resolution: {integrity: sha512-PVDhLAlr+B4Xb7e+1wozBUWmXa6BFU8xUPR/W/E+TsQhPS1qkAdAsJ25keEnFrcePSnXHrOsh3tiFbEToOzV9w==} + /@formatjs/ecma402-abstract@1.18.2: + resolution: {integrity: sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==} + dependencies: + '@formatjs/intl-localematcher': 0.5.4 + tslib: 2.6.2 + dev: false + + /@formatjs/fast-memoize@2.2.0: + resolution: {integrity: sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==} + dependencies: + tslib: 2.6.2 + dev: false + + /@formatjs/icu-messageformat-parser@2.7.6: + resolution: {integrity: sha512-etVau26po9+eewJKYoiBKP6743I1br0/Ie00Pb/S/PtmYfmjTcOn2YCh2yNkSZI12h6Rg+BOgQYborXk46BvkA==} + dependencies: + '@formatjs/ecma402-abstract': 1.18.2 + '@formatjs/icu-skeleton-parser': 1.8.0 + tslib: 2.6.2 + dev: false + + /@formatjs/icu-skeleton-parser@1.8.0: + resolution: {integrity: sha512-QWLAYvM0n8hv7Nq5BEs4LKIjevpVpbGLAJgOaYzg9wABEoX1j0JO1q2/jVkO6CVlq0dbsxZCngS5aXbysYueqA==} + dependencies: + '@formatjs/ecma402-abstract': 1.18.2 + tslib: 2.6.2 + dev: false + + /@formatjs/intl-localematcher@0.5.4: + resolution: {integrity: sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==} + dependencies: + tslib: 2.6.2 + dev: false + + /@formkit/auto-animate@0.8.1: + resolution: {integrity: sha512-0/Z2cuNXWVVIG/l0SpcHAWFhGdvLJ8DRvEfRWvmojtmRWfEy+LWNwgDazbZqY0qQYtkHcoEK3jBLkhiZaB/4Ig==} dev: false /@graphql-codegen/cli@5.0.0(@types/node@20.11.5)(graphql@16.8.1)(typescript@5.3.3): @@ -4890,8 +4923,8 @@ packages: zod: 3.22.4 dev: false - /@interchain-ui/react@1.11.4(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-jUx02LyyUjSKANcpNJ9DPOkVlD2nERmQZsqEnUeJQ6wsG4rgO5yd0jHDUgqotvwxkRisYSy8jqDGe3r4pYsNBw==} + /@interchain-ui/react@1.21.18(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-MxeNlEJnDEsq5ftw1W5/Y22ix48ugrAAZwgMGeYr4xkZWjXaRDn+xwLrEjwIW3w9sBYiBv65tSUODQdPuN7GGw==} peerDependencies: react: ^18.x react-dom: ^18.x @@ -4899,27 +4932,54 @@ packages: '@fastify/deepmerge': 1.3.0 '@floating-ui/dom': 1.5.4 '@floating-ui/react': 0.26.6(react-dom@18.2.0)(react@18.2.0) - '@formkit/auto-animate': 1.0.0-beta.6 - '@vanilla-extract/css': 1.14.0 - '@vanilla-extract/css-utils': 0.1.3 + '@formkit/auto-animate': 0.8.1 + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@vanilla-extract/css': 1.14.1 '@vanilla-extract/dynamic': 2.1.0 - '@vanilla-extract/recipes': 0.4.0(@vanilla-extract/css@1.14.0) - '@zag-js/number-input': 0.15.0 - '@zag-js/react': 0.15.0(react-dom@18.2.0)(react@18.2.0) + '@vanilla-extract/recipes': 0.5.1(@vanilla-extract/css@1.14.1) animejs: 3.2.2 bignumber.js: 9.1.2 + client-only: 0.0.1 clsx: 1.2.1 copy-to-clipboard: 3.3.3 immer: 9.0.21 lodash: 4.17.21 - rainbow-sprinkles: 0.17.1(@vanilla-extract/css@1.14.0)(@vanilla-extract/dynamic@2.1.0) + rainbow-sprinkles: 0.17.1(@vanilla-extract/css@1.14.1)(@vanilla-extract/dynamic@2.1.0) react: 18.2.0 + react-aria: 3.31.1(react-dom@18.2.0)(react@18.2.0) react-dom: 18.2.0(react@18.2.0) + react-stately: 3.29.1(react@18.2.0) zustand: 4.4.7(@types/react@18.2.48)(immer@9.0.21)(react@18.2.0) transitivePeerDependencies: - '@types/react' dev: false + /@internationalized/date@3.5.1: + resolution: {integrity: sha512-LUQIfwU9e+Fmutc/DpRTGXSdgYZLBegi4wygCWDSVmUdLTaMHsQyASDiJtREwanwKuQLq0hY76fCJ9J/9I2xOQ==} + dependencies: + '@swc/helpers': 0.5.2 + dev: false + + /@internationalized/message@3.1.1: + resolution: {integrity: sha512-ZgHxf5HAPIaR0th+w0RUD62yF6vxitjlprSxmLJ1tam7FOekqRSDELMg4Cr/DdszG5YLsp5BG3FgHgqquQZbqw==} + dependencies: + '@swc/helpers': 0.5.2 + intl-messageformat: 10.5.11 + dev: false + + /@internationalized/number@3.5.0: + resolution: {integrity: sha512-ZY1BW8HT9WKYvaubbuqXbbDdHhOUMfE2zHHFJeTppid0S+pc8HtdIxFxaYMsGjCb4UsF+MEJ4n2TfU7iHnUK8w==} + dependencies: + '@swc/helpers': 0.5.2 + dev: false + + /@internationalized/string@3.2.0: + resolution: {integrity: sha512-Xx3Sy3f2c9ctT+vh8c7euEaEHQZltp0euZ3Hy4UfT3E13r6lxpUS3kgKyumEjboJZSnaZv7JhqWz3D75v+IxQg==} + dependencies: + '@swc/helpers': 0.5.2 + dev: false + /@ioredis/commands@1.2.0: resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} dev: false @@ -6128,232 +6188,1450 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@radix-ui/react-slot@1.0.2(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + /@radix-ui/react-slot@1.0.2(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toggle': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true + + /@radix-ui/react-toggle@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true + + /@radix-ui/react-toolbar@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-tBgmM/O7a07xbaEkYJWYTXkIdU/1pW4/KZORR43toC/4XWyBCURK0ei9kMUdp+gTPPKBgYLxXmRSH1EVcIDp8Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-separator': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toggle-group': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true + + /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/rect': 1.0.1 + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-use-size@1.0.1(@types/react@18.2.48)(react@18.2.0): + resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + react: 18.2.0 + dev: true + + /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true + + /@radix-ui/rect@1.0.1: + resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + dependencies: + '@babel/runtime': 7.23.8 + dev: true + + /@react-aria/breadcrumbs@3.5.9(react@18.2.0): + resolution: {integrity: sha512-asbXTL5NjeHl1+YIF0K70y8tNHk8Lb6VneYH8yOkpLO49ejyNDYBK0tp0jtI9IZAQiTa2qkhYq58c9LloTwebQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/link': 3.6.3(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/breadcrumbs': 3.7.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/button@3.9.1(react@18.2.0): + resolution: {integrity: sha512-nAnLMUAnwIVcRkKzS1G2IU6LZSkIWPJGu9amz/g7Y02cGUwFp3lk5bEw2LdoaXiSDJNSX8g0SZFU8FROg57jfQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/toggle': 3.7.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/calendar@3.5.4(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-8k7khgea5kwfWriZJWCADNB0R2d7g5A6tTjUEktK4FFZcTb0RCubFejts4hRyzKlF9XHUro2dfh6sbZrzfMKDQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/calendar': 3.4.3(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/calendar': 3.4.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/checkbox@3.13.0(react@18.2.0): + resolution: {integrity: sha512-eylJwtADIPKJ1Y5rITNJm/8JD8sXG2nhiZBIg1ko44Szxrpu+Le53NoGtg8nlrfh9vbUrXVvuFtf2jxbPXR5Jw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/form': 3.0.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/toggle': 3.10.0(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/checkbox': 3.6.1(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/toggle': 3.7.0(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/combobox@3.8.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-q8Kdw1mx6nSSydXqRagRuyKH1NPGvpSOFjUfgxdO8ZqaEEuZX3ObOoiO/DLtXDndViNc03dMbMpfuJoLYXfCtg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/listbox': 3.11.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/menu': 3.12.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/textfield': 3.14.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/combobox': 3.8.1(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/combobox': 3.10.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/datepicker@3.9.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-bdlY2H/zwe3hQf64Lp1oGTf7Va8ennDyAv4Ffowb+BOoL8+FB9smtGyONKe87zXu7VJL2M5xYAi4n7c004PM+w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@internationalized/number': 3.5.0 + '@internationalized/string': 3.2.0 + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/form': 3.0.1(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/spinbutton': 3.6.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/datepicker': 3.9.1(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/calendar': 3.4.3(react@18.2.0) + '@react-types/datepicker': 3.7.1(react@18.2.0) + '@react-types/dialog': 3.5.7(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/dialog@3.5.10(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-H2BNVLOfaum6/4irH5XUU/wIcXSs/ymxmTPGmucRG1hzaUh8H3tupdl/qCZ+SsW9oYDFlphY172uM1nsPjBMiQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/dialog': 3.5.7(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/dnd@3.5.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-7OPGePdle+xNYHAIAUOvIETRMfnkRt7h/C0bCkxUR2GYefEbTzfraso4ppNH2JZ7fCRd0K/Qe+jvQklwusHAKA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/string': 3.2.0 + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/dnd': 3.2.7(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/focus@3.16.0(react@18.2.0): + resolution: {integrity: sha512-GP6EYI07E8NKQQcXHjpIocEU0vh0oi0Vcsd+/71fKS0NnTR0TUOEeil0JuuQ9ymkmPDTu51Aaaa4FxVsuN/23A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + clsx: 2.1.0 + react: 18.2.0 + dev: false + + /@react-aria/form@3.0.1(react@18.2.0): + resolution: {integrity: sha512-6586oODMDR4/ciGRwXjpvEAg7tWGSDrXE//waK0n5e5sMuzlPOo1DHc5SpPTvz0XdJsu6VDt2rHdVWVIC9LEyw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/grid@3.8.6(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-JlQDkdm5heG1FfRyy5KnB8b6s/hRqSI6Xt2xN2AccLX5kcbfFr2/d5KVxyf6ahfa4Gfd46alN6477ju5eTWJew==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/grid': 3.8.4(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-stately/virtualizer': 3.6.6(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@react-types/grid': 3.2.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/gridlist@3.7.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-rkkepYM7xJiebR0g3uC4zzkdR7a8z0fLaM+sg9lSTbdElHMLAlrebS2ytEyZnhiu9nbOnw13GN1OC4/ZenzbHQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/grid': 3.8.6(react-dom@18.2.0)(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/i18n@3.10.0(react@18.2.0): + resolution: {integrity: sha512-sviD5Y1pLPG49HHRmVjR+5nONrp0HK219+nu9Y7cDfUhXu2EjyhMS9t/n9/VZ69hHChZ2PnHYLEE2visu9CuCg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@internationalized/message': 3.1.1 + '@internationalized/number': 3.5.0 + '@internationalized/string': 3.2.0 + '@react-aria/ssr': 3.9.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/interactions@3.20.1(react@18.2.0): + resolution: {integrity: sha512-PLNBr87+SzRhe9PvvF9qvzYeP4ofTwfKSorwmO+hjr3qoczrSXf4LRQlb27wB6hF10C7ZE/XVbUI1lj4QQrZ/g==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/ssr': 3.9.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/label@3.7.4(react@18.2.0): + resolution: {integrity: sha512-3Y0yyrqpLzZdzHw+TOyzwuyx5wa2ujU5DGfKuL5GFnU9Ii4DtdwBGSYS7Yu7qadU+eQmG4OGhAgFVswbIgIwJw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/link@3.6.3(react@18.2.0): + resolution: {integrity: sha512-8kPWc4u/lDow3Ll0LDxeMgaxt9Y3sl8UldKLGli8tzRSltYFugNh/n+i9sCnmo4Qv9Tp9kYv+yxBK50Uk9sINw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/link': 3.5.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/listbox@3.11.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-PBrnldmyEYUUJvfDeljW8ITvZyBTfGpLNf0b5kfBPK3TDgRH4niEH2vYEcaZvSqb0FrpdvcunuTRXcOpfb+gCQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-types/listbox': 3.4.6(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/live-announcer@3.3.1: + resolution: {integrity: sha512-hsc77U7S16trM86d+peqJCOCQ7/smO1cybgdpOuzXyiwcHQw8RQ4GrXrS37P4Ux/44E9nMZkOwATQRT2aK8+Ew==} + dependencies: + '@swc/helpers': 0.5.2 + dev: false + + /@react-aria/menu@3.12.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Nsujv3b61WR0gybDKnBjAeyxDVJOfPLMggRUf9SQDfPWnrPXEsAFxaPaVcAkzlfI4HiQs1IxNwsKFNpc3PPZTQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/menu': 3.6.0(react@18.2.0) + '@react-stately/tree': 3.7.5(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/menu': 3.9.6(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/meter@3.4.9(react@18.2.0): + resolution: {integrity: sha512-1/FHFmFmSyfQBJ2oH152lp4nps76v1UdhnFbIsmRIH+0g0IfMv1yDT2M9dIZ/b9DgVZSx527FmWOXm0eHGKD6w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/progress': 3.4.9(react@18.2.0) + '@react-types/meter': 3.3.6(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/numberfield@3.10.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-KjGTXq3lIhN4DEdEeHzfS/k9Qq0sDEpLgLr/hgSfGN4Q7Syu4Ck/n2HXmrDn//z08/wNvcukuP6Ioers138DcQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/spinbutton': 3.6.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/textfield': 3.14.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/numberfield': 3.8.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/numberfield': 3.7.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/overlays@3.20.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-2m7MpRJL5UucbEuu08lMHsiFJoDowkJV4JAIFBZYK1NzVH0vF/A+w9HRNM7jRwx2DUxE+iIsZnl8yKV/7KY8OQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/ssr': 3.9.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-aria/visually-hidden': 3.8.8(react@18.2.0) + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/overlays': 3.8.4(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/progress@3.4.9(react@18.2.0): + resolution: {integrity: sha512-CME1ZLsJHOmSgK8IAPOC/+vYO5Oc614mkEw5MluT/yclw5rMyjAkK1XsHLjEXy81uwPeiRyoQQIMPKG2/sMxFQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/progress': 3.5.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/radio@3.10.0(react@18.2.0): + resolution: {integrity: sha512-6NaKzdGymdcVWLYgHT0cHsVmNzPOp89o8r41w29OPBQWu8w2c9mxg4366OiIZn/uXIBS4abhQ4nL4toBRLgBrg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/form': 3.0.1(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/radio': 3.10.1(react@18.2.0) + '@react-types/radio': 3.7.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/searchfield@3.7.1(react@18.2.0): + resolution: {integrity: sha512-ebhnV/reNByIZzpcQLHIo1RQ+BrYS8HdwX624i9R7dep1gxGHXYEaqL9aSY+RdngNerB4OeiWmB75em9beSpjQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/textfield': 3.14.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/searchfield': 3.5.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/searchfield': 3.5.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/select@3.14.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-pAy/+Xbj11Lx6bi/O1hWH0NSIDRxFb6V7N0ry2L8x7MALljh516VbpnAc5RgvbjbuKq0cHUAcdINOzOzpYWm4A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/form': 3.0.1(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/listbox': 3.11.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/menu': 3.12.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-aria/visually-hidden': 3.8.8(react@18.2.0) + '@react-stately/select': 3.6.1(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/select': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/selection@3.17.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-xl2sgeGH61ngQeE05WOWWPVpGRTPMjQEFmsAWEprArFi4Z7ihSZgpGX22l1w7uSmtXM/eN/v0W8hUYUju5iXlQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/separator@3.3.9(react@18.2.0): + resolution: {integrity: sha512-1wEXiaSJjq2+DR5TC0RKnUBsfZN+YXTzyI7XMzjQoc3YlclumX8wQtzPAOGOEjHB1JKUgo1Gw70FtupVXz58QQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/slider@3.7.4(react@18.2.0): + resolution: {integrity: sha512-OFJWeGSL2duVDFs/kcjlWsY6bqCVKZgM0aFn2QN4wmID+vfBvBnqGHAgWv3BCePTAPS3+GBjMN002TrftorjwQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/slider': 3.5.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/slider': 3.7.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/spinbutton@3.6.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-u5GuOP3k4Zis055iY0fZJNHU7dUNCoSfUq5LKwJ1iNaCqDcavdstAnAg+X1a7rhpp5zCnJmAMseo3Qmzi9P+Ew==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/ssr@3.9.1(react@18.2.0): + resolution: {integrity: sha512-NqzkLFP8ZVI4GSorS0AYljC13QW2sc8bDqJOkBvkAt3M8gbcAXJWVRGtZBCRscki9RZF+rNlnPdg0G0jYkhJcg==} + engines: {node: '>= 12'} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/switch@3.6.0(react@18.2.0): + resolution: {integrity: sha512-YNWc5fGLNXE4XlmDAKyqAdllRiClGR7ki4KGFY7nL+xR5jxzjCGU3S3ToMK5Op3QSMGZLxY/aYmC4O+MvcoADQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/toggle': 3.10.0(react@18.2.0) + '@react-stately/toggle': 3.7.0(react@18.2.0) + '@react-types/switch': 3.5.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/table@3.13.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-AzmETpyxwNqISTzwHJPs85x9gujG40IIsSOBUdp49oKhB85RbPLvMwhadp4wCVAoHw3erOC/TJxHtVc7o2K1LA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/grid': 3.8.6(react-dom@18.2.0)(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/live-announcer': 3.3.1 + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-aria/visually-hidden': 3.8.8(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/flags': 3.0.0 + '@react-stately/table': 3.11.4(react@18.2.0) + '@react-stately/virtualizer': 3.6.6(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@react-types/grid': 3.2.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/table': 3.9.2(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/tabs@3.8.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Plw0K/5Qv35vYq7pHZFfQB2BF5OClFx4Abzo9hLVx4oMy3qb7i5lxmLBVbt81yPX/MdjYeP4zO1EHGBl4zMRhA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/tabs': 3.6.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/tabs': 3.3.4(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/tag@3.3.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-w7d8sVZqxTo8VFfeg2ixLp5kawtrcguGznVY4mt5aE6K8LMJOeNVDqNNfolfyia80VjOWjeX+RpVdVJRdrv/GQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/gridlist': 3.7.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-types/button': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@react-aria/textfield@3.14.1(react@18.2.0): + resolution: {integrity: sha512-UMepuYtDdCgrUF4dMphNxrUm23xOmR54aZD1pbp9cJyfioVkJN35BTXZVkD0D07gHLn4RhxKIZxBortQQrLB9g==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/form': 3.0.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/textfield': 3.9.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/toggle@3.10.0(react@18.2.0): + resolution: {integrity: sha512-6cUf4V9TuG2J7AvXUdU/GspEPFCubUOID3mrselSe563RViy+mMZk0vUEOdyoNanDcEXl58W4dE3SGWxFn71vg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/toggle': 3.7.0(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/tooltip@3.7.0(react@18.2.0): + resolution: {integrity: sha512-+u9Sftkfe09IDyPEnbbreFKS50vh9X/WTa7n1u2y3PenI9VreLpUR6czyzda4BlvQ95e9jQz1cVxUjxTNaZmBw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-stately/tooltip': 3.4.6(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/tooltip': 3.4.6(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-aria/utils@3.23.0(react@18.2.0): + resolution: {integrity: sha512-fJA63/VU4iQNT8WUvrmll3kvToqMurD69CcgVmbQ56V7ZbvlzFi44E7BpnoaofScYLLtFWRjVdaHsohT6O/big==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/ssr': 3.9.1(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + clsx: 2.1.0 + react: 18.2.0 + dev: false + + /@react-aria/visually-hidden@3.8.8(react@18.2.0): + resolution: {integrity: sha512-Cn2PYKD4ijGDtF0+dvsh8qa4y7KTNAlkTG6h20r8Q+6UTyRNmtE2/26QEaApRF8CBiNy9/BZC/ZC4FK2OjvCoA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-icons/all-files@4.1.0(react@18.2.0): + resolution: {integrity: sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==} + peerDependencies: + react: '*' + dependencies: + react: 18.2.0 + dev: false + + /@react-stately/calendar@3.4.3(react@18.2.0): + resolution: {integrity: sha512-OrEcdskszDjnjVnFuSiDC2PVBJ6lWMCJROD5s6W1LUehUtBp8LX9wPavAGHV43LbhN9ldj560sxaQ4WCddrRCA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/calendar': 3.4.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/checkbox@3.6.1(react@18.2.0): + resolution: {integrity: sha512-rOjFeVBy32edYwhKiHj3ZLdLeO+xZ2fnBwxnOBjcygnw4Neygm8FJH/dB1J0hdYYR349yby86ED2x0wRc84zPw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/collections@3.10.4(react@18.2.0): + resolution: {integrity: sha512-OHhCrItGt4zB2bSrgObRo0H2SC7QlkH8ReGxo+NVIWchXRLRoiWBP7S+IwleewEo5gOqDVPY3hqA9n4iiI8twg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/combobox@3.8.1(react@18.2.0): + resolution: {integrity: sha512-FaWkqTXQdWg7ptaeU4iPcqF/kxbRg2ZNUcvW/hiL/enciV5tRCsddvfNqvDvy1L30z9AUwlp9MWqzm/DhBITCw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-stately/select': 3.6.1(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/combobox': 3.10.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/data@3.11.0(react@18.2.0): + resolution: {integrity: sha512-0BlPT58WrAtUvpiEfUuyvIsGFTzp/9vA5y+pk53kGJhOdc5tqBGHi9cg40pYE/i1vdHJGMpyHGRD9nkQb8wN3Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/datepicker@3.9.1(react@18.2.0): + resolution: {integrity: sha512-o5xLvlZGJyAbTev2yruGlV2fzQyIDuYTgL19TTt0W0WCfjGGr/AAA9GjGXXmyoRA7sZMxqIPnnv7lNrdA38ofA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@internationalized/string': 3.2.0 + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/datepicker': 3.7.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/dnd@3.2.7(react@18.2.0): + resolution: {integrity: sha512-QqSCvE9Rhp+Mr8Mt/SrByze24BFX1cy7gmXbwoqAYgHNIx3gWCVdBLqxfpfgYIhZdF9H72EWS8lQkfkZla06Ng==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/flags@3.0.0: + resolution: {integrity: sha512-e3i2ItHbIa0eEwmSXAnPdD7K8syW76JjGe8ENxwFJPW/H1Pu9RJfjkCb/Mq0WSPN/TpxBb54+I9TgrGhbCoZ9w==} + dependencies: + '@swc/helpers': 0.4.36 + dev: false + + /@react-stately/form@3.0.0(react@18.2.0): + resolution: {integrity: sha512-C8wkfFmtx1escizibhdka5JvTy9/Vp173CS9cakjvWTmnjYYC1nOlzwp7BsYWTgerCFbRY/BU/Cf/bJDxPiUKQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/grid@3.8.4(react@18.2.0): + resolution: {integrity: sha512-rwqV1K4lVhaiaqJkt4TfYqdJoVIyqvSm98rKAYfCNzrKcivVpoiCMJ2EMt6WlYCjDVBdEOQ7fMV1I60IV0pntA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-types/grid': 3.2.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/list@3.10.2(react@18.2.0): + resolution: {integrity: sha512-INt+zofkIg2KN8B95xPi9pJG7ZFWAm30oIm/lCPBqM3K1Nm03/QaAbiQj2QeJcOsG3lb7oqI6D6iwTolwJkjIQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/menu@3.6.0(react@18.2.0): + resolution: {integrity: sha512-OB6CjNyfOkAuirqx1oTL8z8epS9WDzLyrXjmRnxdiCU9EgRXLGAQNECuO7VIpl58oDry8tgRJiJ8fn8FivWSQA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-types/menu': 3.9.6(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/numberfield@3.8.0(react@18.2.0): + resolution: {integrity: sha512-1XvB8tDOvZKcFnMM6qNLEaTVJcIc0jRFS/9jtS8MzalZvh8DbKi0Ucm1bGU7S5rkCx2QWqZ0rGOIm2h/RlcpkA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/number': 3.5.0 + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/numberfield': 3.7.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/overlays@3.6.4(react@18.2.0): + resolution: {integrity: sha512-tHEaoAGpE9dSnsskqLPVKum59yGteoSqsniTopodM+miQozbpPlSjdiQnzGLroy5Afx5OZYClE616muNHUILXA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/overlays': 3.8.4(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/radio@3.10.1(react@18.2.0): + resolution: {integrity: sha512-MsBYbcLCvjKsqTAKe43T681F2XwKMsS7PLG0eplZgWP9210AMY78GeY1XPYZKHPAau8XkbYiuJqbqTerIJ3DBw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/radio': 3.7.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/searchfield@3.5.0(react@18.2.0): + resolution: {integrity: sha512-SStjChkn/33pEn40slKQPnBnmQYyxVazVwPjiBkdeVejC42lUVairUTrGJgF0PNoZTbxn0so2/XzjqTC9T8iCw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/searchfield': 3.5.2(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/select@3.6.1(react@18.2.0): + resolution: {integrity: sha512-e5ixtLiYLlFWM8z1msDqXWhflF9esIRfroptZsltMn1lt2iImUlDRlOTZlMtPQzUrDWoiHXRX88sSKUM/jXjQQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-types/select': 3.9.1(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/selection@3.14.2(react@18.2.0): + resolution: {integrity: sha512-mL7OoiUgVWaaF7ks5XSxgbXeShijYmD4G3bkBHhqkpugU600QH6BM2hloCq8KOUupk1y8oTljPtF9EmCv375DA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/slider@3.5.0(react@18.2.0): + resolution: {integrity: sha512-dOVpIxb7XKuiRxgpHt1bUSlsklciFki100tKIyBPR+Okar9iC/CwLYROYgVfLkGe77jEBNkor9tDLjDGEWcc1w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/slider': 3.7.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/table@3.11.4(react@18.2.0): + resolution: {integrity: sha512-dWINJIEOKQl4qq3moq+S8xCD3m+yJqBj0dahr+rOkS+t2uqORwzsusTM35D2T/ZHZi49S2GpE7QuDa+edCynPw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/flags': 3.0.0 + '@react-stately/grid': 3.8.4(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/grid': 3.2.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/table': 3.9.2(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/tabs@3.6.3(react@18.2.0): + resolution: {integrity: sha512-Nj+Gacwa2SIzYIvHW40GsyX4Q6c8kF7GOuXESeQswbCjnwqhrSbDBp+ngPcUPUJxqFh6JhDCVwAS3wMhUoyUwA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/tabs': 3.3.4(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/toggle@3.7.0(react@18.2.0): + resolution: {integrity: sha512-TRksHkCJk/Xogq4181g3CYgJf+EfsJCqX5UZDSw1Z1Kgpvonjmdf6FAfQfCh9QR2OuXUL6hOLUDVLte5OPI+5g==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/checkbox': 3.6.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/tooltip@3.4.6(react@18.2.0): + resolution: {integrity: sha512-uL93bmsXf+OOgpKLPEKfpDH4z+MK2CuqlqVxx7rshN0vjWOSoezE5nzwgee90+RpDrLNNNWTNa7n+NkDRpI1jA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-types/tooltip': 3.4.6(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/tree@3.7.5(react@18.2.0): + resolution: {integrity: sha512-xTJVwvhAeY0N5rui4N/TxN7f8hjXdqApDuGDxMZeFAWoQz8Abf7LFKBVQ3OkT6qVr7P+23dgoisUDBhD5a45Hg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-stately/utils': 3.9.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/utils@3.9.0(react@18.2.0): + resolution: {integrity: sha512-yPKFY1F88HxuZ15BG2qwAYxtpE4HnIU0Ofi4CuBE0xC6I8mwo4OQjDzi+DZjxQngM9D6AeTTD6F1V8gkozA0Gw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-stately/virtualizer@3.6.6(react@18.2.0): + resolution: {integrity: sha512-9hWvfITdE/028q4YFve6FxlmA3PdSMkUwpYA+vfaGCXI/4DFZIssBMspUeu4PTRJoV+k+m0z1wYHPmufrq6a3g==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + '@swc/helpers': 0.5.2 + react: 18.2.0 + dev: false + + /@react-types/breadcrumbs@3.7.2(react@18.2.0): + resolution: {integrity: sha512-esl6RucDW2CNMsApJxNYfMtDaUcfLlwKMPH/loYsOBbKxGl2HsgVLMcdpjEkTRs2HCTNCbBXWpeU8AY77t+bsw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/link': 3.5.2(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/button@3.9.1(react@18.2.0): + resolution: {integrity: sha512-bf9iTar3PtqnyV9rA+wyFyrskZKhwmOuOd/ifYIjPs56YNVXWH5Wfqj6Dx3xdFBgtKx8mEVQxVhoX+WkHX+rtw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/calendar@3.4.3(react@18.2.0): + resolution: {integrity: sha512-96x57ctX5wNEl+8et3sc2NQm8neOJayEeqOQQpyPtI7jyvst/xBrKCwysf9W/dhgPlUC+KeBAYFWfjd5hFVHYA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/checkbox@3.6.0(react@18.2.0): + resolution: {integrity: sha512-vgbuJzQpVCNT5AZWV0OozXCnihqrXxoZKfJFIw0xro47pT2sn3t5UC4RA9wfjDGMoK4frw1K/4HQLsQIOsPBkw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/combobox@3.10.0(react@18.2.0): + resolution: {integrity: sha512-1IXSNS02TPbguyYopaW2snU6sZusbClHrEyVr4zPeexTV4kpUUBNXOzFQ+eSQRR0r2XW57Z0yRW4GJ6FGU0yCA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/datepicker@3.7.1(react@18.2.0): + resolution: {integrity: sha512-5juVDULOytNzkotqX8j5mYKJckeIpkgbHqVSGkPgLw0++FceIaSZ6RH56cqLup0pO45paqIt9zHh+QXBYX+syg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/date': 3.5.1 + '@react-types/calendar': 3.4.3(react@18.2.0) + '@react-types/overlays': 3.8.4(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/dialog@3.5.7(react@18.2.0): + resolution: {integrity: sha512-geYoqAyQaTLG43AaXdMUVqZXYgkSifrD9cF7lR2kPAT0uGFv0YREi6ieU+aui8XJ83EW0xcxP+EPWd2YkN4D4w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/overlays': 3.8.4(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/grid@3.2.3(react@18.2.0): + resolution: {integrity: sha512-GQM4RDmYhstcYZ0Odjq+xUwh1fhLmRebG6qMM8OXHTPQ77nhl3wc1UTGRhZm6mzEionplSRx4GCpEMEHMJIU0w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/link@3.5.2(react@18.2.0): + resolution: {integrity: sha512-/s51/WejmpLiyxOgP89s4txgxYoGaPe8pVDItVo1h4+BhU1Puyvgv/Jx8t9dPvo6LUXbraaN+SgKk/QDxaiirw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/listbox@3.4.6(react@18.2.0): + resolution: {integrity: sha512-XOQvrTqNh5WIPDvKiWiep8T07RAsMfjAXTjDbnjxVlKACUXkcwpts9kFaLnJ9LJRFt6DwItfP+WMkzvmx63/NQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/menu@3.9.6(react@18.2.0): + resolution: {integrity: sha512-w/RbFInOf4nNayQDv5c2L8IMJbcFOkBhsT3xvvpTy+CHvJcQdjggwaV1sRiw7eF/PwB81k2CwigmidUzHJhKDg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-types/overlays': 3.8.4(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@react-types/meter@3.3.6(react@18.2.0): + resolution: {integrity: sha512-1XYp1fA9UU0lO6kjf3TwVE8mppOJa64mBKAcLWtTyq1e/cYIAbx5o6CsuUx0YDpXKF6gdtvIWvfmxeWsmqJ1jQ==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 + '@react-types/progress': 3.5.1(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} + /@react-types/numberfield@3.7.0(react@18.2.0): + resolution: {integrity: sha512-gaGi+vqm1Y8LCWRsWYUjcGftPIzl+8W2VOfkgKMLM8y76nnwTPtmAqs+Ap1cg7sEJSfsiKMq93e9yvP3udrC2w==} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-toggle': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true + dev: false - /@radix-ui/react-toggle@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==} + /@react-types/overlays@3.8.4(react@18.2.0): + resolution: {integrity: sha512-pfgNlQnbF6RB/R2oSxyqAP3Uzz0xE/k5q4n5gUeCDNLjY5qxFHGE8xniZZ503nZYw6VBa9XMN1efDOKQyeiO0w==} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true + dev: false - /@radix-ui/react-toolbar@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-tBgmM/O7a07xbaEkYJWYTXkIdU/1pW4/KZORR43toC/4XWyBCURK0ei9kMUdp+gTPPKBgYLxXmRSH1EVcIDp8Q==} + /@react-types/progress@3.5.1(react@18.2.0): + resolution: {integrity: sha512-CqsUjczUK/SfuFzDcajBBaXRTW0D3G9S/yqLDj9e8E0ii+lGDLt1PHj24t1J7E88U2rVYqmM9VL4NHTt8o3IYA==} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-separator': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-toggle-group': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true + dev: false - /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + /@react-types/radio@3.7.0(react@18.2.0): + resolution: {integrity: sha512-EcwGAXzSHjSqpFZha7xn3IUrhPiJLj+0yb1Ip0qPmhWz0VVw2DwrkY7q/jfaKroVvQhTo2TbfGhcsAQrt0fRqg==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + /@react-types/searchfield@3.5.2(react@18.2.0): + resolution: {integrity: sha512-JAK2/Kg4Dr393FYfbRw0TlXKnJPX77sq1x/ZBxtO6p64+MuuIYKqw0i9PwDlo1PViw2QI5u8GFhKA2TgemY9uA==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 + '@react-types/shared': 3.22.0(react@18.2.0) + '@react-types/textfield': 3.9.0(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + /@react-types/select@3.9.1(react@18.2.0): + resolution: {integrity: sha512-EpKSxrnh8HdZvOF9dHQkjivAcdIp1K81FaxmvosH8Lygqh0iYXxAdZGtKLMyBoPI8YFhA+rotIzTcOqgCCnqWA==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + /@react-types/shared@3.22.0(react@18.2.0): + resolution: {integrity: sha512-yVOekZWbtSmmiThGEIARbBpnmUIuePFlLyctjvCbgJgGhz8JnEJOipLQ/a4anaWfzAgzSceQP8j/K+VOOePleA==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} + /@react-types/slider@3.7.0(react@18.2.0): + resolution: {integrity: sha512-uyQXUVFfqc9SPUW0LZLMan2n232F/OflRafiHXz9viLFa9tVOupVa7GhASRAoHojwkjoJ1LjFlPih7g5dOZ0/Q==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@types/react': 18.2.48 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} + /@react-types/switch@3.5.0(react@18.2.0): + resolution: {integrity: sha512-/wNmUGjk69bP6t5k2QkAdrNN5Eb9Rz4dOyp0pCPmoeE+5haW6sV5NmtkvWX1NSc4DQz1xL/a5b+A0vxPCP22Jw==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/rect': 1.0.1 - '@types/react': 18.2.48 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-use-size@1.0.1(@types/react@18.2.48)(react@18.2.0): - resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} + /@react-types/table@3.9.2(react@18.2.0): + resolution: {integrity: sha512-brw5JUANOzBa2rYNpN8AIl9nDZ9RwRZC6G/wTM/JhtirjC1S42oCtf8Ap5rWJBdmMG/5KOfcGNcAl/huyqb3gg==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.48)(react@18.2.0) - '@types/react': 18.2.48 + '@react-types/grid': 3.2.3(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - dev: true + dev: false - /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} + /@react-types/tabs@3.3.4(react@18.2.0): + resolution: {integrity: sha512-4mCTtFrwMRypyGTZCvNYVT9CkknexO/UYvqwDm2jMYb8JgjRvxnomu776Yh7uyiYKWyql2upm20jqasEOm620w==} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.48 - '@types/react-dom': 18.2.18 + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: true + dev: false - /@radix-ui/rect@1.0.1: - resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + /@react-types/textfield@3.9.0(react@18.2.0): + resolution: {integrity: sha512-D/DiwzsfkwlAg3uv8hoIfwju+zhB/hWDEdTvxQbPkntDr0kmN/QfI17NMSzbOBCInC4ABX87ViXLGxr940ykGA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: - '@babel/runtime': 7.23.8 - dev: true + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false - /@react-icons/all-files@4.1.0(react@18.2.0): - resolution: {integrity: sha512-hxBI2UOuVaI3O/BhQfhtb4kcGn9ft12RWAFVMUeNjqqhLsHvFtzIkFaptBJpFDANTKoDfdVoHTKZDlwKCACbMQ==} + /@react-types/tooltip@3.4.6(react@18.2.0): + resolution: {integrity: sha512-RaZewdER7ZcsNL99RhVHs8kSLyzIBkwc0W6eFZrxST2MD9J5GzkVWRhIiqtFOd5U1aYnxdJ6woq72Ef+le6Vfw==} peerDependencies: - react: '*' + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 dependencies: + '@react-types/overlays': 3.8.4(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) react: 18.2.0 dev: false @@ -7788,6 +9066,19 @@ packages: /@swc/counter@0.1.2: resolution: {integrity: sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==} + /@swc/helpers@0.4.14: + resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} + dependencies: + tslib: 2.6.2 + dev: false + + /@swc/helpers@0.4.36: + resolution: {integrity: sha512-5lxnyLEYFskErRPenYItLRSge5DjrJngYKdVjRSrWfza9G6KkgHEXi0vUZiyUeMU5JfXH1YnvXZzSp8ul88o2Q==} + dependencies: + legacy-swc-helpers: /@swc/helpers@0.4.14 + tslib: 2.6.2 + dev: false + /@swc/helpers@0.5.2: resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} dependencies: @@ -8562,12 +9853,8 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - /@vanilla-extract/css-utils@0.1.3: - resolution: {integrity: sha512-PZAcHROlgtCUGI2y0JntdNwvPwCNyeVnkQu6KTYKdmxBbK3w72XJUmLFYapfaFfgami4I9CTLnrJTPdtmS3gpw==} - dev: false - - /@vanilla-extract/css@1.14.0: - resolution: {integrity: sha512-rYfm7JciWZ8PFzBM/HDiE2GLnKI3xJ6/vdmVJ5BSgcCZ5CxRlM9Cjqclni9lGzF3eMOijnUhCd/KV8TOzyzbMA==} + /@vanilla-extract/css@1.14.1: + resolution: {integrity: sha512-V4JUuHNjZgl64NGfkDJePqizkNgiSpphODtZEs4cCPuxLAzwOUJYATGpejwimJr1n529kq4DEKWexW22LMBokw==} dependencies: '@emotion/hash': 0.9.1 '@vanilla-extract/private': 1.0.3 @@ -8592,12 +9879,12 @@ packages: resolution: {integrity: sha512-17kVyLq3ePTKOkveHxXuIJZtGYs+cSoev7BlP+Lf4916qfDhk/HBjvlYDe8egrea7LNPHKwSZJK/bzZC+Q6AwQ==} dev: false - /@vanilla-extract/recipes@0.4.0(@vanilla-extract/css@1.14.0): - resolution: {integrity: sha512-gFgB7BofUYbtbxINHK6DhMv1JDFDXp/YI/Xm+cqKar+1I/2dfxPepeDxSexL6YB4ftfeaDw8Kn5zydMvHcGOEQ==} + /@vanilla-extract/recipes@0.5.1(@vanilla-extract/css@1.14.1): + resolution: {integrity: sha512-7dCuBgPQQ/89siQ0w2lkfjgkmToPUUDzFlHf5DRmt9ykiiycfA52tmPJ2RI/mr7jXi7U/vEN2aGP9QJSXEpGlA==} peerDependencies: '@vanilla-extract/css': ^1.0.0 dependencies: - '@vanilla-extract/css': 1.14.0 + '@vanilla-extract/css': 1.14.1 dev: false /@vercel/analytics@1.1.1: @@ -9064,28 +10351,6 @@ packages: tslib: 1.14.1 dev: true - /@zag-js/anatomy@0.15.0: - resolution: {integrity: sha512-+lmu/JVQ6Q5M9Tmbt1sXVkp3CtP10JYOo/PU2L6w6mXpwazT5FUpsuorrBrBM9rhWOnxI7CVvFy7r/rxReDWgg==} - dev: false - - /@zag-js/core@0.15.0: - resolution: {integrity: sha512-eH3yx9nv0hMyoR+hWtJVJpCagpU5s61rOMHfLkdjMPTWSVjQZdp3SGEm6BTUjBlNbQkTZhUbPpg/FEqx1iPfJw==} - dependencies: - '@zag-js/store': 0.15.0 - klona: 2.0.6 - dev: false - - /@zag-js/dom-event@0.15.0: - resolution: {integrity: sha512-5Sw2pNCcX2PqSiz4Ntm2PDu+YARQLtUrAf6PBBSUIqMZ0X9pp7DWTY3IfpdqY2ADsRLRMIe1LqzM+/c0u3Gd1Q==} - dependencies: - '@zag-js/text-selection': 0.15.0 - '@zag-js/types': 0.15.0 - dev: false - - /@zag-js/dom-query@0.15.0: - resolution: {integrity: sha512-gxm7GefQ+ggJE+iN0/kHgbM90DPd4RZYoQC6TQOWy3nxij69IuoSI6goMakJ33hUckszWm9z86Sqe1U1puzssQ==} - dev: false - /@zag-js/dom-query@0.16.0: resolution: {integrity: sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ==} @@ -9097,70 +10362,6 @@ packages: dependencies: '@zag-js/dom-query': 0.16.0 - /@zag-js/form-utils@0.15.0: - resolution: {integrity: sha512-3gFzyF8x48wK2Fabt6rxjMETmhSlwTtCjF10XFrKscL1LZASc3Abl7lJcpTEmVJ5kb5D+50Zw+jlHjHrvddH6g==} - dependencies: - '@zag-js/mutation-observer': 0.15.0 - dev: false - - /@zag-js/mutation-observer@0.15.0: - resolution: {integrity: sha512-7e2d1RYA0nuKOAJknbYBw6XfywF5eFC/4oel/nINHmS14JtjZnjMq/8z/kdrMMJnlQHou+wnaoskOLv+4Sv7pw==} - dev: false - - /@zag-js/number-input@0.15.0: - resolution: {integrity: sha512-WyIGLI4gUm9+53OPCoOmzyZaqT32ALdfZl1QjTVLuDXzckoBgqxaowR0mJU1gDkJ89mSI02p0B0Q89SOiokUfQ==} - dependencies: - '@zag-js/anatomy': 0.15.0 - '@zag-js/core': 0.15.0 - '@zag-js/dom-event': 0.15.0 - '@zag-js/dom-query': 0.15.0 - '@zag-js/form-utils': 0.15.0 - '@zag-js/mutation-observer': 0.15.0 - '@zag-js/number-utils': 0.15.0 - '@zag-js/types': 0.15.0 - '@zag-js/utils': 0.15.0 - dev: false - - /@zag-js/number-utils@0.15.0: - resolution: {integrity: sha512-ebDPCv4UNl5qAe+x55NSUK5gMLbhlqh8mVVq6EnPUqPfbglcjUgNzht78TZ3d+0rdfgC3F8SI3pWaZk9DY4O1Q==} - dev: false - - /@zag-js/react@0.15.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Uygdyq29Y7q5GPOYv1VC9Ya5tdFOs+jdCZk5h5BKzFy3vCSDaVuZ8WT+w7JgvUWh6aQUKjUMLG8lXxWWnJA0Jg==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - dependencies: - '@zag-js/core': 0.15.0 - '@zag-js/store': 0.15.0 - '@zag-js/types': 0.15.0 - proxy-compare: 2.5.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@zag-js/store@0.15.0: - resolution: {integrity: sha512-xq4WFrd+fqJE+Y0Os3FhN2/ru2zxvIvV8IT9y5Ev+3VRZw+L6Ut4tEjOONk+zr+UpkRx3jflPqlekjLHtowp0w==} - dependencies: - proxy-compare: 2.5.1 - dev: false - - /@zag-js/text-selection@0.15.0: - resolution: {integrity: sha512-5i/MkTTBOJN17YylGgvRC+dyO5l3pgz2a/z0xBiIpimYqP1W66P0N1Yq0/5VZubs9TG41jKyEKuulKfcpLwmYg==} - dependencies: - '@zag-js/dom-query': 0.15.0 - dev: false - - /@zag-js/types@0.15.0: - resolution: {integrity: sha512-rkAwZDl6e5p2iXF9HknP03TQ/G9jfOto0x2r2rds4wsPbfVJBNGk0Mo6Jl9GXcpNiyOCOO74SoO9VjZTmMqVvw==} - dependencies: - csstype: 3.1.2 - dev: false - - /@zag-js/utils@0.15.0: - resolution: {integrity: sha512-aNjydiheTKMoIo1wASk3XgN3mbcCiCk2zAiUyldU4JCw9xWevMk5aSszW2v3A0yms6z+qhRb77Z50fejG7OlSA==} - dev: false - /JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -10424,6 +11625,11 @@ packages: engines: {node: '>=6'} dev: false + /clsx@2.1.0: + resolution: {integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==} + engines: {node: '>=6'} + dev: false + /cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} @@ -10928,10 +12134,6 @@ packages: engines: {node: '>=4'} hasBin: true - /csstype@3.1.2: - resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} - dev: false - /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -13525,6 +14727,15 @@ packages: side-channel: 1.0.4 dev: true + /intl-messageformat@10.5.11: + resolution: {integrity: sha512-eYq5fkFBVxc7GIFDzpFQkDOZgNayNTQn4Oufe8jw6YY6OHVw70/4pA3FyCsQ0Gb2DnvEJEMmN2tOaXUGByM+kg==} + dependencies: + '@formatjs/ecma402-abstract': 1.18.2 + '@formatjs/fast-memoize': 2.2.0 + '@formatjs/icu-messageformat-parser': 2.7.6 + tslib: 2.6.2 + dev: false + /invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} dependencies: @@ -14682,6 +15893,7 @@ packages: /klona@2.0.6: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} + dev: true /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} @@ -16869,10 +18081,6 @@ packages: ipaddr.js: 1.9.1 dev: true - /proxy-compare@2.5.1: - resolution: {integrity: sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==} - dev: false - /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -17011,13 +18219,13 @@ packages: performance-now: 2.1.0 dev: false - /rainbow-sprinkles@0.17.1(@vanilla-extract/css@1.14.0)(@vanilla-extract/dynamic@2.1.0): + /rainbow-sprinkles@0.17.1(@vanilla-extract/css@1.14.1)(@vanilla-extract/dynamic@2.1.0): resolution: {integrity: sha512-s/6mCZsBw63mxw976CesRhaLEa3QJVOzEXiuUm3/OKp1R0bBNiCsM3AoAjvazLn3F+BKKxI5sqyNmfah7nTdnQ==} peerDependencies: '@vanilla-extract/css': ^1 '@vanilla-extract/dynamic': ^2 dependencies: - '@vanilla-extract/css': 1.14.0 + '@vanilla-extract/css': 1.14.1 '@vanilla-extract/dynamic': 2.1.0 dev: false @@ -17076,6 +18284,53 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /react-aria@3.31.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-q4jRCVDKO6V2o4Sgir5S2obssw/YnMx6QOy10+p0dYqROHpSnMFNkONrKT1w/nA+Nx4ptfPqZbaNra1hR1bUWg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@internationalized/string': 3.2.0 + '@react-aria/breadcrumbs': 3.5.9(react@18.2.0) + '@react-aria/button': 3.9.1(react@18.2.0) + '@react-aria/calendar': 3.5.4(react-dom@18.2.0)(react@18.2.0) + '@react-aria/checkbox': 3.13.0(react@18.2.0) + '@react-aria/combobox': 3.8.2(react-dom@18.2.0)(react@18.2.0) + '@react-aria/datepicker': 3.9.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/dialog': 3.5.10(react-dom@18.2.0)(react@18.2.0) + '@react-aria/dnd': 3.5.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/focus': 3.16.0(react@18.2.0) + '@react-aria/gridlist': 3.7.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/i18n': 3.10.0(react@18.2.0) + '@react-aria/interactions': 3.20.1(react@18.2.0) + '@react-aria/label': 3.7.4(react@18.2.0) + '@react-aria/link': 3.6.3(react@18.2.0) + '@react-aria/listbox': 3.11.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/menu': 3.12.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/meter': 3.4.9(react@18.2.0) + '@react-aria/numberfield': 3.10.2(react-dom@18.2.0)(react@18.2.0) + '@react-aria/overlays': 3.20.0(react-dom@18.2.0)(react@18.2.0) + '@react-aria/progress': 3.4.9(react@18.2.0) + '@react-aria/radio': 3.10.0(react@18.2.0) + '@react-aria/searchfield': 3.7.1(react@18.2.0) + '@react-aria/select': 3.14.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/selection': 3.17.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/separator': 3.3.9(react@18.2.0) + '@react-aria/slider': 3.7.4(react@18.2.0) + '@react-aria/ssr': 3.9.1(react@18.2.0) + '@react-aria/switch': 3.6.0(react@18.2.0) + '@react-aria/table': 3.13.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/tabs': 3.8.3(react-dom@18.2.0)(react@18.2.0) + '@react-aria/tag': 3.3.1(react-dom@18.2.0)(react@18.2.0) + '@react-aria/textfield': 3.14.1(react@18.2.0) + '@react-aria/tooltip': 3.7.0(react@18.2.0) + '@react-aria/utils': 3.23.0(react@18.2.0) + '@react-aria/visually-hidden': 3.8.8(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /react-clientside-effect@1.2.6(react@18.2.0): resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==} peerDependencies: @@ -17347,6 +18602,37 @@ packages: - '@types/react' dev: false + /react-stately@3.29.1(react@18.2.0): + resolution: {integrity: sha512-hc4ZHy/ahvMwr6z7XMjYJ7EgzNVrXhzM4l2Qj17rdRhERo7/ovWmQencf9pF7K8kD5TraEHxPHLrYzGN4fxfUQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + dependencies: + '@react-stately/calendar': 3.4.3(react@18.2.0) + '@react-stately/checkbox': 3.6.1(react@18.2.0) + '@react-stately/collections': 3.10.4(react@18.2.0) + '@react-stately/combobox': 3.8.1(react@18.2.0) + '@react-stately/data': 3.11.0(react@18.2.0) + '@react-stately/datepicker': 3.9.1(react@18.2.0) + '@react-stately/dnd': 3.2.7(react@18.2.0) + '@react-stately/form': 3.0.0(react@18.2.0) + '@react-stately/list': 3.10.2(react@18.2.0) + '@react-stately/menu': 3.6.0(react@18.2.0) + '@react-stately/numberfield': 3.8.0(react@18.2.0) + '@react-stately/overlays': 3.6.4(react@18.2.0) + '@react-stately/radio': 3.10.1(react@18.2.0) + '@react-stately/searchfield': 3.5.0(react@18.2.0) + '@react-stately/select': 3.6.1(react@18.2.0) + '@react-stately/selection': 3.14.2(react@18.2.0) + '@react-stately/slider': 3.5.0(react@18.2.0) + '@react-stately/table': 3.11.4(react@18.2.0) + '@react-stately/tabs': 3.6.3(react@18.2.0) + '@react-stately/toggle': 3.7.0(react@18.2.0) + '@react-stately/tooltip': 3.4.6(react@18.2.0) + '@react-stately/tree': 3.7.5(react@18.2.0) + '@react-types/shared': 3.22.0(react@18.2.0) + react: 18.2.0 + dev: false + /react-style-singleton@2.2.1(@types/react@18.2.48)(react@18.2.0): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} diff --git a/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts b/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts new file mode 100644 index 000000000..06c692ce4 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts @@ -0,0 +1,314 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import big from "big.js"; +import type Big from "big.js"; +import dayjs from "dayjs"; + +import { StatusSummary } from "../status-summary"; +import { ProposalStatus } from "lib/types"; +import type { ProposalParams, ProposalData, Token, U } from "lib/types"; + +const meta: Meta = { + component: StatusSummary, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], +}; + +export default meta; +type Story = StoryObj; + +const data: Omit< + ProposalData, + "status" | "depositEndTime" | "votingEndTime" | "resolvedTimestamp" +> = { + id: 999, + title: "storybook", + resolvedHeight: null, + types: [], + proposer: undefined, + isExpedited: false, + createdHeight: null, + createdTimestamp: null, + createdTxHash: null, + description: "This is a description.", + messages: null, + metadata: "metadata", + proposalDeposits: [], + submitTime: dayjs("01 Jan 1970 00:00:00 UTC").toDate(), + totalDeposit: [ + { + isLPToken: false, + denom: "denom", + amount: big(1000000) as U>, + precision: 10, + symbol: "CLTN", + logo: undefined, + price: undefined, + value: undefined, + }, + ], + version: "v1", + votingTime: null, +}; + +const params: ProposalParams = { + minDeposit: [ + { + isLPToken: false, + denom: "denom", + amount: big(10000000) as U>, + precision: 10, + symbol: "CLTN", + logo: undefined, + price: undefined, + value: undefined, + }, + ], + minInitialDepositRatio: 0.2, + maxDepositPeriod: "", + votingPeriod: "", + vetoThreshold: 0.3, + quorum: 0.3, + threshold: 0.5, +}; + +export const DepositPeriod: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.DEPOSIT_PERIOD, + depositEndTime: dayjs().utc().add(2, "days").toDate(), + votingEndTime: null, + resolvedTimestamp: null, + }, + params, + votesInfo: { + yes: big(0), + abstain: big(0), + no: big(0), + noWithVeto: big(0), + totalVotingPower: big(0), + }, + }, +}; + +export const VotingPeriodRejectedQuorum: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.VOTING_PERIOD, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: dayjs().utc().add(2, "days").toDate(), + resolvedTimestamp: null, + }, + params, + votesInfo: { + yes: big(1), + abstain: big(1), + no: big(0), + noWithVeto: big(0), + totalVotingPower: big(10), + }, + }, +}; + +export const VotingPeriodRejectedNoWithVeto: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.VOTING_PERIOD, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: dayjs().utc().add(2, "days").toDate(), + resolvedTimestamp: null, + }, + params, + votesInfo: { + yes: big(1), + abstain: big(1), + no: big(1), + noWithVeto: big(4), + totalVotingPower: big(10), + }, + }, +}; + +export const VotingPeriodRejectedNotPassed: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.VOTING_PERIOD, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: dayjs().utc().add(2, "days").toDate(), + resolvedTimestamp: null, + }, + params, + votesInfo: { + yes: big(2), + abstain: big(1), + no: big(1), + noWithVeto: big(1), + totalVotingPower: big(10), + }, + }, +}; + +export const VotingPeriodPassed: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.VOTING_PERIOD, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: dayjs().utc().add(2, "days").toDate(), + resolvedTimestamp: null, + }, + params, + votesInfo: { + yes: big(3), + abstain: big(1), + no: big(1), + noWithVeto: big(1), + totalVotingPower: big(10), + }, + }, +}; + +export const Failed: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.FAILED, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: dayjs().utc().toDate(), + resolvedTimestamp: dayjs().utc().toDate(), + }, + params, + votesInfo: { + yes: big(2), + abstain: big(1), + no: big(1), + noWithVeto: big(1), + totalVotingPower: big(10), + }, + }, +}; + +export const RejectedQuorum: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.REJECTED, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: dayjs().utc().toDate(), + resolvedTimestamp: dayjs().utc().toDate(), + }, + params, + votesInfo: { + yes: big(1), + abstain: big(1), + no: big(0), + noWithVeto: big(0), + totalVotingPower: big(10), + }, + }, +}; + +export const RejectedNoWithVeto: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.REJECTED, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: dayjs().utc().toDate(), + resolvedTimestamp: dayjs().utc().toDate(), + }, + params, + votesInfo: { + yes: big(1), + abstain: big(1), + no: big(1), + noWithVeto: big(4), + totalVotingPower: big(10), + }, + }, +}; + +export const RejectedNotPassed: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.REJECTED, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: dayjs().utc().toDate(), + resolvedTimestamp: dayjs().utc().toDate(), + }, + params, + votesInfo: { + yes: big(2), + abstain: big(1), + no: big(1), + noWithVeto: big(1), + totalVotingPower: big(10), + }, + }, +}; + +export const Passed: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.PASSED, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: dayjs().utc().toDate(), + resolvedTimestamp: dayjs().utc().toDate(), + }, + params, + votesInfo: { + yes: big(3), + abstain: big(1), + no: big(1), + noWithVeto: big(1), + totalVotingPower: big(10), + }, + }, +}; + +export const Cancelled: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.CANCELLED, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: dayjs().utc().toDate(), + resolvedTimestamp: dayjs().utc().toDate(), + }, + params, + votesInfo: { + yes: big(3), + abstain: big(1), + no: big(1), + noWithVeto: big(1), + totalVotingPower: big(10), + }, + }, +}; + +export const DepositFailed: Story = { + args: { + proposalData: { + ...data, + status: ProposalStatus.DEPOSIT_FAILED, + depositEndTime: dayjs().utc().toDate(), + votingEndTime: null, + resolvedTimestamp: dayjs().utc().toDate(), + }, + params, + votesInfo: { + yes: big(0), + abstain: big(0), + no: big(0), + noWithVeto: big(0), + totalVotingPower: big(0), + }, + }, +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx index 00e708ef3..a9b8b71be 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx @@ -1,7 +1,6 @@ /* eslint-disable sonarjs/cognitive-complexity */ import { SkeletonText, Text } from "@chakra-ui/react"; -import type Big from "big.js"; -import { roundHalfUp } from "big.js"; +import big from "big.js"; import type { ProposalOverviewProps } from ".."; import { ErrorFetching } from "lib/components/state"; @@ -45,7 +44,7 @@ export const SummaryStatusBody = ({ if (isLoading) return ; if (!params || !votesInfo) - return ; + return ; const { minDeposit, quorum, threshold, vetoThreshold } = extractParams( params, @@ -85,7 +84,7 @@ export const SummaryStatusBody = ({ ); - if (noWithVeto.lt(vetoThreshold)) + if (noWithVeto.gte(vetoThreshold)) return ( The proposal has successfully met the voting quorum. However, if the @@ -102,7 +101,7 @@ export const SummaryStatusBody = ({ ); - if (yes.lt(threshold)) + if (currentTotalVotes.eq(0) || yes.div(currentTotalVotes).lt(threshold)) return ( The proposal has{" "} @@ -131,9 +130,9 @@ export const SummaryStatusBody = ({ if (proposalData.status === ProposalStatus.FAILED) return ( - Although the proposal successfully reached the voting quorum with a - {yes.mul(100).round(2, roundHalfUp).toNumber()}% “Yes” rate, - it was not implemented due to technical reasons. + Although the proposal successfully reached the voting quorum with a{" "} + {yes.mul(100).round(2, big.roundHalfUp).toNumber()}% “Yes” + rate, it was not implemented due to technical reasons. ); @@ -146,7 +145,7 @@ export const SummaryStatusBody = ({ ); - if (noWithVeto.lt(vetoThreshold)) + if (noWithVeto.gte(vetoThreshold)) return ( This proposal has{" "} @@ -180,7 +179,8 @@ export const SummaryStatusBody = ({ fontWeight: 700, }} > - {yes.mul(100).round(2, roundHalfUp).toNumber()}% of “Yes” + {yes.mul(100).round(2, big.roundHalfUp).toNumber()}% of + “Yes” {" "} rate. As a result, the proposal has been passed, and its content will now be implemented. diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx index 61ad04705..d2003fd69 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx @@ -37,8 +37,9 @@ export const SummaryStatusChip = ({ { + if (votesInfo.totalVotingPower.eq(0)) + return { + yes: big(0), + abstain: big(0), + no: big(0), + noWithVeto: big(0), + currentTotalVotes: big(0), + }; + const yes = votesInfo.yes.div(votesInfo.totalVotingPower); const abstain = votesInfo.abstain.div(votesInfo.totalVotingPower); const no = votesInfo.no.div(votesInfo.totalVotingPower); From ad80d0194b38b57fef4019add8875b86c50f9c54 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Thu, 8 Feb 2024 10:29:01 +0700 Subject: [PATCH 091/531] fix: dot animation easeinout --- .../components/proposal-overview/status-summary/ActiveDot.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx index acff34b22..dbb12e62d 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx @@ -17,6 +17,7 @@ export const ActiveDot = ({ status }: ActiveDotProps) => transition={{ duration: 1.5, repeat: Infinity, + ease: "easeInOut", }} /> ); From 5dd925137879d9862584765d9acaf7bdebf70b16 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Thu, 8 Feb 2024 10:40:54 +0700 Subject: [PATCH 092/531] refactor(pages): add zod validator to code details page code id params url --- src/lib/pages/code-details/index.tsx | 18 ++++++++++++++---- src/lib/pages/code-details/types.ts | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/lib/pages/code-details/types.ts diff --git a/src/lib/pages/code-details/index.tsx b/src/lib/pages/code-details/index.tsx index 6a975d77e..d22ae9eb3 100644 --- a/src/lib/pages/code-details/index.tsx +++ b/src/lib/pages/code-details/index.tsx @@ -21,6 +21,7 @@ import { getFirstQueryParam, isId } from "lib/utils"; import { CodeInfoSection, CodeContractsTable } from "./components/code-info"; import { CodeTopInfo } from "./components/code-info/CodeTopInfo"; import { CodeSchemaSection } from "./components/json-schema/CodeSchemaSection"; +import { zCodeDetailsQueryParams } from "./types"; const codeTabId = "codeDetailsTab"; @@ -144,16 +145,25 @@ const CodeDetailsBody = observer( const CodeDetails = observer(() => { useWasmConfig({ shouldRedirect: true }); const router = useRouter(); - const codeIdParam = getFirstQueryParam(router.query.codeId); - const data = useCodeData(codeIdParam); + + const validated = zCodeDetailsQueryParams.safeParse(router.query); + + if (!validated.success) { + return ; + } + + const { codeId } = validated.data; + + const data = useCodeData(codeId); if (data.isLoading) return ; + return ( - {!isId(codeIdParam) ? ( + {!isId(codeId) ? ( ) : ( - + )} ); diff --git a/src/lib/pages/code-details/types.ts b/src/lib/pages/code-details/types.ts new file mode 100644 index 000000000..e29374aa6 --- /dev/null +++ b/src/lib/pages/code-details/types.ts @@ -0,0 +1,15 @@ +import { z } from "zod"; + +export const zCodeDetailsQueryParams = z.object({ + codeId: z.string().refine( + (val) => { + const code = Number(val); + const isInteger = Number.isInteger(code); + + return isInteger && code > 0; + }, + { + message: "Invalid code id", + } + ), +}); From 12faeb2f236da67a416d553874d20e2a24743d07 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Thu, 8 Feb 2024 10:52:17 +0700 Subject: [PATCH 093/531] refactor(pages): update zod validator to use utils function for validate code id --- CHANGELOG.md | 1 + src/lib/pages/code-details/index.tsx | 8 ++------ src/lib/pages/code-details/types.ts | 7 +++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9385b17a3..1ac341be6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#772](https://github.com/alleslabs/celatone-frontend/pull/772) Add zod validator to code details page code id params - [#770](https://github.com/alleslabs/celatone-frontend/pull/770) Add unit test for account store (mobx) - [#769](https://github.com/alleslabs/celatone-frontend/pull/769) Add unit test for format.test.ts on shortenName function - [#768](https://github.com/alleslabs/celatone-frontend/pull/768) Add unit test for truncate.test.ts diff --git a/src/lib/pages/code-details/index.tsx b/src/lib/pages/code-details/index.tsx index d22ae9eb3..04454d6a8 100644 --- a/src/lib/pages/code-details/index.tsx +++ b/src/lib/pages/code-details/index.tsx @@ -16,7 +16,7 @@ import { InvalidState } from "lib/components/state"; import type { CodeDataState } from "lib/model/code"; import { useCodeData } from "lib/model/code"; import { useSchemaStore } from "lib/providers/store"; -import { getFirstQueryParam, isId } from "lib/utils"; +import { getFirstQueryParam } from "lib/utils"; import { CodeInfoSection, CodeContractsTable } from "./components/code-info"; import { CodeTopInfo } from "./components/code-info/CodeTopInfo"; @@ -160,11 +160,7 @@ const CodeDetails = observer(() => { return ( - {!isId(codeId) ? ( - - ) : ( - - )} + ); }); diff --git a/src/lib/pages/code-details/types.ts b/src/lib/pages/code-details/types.ts index e29374aa6..dd6bcd03c 100644 --- a/src/lib/pages/code-details/types.ts +++ b/src/lib/pages/code-details/types.ts @@ -1,12 +1,11 @@ import { z } from "zod"; +import { isId } from "lib/utils"; + export const zCodeDetailsQueryParams = z.object({ codeId: z.string().refine( (val) => { - const code = Number(val); - const isInteger = Number.isInteger(code); - - return isInteger && code > 0; + return isId(val); }, { message: "Invalid code id", From 383a0c06a40f8fa3bddc867dd65f4bb813b4cfad Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Thu, 8 Feb 2024 11:03:17 +0700 Subject: [PATCH 094/531] refactor(pages): update zod validator --- src/lib/model/code.ts | 13 +++++++++---- src/lib/pages/code-details/types.ts | 11 +---------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/lib/model/code.ts b/src/lib/model/code.ts index 680005a6a..532e1c52e 100644 --- a/src/lib/model/code.ts +++ b/src/lib/model/code.ts @@ -42,11 +42,16 @@ export interface CodeDataState { }; } -export const useCodeData = (codeId: string): CodeDataState => { +export const useCodeData = (codeId: number): CodeDataState => { const { currentChainId } = useCelatoneApp(); - const { data: codeInfo, isLoading } = useCodeDataByCodeId({ codeId }); - const { data: publicCodeInfo } = usePublicProjectByCodeId(codeId); + // TODO: Change codeId to integer + const codeStr = codeId.toString(); + + const { data: codeInfo, isLoading } = useCodeDataByCodeId({ + codeId: codeStr, + }); + const { data: publicCodeInfo } = usePublicProjectByCodeId(codeStr); const { data: publicInfoBySlug } = usePublicProjectBySlug( publicCodeInfo?.slug ); @@ -54,7 +59,7 @@ export const useCodeData = (codeId: string): CodeDataState => { data: lcdCode, isLoading: isLcdCodeLoading, error: isLcdCodeError, - } = useLCDCodeInfo(codeId); + } = useLCDCodeInfo(codeStr); return { isLoading, diff --git a/src/lib/pages/code-details/types.ts b/src/lib/pages/code-details/types.ts index dd6bcd03c..a7e1cd739 100644 --- a/src/lib/pages/code-details/types.ts +++ b/src/lib/pages/code-details/types.ts @@ -1,14 +1,5 @@ import { z } from "zod"; -import { isId } from "lib/utils"; - export const zCodeDetailsQueryParams = z.object({ - codeId: z.string().refine( - (val) => { - return isId(val); - }, - { - message: "Invalid code id", - } - ), + codeId: z.coerce.number().positive(), }); From 723c610110fc9a87023759a0be87f0b988568539 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Thu, 8 Feb 2024 11:17:03 +0700 Subject: [PATCH 095/531] refactor(utils): update account test file --- src/lib/stores/account.test.ts | 35 +++++++++++----------------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/src/lib/stores/account.test.ts b/src/lib/stores/account.test.ts index 8c13eab36..d7ac78af7 100644 --- a/src/lib/stores/account.test.ts +++ b/src/lib/stores/account.test.ts @@ -4,6 +4,7 @@ import { AccountStore } from "./account"; describe("accountStore", () => { let accountStore: AccountStore; + const address = zBechAddr.parse("address"); beforeEach(() => { accountStore = new AccountStore(); @@ -18,20 +19,12 @@ describe("accountStore", () => { }); test("account info", () => { - expect( - accountStore.getAccountLocalInfo(zBechAddr.parse("address")) - ).toBeUndefined(); - - accountStore.updateAccountLocalInfo( - zBechAddr.parse("address"), - "name", - "description" - ); - - expect( - accountStore.getAccountLocalInfo(zBechAddr.parse("address")) - ).toEqual({ - address: zBechAddr.parse("address"), + expect(accountStore.getAccountLocalInfo(address)).toBeUndefined(); + + accountStore.updateAccountLocalInfo(address, "name", "description"); + + expect(accountStore.getAccountLocalInfo(address)).toEqual({ + address: "address", name: "name", description: "description", }); @@ -39,21 +32,15 @@ describe("accountStore", () => { test("saved account", () => { expect(accountStore.savedAccounts).toEqual({}); - expect(accountStore.isAccountSaved(zBechAddr.parse("address"))).toBeFalsy(); + expect(accountStore.isAccountSaved(address)).toBeFalsy(); - accountStore.updateAccountLocalInfo( - zBechAddr.parse("address"), - "name", - "description" - ); + accountStore.updateAccountLocalInfo(address, "name", "description"); - expect( - accountStore.isAccountSaved(zBechAddr.parse("address")) - ).toBeTruthy(); + expect(accountStore.isAccountSaved(address)).toBeTruthy(); expect(accountStore.getSavedAccounts()).toEqual([ { - address: zBechAddr.parse("address"), + address: "address", name: "name", description: "description", }, From e6505865bbbacca814bb9b4080b1f5a4aab61846 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Thu, 8 Feb 2024 11:33:30 +0700 Subject: [PATCH 096/531] fix: router --- src/lib/amplitude/types.ts | 1 + src/lib/pages/proposal-details/index.tsx | 24 +++++++----------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/lib/amplitude/types.ts b/src/lib/amplitude/types.ts index e67d65515..df70c1c10 100644 --- a/src/lib/amplitude/types.ts +++ b/src/lib/amplitude/types.ts @@ -60,6 +60,7 @@ export enum AmpEvent { TO_FAUCET = "To Faucet", TO_POOL_LIST = "To Pool List", TO_POOL_DETAILS = "To Pool Detail", + TO_PROPOSAL_DETAILS = "To Proposal Detail", TO_PROPOSAL_TO_STORE_CODE = "To Proposal To Store Code", TO_PROPOSAL_TO_WHITELIST = "To Proposal To Whitelist", TO_MODULE_DETAILS = "To Module Detail", diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index ec349a5c5..1cc51338c 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -2,6 +2,7 @@ import { TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"; import { useRouter } from "next/router"; import { useCallback, useEffect } from "react"; +import { AmpEvent, track } from "lib/amplitude"; import { useGovConfig, useInternalNavigate } from "lib/app-provider"; import { CustomTab } from "lib/components/CustomTab"; import { Loading } from "lib/components/Loading"; @@ -21,7 +22,6 @@ const ProposalDetailsBody = ({ }: ProposalDetailsQueryParams) => { useGovConfig({ shouldRedirect: true }); - const router = useRouter(); const navigate = useInternalNavigate(); const { data, isLoading } = useDerivedProposalData(id); const { data: votesInfo, isLoading: isVotesInfoLoading } = @@ -46,22 +46,6 @@ const ProposalDetailsBody = ({ [id, tab, navigate] ); - useEffect(() => { - if (router.isReady && (!tab || !Object.values(TabIndex).includes(tab))) { - navigate({ - replace: true, - pathname: "/proposals/[id]/[tab]", - query: { - id, - tab: TabIndex.Overview, - }, - options: { - shallow: true, - }, - }); - } - }, [router.isReady, tab, navigate, id]); - if (isLoading) return ; if (!data) return ; if (!data.info) return ; @@ -109,6 +93,12 @@ const ProposalDetails = () => { const validated = zProposalDetailsQueryParams.safeParse(router.query); + useEffect(() => { + if (router.isReady && validated.success) + track(AmpEvent.TO_PROPOSAL_DETAILS, { tab: validated.data.tab }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [router.isReady]); + return ( {!validated.success ? ( From 9d56cd3922429454b4c25392992577f27c9ca7c3 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Thu, 8 Feb 2024 13:17:06 +0700 Subject: [PATCH 097/531] refactor(pages): update code details page component --- src/lib/pages/code-details/index.tsx | 229 +++++++++++++-------------- 1 file changed, 111 insertions(+), 118 deletions(-) diff --git a/src/lib/pages/code-details/index.tsx b/src/lib/pages/code-details/index.tsx index 04454d6a8..03ca817f4 100644 --- a/src/lib/pages/code-details/index.tsx +++ b/src/lib/pages/code-details/index.tsx @@ -13,7 +13,6 @@ import { CustomTab } from "lib/components/CustomTab"; import { Loading } from "lib/components/Loading"; import PageContainer from "lib/components/PageContainer"; import { InvalidState } from "lib/components/state"; -import type { CodeDataState } from "lib/model/code"; import { useCodeData } from "lib/model/code"; import { useSchemaStore } from "lib/providers/store"; import { getFirstQueryParam } from "lib/utils"; @@ -30,117 +29,117 @@ enum TabIndex { JsonSchema = "schema", } interface CodeDetailsBodyProps { - codeDataState: CodeDataState; codeId: number; } const InvalidCode = () => ; -const CodeDetailsBody = observer( - ({ codeDataState, codeId }: CodeDetailsBodyProps) => { - const router = useRouter(); - const navigate = useInternalNavigate(); - const { - chainId, - codeData, - lcdCodeData: { codeHash, isLcdCodeLoading }, - } = codeDataState; - const { getSchemaByCodeHash } = useSchemaStore(); - const jsonSchema = codeHash ? getSchemaByCodeHash(codeHash) : undefined; - const isMobile = useMobile(); - const tab = getFirstQueryParam(router.query.tab) as TabIndex; - - useEffect(() => { - if (router.isReady) track(AmpEvent.TO_CODE_DETAILS, { tab }); - // Note: we don't want to track when tab changes - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [router.isReady, track]); - - const handleTabChange = useCallback( - (nextTab: TabIndex) => () => { - if (nextTab === tab) return; - navigate({ - pathname: "/codes/[codeId]/[tab]", - query: { - codeId, - tab: nextTab, - }, - options: { - shallow: true, - }, - }); - }, - [codeId, tab, navigate] - ); - - useEffect(() => { - if (router.isReady && (!tab || !Object.values(TabIndex).includes(tab))) { - navigate({ - replace: true, - pathname: "/codes/[codeId]/[tab]", - query: { - codeId, - tab: TabIndex.CodeInfo, - }, - options: { - shallow: true, - }, - }); - } - }, [router.isReady, tab, codeId, navigate]); - - if (!codeData) return ; - - return ( - <> - - - {!isMobile && ( - - - Code Information - - - JSON Schema - - - )} - - - - - - - - - - - - ); - } -); +const CodeDetailsBody = observer(({ codeId }: CodeDetailsBodyProps) => { + const router = useRouter(); + const codeDataState = useCodeData(codeId); + const navigate = useInternalNavigate(); + const { + chainId, + codeData, + lcdCodeData: { codeHash, isLcdCodeLoading }, + } = codeDataState; + const { getSchemaByCodeHash } = useSchemaStore(); + const jsonSchema = codeHash ? getSchemaByCodeHash(codeHash) : undefined; + const isMobile = useMobile(); + const tab = getFirstQueryParam(router.query.tab) as TabIndex; + + useEffect(() => { + if (router.isReady) track(AmpEvent.TO_CODE_DETAILS, { tab }); + // Note: we don't want to track when tab changes + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [router.isReady, track]); + + const handleTabChange = useCallback( + (nextTab: TabIndex) => () => { + if (nextTab === tab) return; + navigate({ + pathname: "/codes/[codeId]/[tab]", + query: { + codeId, + tab: nextTab, + }, + options: { + shallow: true, + }, + }); + }, + [codeId, tab, navigate] + ); + + useEffect(() => { + if (router.isReady && (!tab || !Object.values(TabIndex).includes(tab))) { + navigate({ + replace: true, + pathname: "/codes/[codeId]/[tab]", + query: { + codeId, + tab: TabIndex.CodeInfo, + }, + options: { + shallow: true, + }, + }); + } + }, [router.isReady, tab, codeId, navigate]); + + if (codeDataState.isLoading) return ; + + if (!codeData) return ; + + return ( + <> + + + {!isMobile && ( + + + Code Information + + + JSON Schema + + + )} + + + + + + + + + + + + ); +}); const CodeDetails = observer(() => { useWasmConfig({ shouldRedirect: true }); @@ -148,19 +147,13 @@ const CodeDetails = observer(() => { const validated = zCodeDetailsQueryParams.safeParse(router.query); - if (!validated.success) { - return ; - } - - const { codeId } = validated.data; - - const data = useCodeData(codeId); - - if (data.isLoading) return ; - return ( - + {validated.success ? ( + + ) : ( + + )} ); }); From 5d4d51e1d768a056b630d66beed727705425f2d3 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Thu, 8 Feb 2024 13:24:10 +0700 Subject: [PATCH 098/531] refactor(pages): update code details page component --- src/lib/pages/code-details/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/pages/code-details/index.tsx b/src/lib/pages/code-details/index.tsx index 03ca817f4..9acb66994 100644 --- a/src/lib/pages/code-details/index.tsx +++ b/src/lib/pages/code-details/index.tsx @@ -150,7 +150,7 @@ const CodeDetails = observer(() => { return ( {validated.success ? ( - + ) : ( )} From b5203364b38b440d3585bbc9bebc05457119ace4 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Thu, 8 Feb 2024 13:35:42 +0700 Subject: [PATCH 099/531] refactor(pages): update code details page to handle tab change with zod validator --- src/lib/pages/code-details/index.tsx | 33 +++++----------------------- src/lib/pages/code-details/types.ts | 12 ++++++++++ 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/lib/pages/code-details/index.tsx b/src/lib/pages/code-details/index.tsx index 9acb66994..42acff7aa 100644 --- a/src/lib/pages/code-details/index.tsx +++ b/src/lib/pages/code-details/index.tsx @@ -15,26 +15,22 @@ import PageContainer from "lib/components/PageContainer"; import { InvalidState } from "lib/components/state"; import { useCodeData } from "lib/model/code"; import { useSchemaStore } from "lib/providers/store"; -import { getFirstQueryParam } from "lib/utils"; import { CodeInfoSection, CodeContractsTable } from "./components/code-info"; import { CodeTopInfo } from "./components/code-info/CodeTopInfo"; import { CodeSchemaSection } from "./components/json-schema/CodeSchemaSection"; -import { zCodeDetailsQueryParams } from "./types"; +import { zCodeDetailsQueryParams, TabIndex } from "./types"; const codeTabId = "codeDetailsTab"; -enum TabIndex { - CodeInfo = "info", - JsonSchema = "schema", -} interface CodeDetailsBodyProps { codeId: number; + tab: TabIndex; } const InvalidCode = () => ; -const CodeDetailsBody = observer(({ codeId }: CodeDetailsBodyProps) => { +const CodeDetailsBody = observer(({ codeId, tab }: CodeDetailsBodyProps) => { const router = useRouter(); const codeDataState = useCodeData(codeId); const navigate = useInternalNavigate(); @@ -46,13 +42,11 @@ const CodeDetailsBody = observer(({ codeId }: CodeDetailsBodyProps) => { const { getSchemaByCodeHash } = useSchemaStore(); const jsonSchema = codeHash ? getSchemaByCodeHash(codeHash) : undefined; const isMobile = useMobile(); - const tab = getFirstQueryParam(router.query.tab) as TabIndex; useEffect(() => { if (router.isReady) track(AmpEvent.TO_CODE_DETAILS, { tab }); - // Note: we don't want to track when tab changes // eslint-disable-next-line react-hooks/exhaustive-deps - }, [router.isReady, track]); + }, [router.isReady]); const handleTabChange = useCallback( (nextTab: TabIndex) => () => { @@ -71,22 +65,6 @@ const CodeDetailsBody = observer(({ codeId }: CodeDetailsBodyProps) => { [codeId, tab, navigate] ); - useEffect(() => { - if (router.isReady && (!tab || !Object.values(TabIndex).includes(tab))) { - navigate({ - replace: true, - pathname: "/codes/[codeId]/[tab]", - query: { - codeId, - tab: TabIndex.CodeInfo, - }, - options: { - shallow: true, - }, - }); - } - }, [router.isReady, tab, codeId, navigate]); - if (codeDataState.isLoading) return ; if (!codeData) return ; @@ -144,13 +122,12 @@ const CodeDetailsBody = observer(({ codeId }: CodeDetailsBodyProps) => { const CodeDetails = observer(() => { useWasmConfig({ shouldRedirect: true }); const router = useRouter(); - const validated = zCodeDetailsQueryParams.safeParse(router.query); return ( {validated.success ? ( - + ) : ( )} diff --git a/src/lib/pages/code-details/types.ts b/src/lib/pages/code-details/types.ts index a7e1cd739..ccd6eb1bc 100644 --- a/src/lib/pages/code-details/types.ts +++ b/src/lib/pages/code-details/types.ts @@ -1,5 +1,17 @@ import { z } from "zod"; +export enum TabIndex { + CodeInfo = "info", + JsonSchema = "schema", +} + export const zCodeDetailsQueryParams = z.object({ codeId: z.coerce.number().positive(), + tab: z.union([ + z.nativeEnum(TabIndex), + z + .string() + .optional() + .transform(() => TabIndex.CodeInfo), + ]), }); From 925ea8fe64dc23ce274c439619f5ad9c795cdb40 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Fri, 9 Feb 2024 14:09:26 +0700 Subject: [PATCH 100/531] fix(components): add relevant contract to cosmwasm pool --- CHANGELOG.md | 1 + .../components/pool-details/header/PoolInfo.tsx | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0196ba93c..eba303d56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#774](https://github.com/alleslabs/celatone-frontend/pull/774) Add relevant contract to cosmwasm pool - [#772](https://github.com/alleslabs/celatone-frontend/pull/772) Add zod validator to code details page code id params - [#770](https://github.com/alleslabs/celatone-frontend/pull/770) Add unit test for account store (mobx) - [#769](https://github.com/alleslabs/celatone-frontend/pull/769) Add unit test for format.test.ts on shortenName function diff --git a/src/lib/pages/pools/components/pool-details/header/PoolInfo.tsx b/src/lib/pages/pools/components/pool-details/header/PoolInfo.tsx index a7df11ef4..5cce78660 100644 --- a/src/lib/pages/pools/components/pool-details/header/PoolInfo.tsx +++ b/src/lib/pages/pools/components/pool-details/header/PoolInfo.tsx @@ -19,6 +19,7 @@ export const PoolInfo = ({ pool }: PoolInfoProps) => { const futurePoolGovernorType = getAddressType( pool.futurePoolGovernor ?? undefined ); + return ( { )} )} - {pool.tickSpacing !== null && ( { /> )} + {pool.type === PoolType.COSMWASM && pool.contractAddress && ( + + + + + + )} ); }; From 10da79d7edb23a155f0628099ff66b840418a97b Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 9 Feb 2024 14:56:42 +0700 Subject: [PATCH 101/531] feat: proposal period overview deposit --- CHANGELOG.md | 1 + src/lib/components/icon/CustomIcon.tsx | 11 +++ src/lib/components/token/TokenComposition.tsx | 27 ++++-- .../proposal-details/components/ActiveDot.tsx | 19 +++++ .../components/DepositList.tsx | 44 ++++++++++ .../components/ErrorFetchingProposalInfos.tsx | 13 +++ .../components/ProgressBadge.tsx | 56 ++++++++++++ .../components/deposit-bar/DepositRatio.tsx | 51 +++++++++++ .../components/deposit-bar/ProgressBar.tsx | 47 ++++++++++ .../components/deposit-bar/index.tsx | 44 ++++++++++ .../components/proposal-overview/index.tsx | 20 ++--- .../DepositPeriodOverview.tsx | 85 +++++++++++++++++++ .../proposal-period-overview/index.tsx | 20 +++++ .../status-summary/ActiveDot.tsx | 23 ----- .../status-summary/SummaryStatusBody.tsx | 10 +-- .../status-summary/index.tsx | 4 +- .../components/proposal-stepper/StepIcon.tsx | 69 +++++++++++++++ .../components/proposal-stepper/index.tsx | 35 ++++++++ .../components/proposal-stepper/utils.ts | 42 +++++++++ src/lib/pages/proposal-details/data.ts | 8 +- src/lib/pages/proposal-details/index.tsx | 5 +- src/lib/pages/proposal-details/utils.ts | 3 + 22 files changed, 584 insertions(+), 53 deletions(-) create mode 100644 src/lib/pages/proposal-details/components/ActiveDot.tsx create mode 100644 src/lib/pages/proposal-details/components/DepositList.tsx create mode 100644 src/lib/pages/proposal-details/components/ErrorFetchingProposalInfos.tsx create mode 100644 src/lib/pages/proposal-details/components/ProgressBadge.tsx create mode 100644 src/lib/pages/proposal-details/components/deposit-bar/DepositRatio.tsx create mode 100644 src/lib/pages/proposal-details/components/deposit-bar/ProgressBar.tsx create mode 100644 src/lib/pages/proposal-details/components/deposit-bar/index.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositPeriodOverview.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx delete mode 100644 src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-stepper/StepIcon.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-stepper/index.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-stepper/utils.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c50dc329..a20422bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#775](https://github.com/alleslabs/celatone-frontend/pull/766) Proposal period overview deposit - [#766](https://github.com/alleslabs/celatone-frontend/pull/766) Proposal status summary body - [#763](https://github.com/alleslabs/celatone-frontend/pull/763) Proposal status summary top - [#765](https://github.com/alleslabs/celatone-frontend/pull/765) Support Proposal Cancelled status diff --git a/src/lib/components/icon/CustomIcon.tsx b/src/lib/components/icon/CustomIcon.tsx index 0e204cc11..9a1ba1cda 100644 --- a/src/lib/components/icon/CustomIcon.tsx +++ b/src/lib/components/icon/CustomIcon.tsx @@ -488,6 +488,17 @@ export const ICONS = { ), viewBox: "-2 -4 16 16", }, + circle: { + svg: ( + + ), + viewBox: viewboxDefault, + }, close: { svg: ( ( @@ -22,7 +26,9 @@ export const TokenComposition = ({ {formatUTokenWithPrecision( token.poolInfo.coinA.amount, - token.poolInfo.coinA.precision ?? 0 + token.poolInfo.coinA.precision ?? 0, + true, + decimal )} {getTokenLabel( @@ -37,7 +43,9 @@ export const TokenComposition = ({ {formatUTokenWithPrecision( token.poolInfo.coinB.amount, - token.poolInfo.coinB.precision ?? 0 + token.poolInfo.coinB.precision ?? 0, + true, + decimal )} {getTokenLabel( @@ -49,13 +57,20 @@ export const TokenComposition = ({ ) : ( - {formatUTokenWithPrecision(token.amount, token.precision ?? 0)} + {formatUTokenWithPrecision( + token.amount, + token.precision ?? 0, + true, + decimal + )} {getTokenLabel(token.denom, token.symbol)} )} - - {token.value ? `(≈ ${formatPrice(token.value)})` : "-"} - + {displayValue && ( + + {token.value ? `(≈ ${formatPrice(token.value)})` : "-"} + + )} ); diff --git a/src/lib/pages/proposal-details/components/ActiveDot.tsx b/src/lib/pages/proposal-details/components/ActiveDot.tsx new file mode 100644 index 000000000..c3b81bff8 --- /dev/null +++ b/src/lib/pages/proposal-details/components/ActiveDot.tsx @@ -0,0 +1,19 @@ +import type { BoxProps } from "@chakra-ui/react"; + +import { MotionBox } from "lib/components/MotionBox"; + +export const ActiveDot = (props: BoxProps) => ( + +); diff --git a/src/lib/pages/proposal-details/components/DepositList.tsx b/src/lib/pages/proposal-details/components/DepositList.tsx new file mode 100644 index 000000000..c9a353c91 --- /dev/null +++ b/src/lib/pages/proposal-details/components/DepositList.tsx @@ -0,0 +1,44 @@ +import { Flex } from "@chakra-ui/react"; + +import { useMobile } from "lib/app-provider"; +import { ExplorerLink } from "lib/components/ExplorerLink"; +import { TokenComposition, TokenImageRender } from "lib/components/token"; +import type { ProposalDeposit } from "lib/types"; + +interface DepositListProps { + proposalDeposits: ProposalDeposit[]; +} + +export const DepositList = ({ proposalDeposits }: DepositListProps) => { + const isMobile = useMobile(); + + return ( +
+ {proposalDeposits.map((deposit) => ( + + +
+ {deposit.amount.map((token) => ( + + + + + ))} +
+
+ ))} +
+ ); +}; diff --git a/src/lib/pages/proposal-details/components/ErrorFetchingProposalInfos.tsx b/src/lib/pages/proposal-details/components/ErrorFetchingProposalInfos.tsx new file mode 100644 index 000000000..4315b0fc5 --- /dev/null +++ b/src/lib/pages/proposal-details/components/ErrorFetchingProposalInfos.tsx @@ -0,0 +1,13 @@ +import { ErrorFetching } from "lib/components/state"; + +interface ErrorFetchingProposalInfosProps { + isParamsOnly?: boolean; +} + +export const ErrorFetchingProposalInfos = ({ + isParamsOnly = false, +}: ErrorFetchingProposalInfosProps) => ( + +); diff --git a/src/lib/pages/proposal-details/components/ProgressBadge.tsx b/src/lib/pages/proposal-details/components/ProgressBadge.tsx new file mode 100644 index 000000000..1c803ed4a --- /dev/null +++ b/src/lib/pages/proposal-details/components/ProgressBadge.tsx @@ -0,0 +1,56 @@ +import { Flex, Text, chakra } from "@chakra-ui/react"; + +import { CustomIcon } from "lib/components/icon"; + +import { ActiveDot } from "./ActiveDot"; + +const StyledCustomIcon = chakra(CustomIcon, { + baseStyle: { + boxSize: 3, + p: 0, + m: 1, + }, +}); + +export enum BadgeState { + ONGOING, + FAILED, + COMPLETE, + WAITING, +} + +export interface ProgressBadgeProps { + state: BadgeState; + text: string; +} + +const BadgeIcon = ({ state }: { state: BadgeState }) => { + switch (state) { + case BadgeState.ONGOING: + return ; + case BadgeState.FAILED: + return ; + case BadgeState.COMPLETE: + return ( + + ); + default: + return ; + } +}; + +export const ProgressBadge = ({ state, text }: ProgressBadgeProps) => ( + + + + {text} + + +); diff --git a/src/lib/pages/proposal-details/components/deposit-bar/DepositRatio.tsx b/src/lib/pages/proposal-details/components/deposit-bar/DepositRatio.tsx new file mode 100644 index 000000000..cec94bfd9 --- /dev/null +++ b/src/lib/pages/proposal-details/components/deposit-bar/DepositRatio.tsx @@ -0,0 +1,51 @@ +import { Flex, Text } from "@chakra-ui/react"; + +import { TokenImageRender } from "lib/components/token"; +import type { TokenWithValue } from "lib/types"; +import { + formatTokenWithValue, + formatUTokenWithPrecision, + getTokenLabel, +} from "lib/utils"; + +interface DepositRatioProps { + current: TokenWithValue; + min: TokenWithValue; + isCompact: boolean; +} + +export const DepositRatio = ({ + current, + min, + isCompact, +}: DepositRatioProps) => ( + + + + {formatUTokenWithPrecision( + current.amount, + current.precision ?? 0, + false, + isCompact ? 2 : undefined + )} + + + {" / "} + + {formatTokenWithValue(min, isCompact ? 2 : undefined)} + + {!isCompact && ( + + )} + +); diff --git a/src/lib/pages/proposal-details/components/deposit-bar/ProgressBar.tsx b/src/lib/pages/proposal-details/components/deposit-bar/ProgressBar.tsx new file mode 100644 index 000000000..9f514a272 --- /dev/null +++ b/src/lib/pages/proposal-details/components/deposit-bar/ProgressBar.tsx @@ -0,0 +1,47 @@ +import { Box, Flex, Text } from "@chakra-ui/react"; +import type Big from "big.js"; + +import { formatPrettyPercent } from "../../utils"; + +interface ProgressBarProps { + value: Big; + max: Big; + isCompact: boolean; +} + +export const ProgressBar = ({ value, max, isCompact }: ProgressBarProps) => { + const ratio = value.div(max).toNumber(); + const percent = formatPrettyPercent(ratio); + + return ( + + + + {!isCompact && ratio >= 0.5 && ( + + {percent} + + )} + + {!isCompact && ratio < 0.5 && ( + + {percent} + + )} + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/deposit-bar/index.tsx b/src/lib/pages/proposal-details/components/deposit-bar/index.tsx new file mode 100644 index 000000000..a42d44232 --- /dev/null +++ b/src/lib/pages/proposal-details/components/deposit-bar/index.tsx @@ -0,0 +1,44 @@ +import { Flex, Text } from "@chakra-ui/react"; + +import { mapDeposit } from "../../utils"; +import type { ProposalData, TokenWithValue } from "lib/types"; + +import { DepositRatio } from "./DepositRatio"; +import { ProgressBar } from "./ProgressBar"; + +interface DepositBarProps { + deposit: ProposalData["totalDeposit"]; + minDeposit: TokenWithValue[]; + isCompact: boolean; +} + +export const DepositBar = ({ + deposit, + minDeposit, + isCompact, +}: DepositBarProps) => { + const pairDeposit = mapDeposit(deposit, minDeposit); + return ( + + {pairDeposit.map(({ current, min }) => ( + + + {isCompact ? ( + + + Deposited + + + + ) : ( + + )} + + ))} + + ); +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/index.tsx index 372f60fe4..02e889f4e 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/index.tsx @@ -1,4 +1,4 @@ -import { Flex, Grid, GridItem, Heading } from "@chakra-ui/react"; +import { Flex, Grid, GridItem } from "@chakra-ui/react"; import type { ProposalData, @@ -7,6 +7,7 @@ import type { ProposalParams, } from "lib/types"; +import { ProposalPeriodOverview } from "./proposal-period-overview"; import { ProposalDescription } from "./ProposalDescription"; import { ProposalMessages } from "./ProposalMessages"; import { ProposalMetadata } from "./ProposalMetadata"; @@ -44,17 +45,12 @@ export const ProposalOverview = ({
- - Proposal Period - - - Proposal period content - +
); diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositPeriodOverview.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositPeriodOverview.tsx new file mode 100644 index 000000000..faaed29c5 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositPeriodOverview.tsx @@ -0,0 +1,85 @@ +import { Button, Flex, Text } from "@chakra-ui/react"; + +import type { ProposalOverviewProps } from ".."; +import { DepositBar } from "../../deposit-bar"; +import { DepositList } from "../../DepositList"; +import { ErrorFetchingProposalInfos } from "../../ErrorFetchingProposalInfos"; +import { useInternalNavigate } from "lib/app-provider"; +import { CustomIcon } from "lib/components/icon"; +import { Loading } from "lib/components/Loading"; +import { TabIndex, VoteTabIndex } from "lib/pages/proposal-details/type"; +import { extractParams } from "lib/pages/proposal-details/utils"; +import { ProposalStatus } from "lib/types"; +import { formatUTC } from "lib/utils"; + +const DepositPeriodOverviewBody = ({ + proposalData, + params, + isLoading, +}: Omit) => { + const navigate = useInternalNavigate(); + + if ( + proposalData.status !== ProposalStatus.DEPOSIT_FAILED && + proposalData.status !== ProposalStatus.DEPOSIT_PERIOD + ) + return ( + + The proposal passed the deposit period at{" "} + {proposalData.votingTime ? formatUTC(proposalData.votingTime) : "N/A"} + + ); + + if (isLoading) return ; + if (!params) return ; + + const { minDeposit } = extractParams(params, proposalData.isExpedited); + return ( + <> + + + {proposalData.proposalDeposits.length > 0 && ( + + )} + + ); +}; + +export const DepositPeriodOverview = ( + props: Omit +) => ( + + + +); diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx new file mode 100644 index 000000000..16094127f --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx @@ -0,0 +1,20 @@ +import { Heading } from "@chakra-ui/react"; + +import type { ProposalOverviewProps } from ".."; +import { ProposalStepper } from "../../proposal-stepper"; + +import { DepositPeriodOverview } from "./DepositPeriodOverview"; + +export const ProposalPeriodOverview = ({ + proposalData, + ...props +}: ProposalOverviewProps) => ( +
+ + Proposal Period + + + + +
+); diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx deleted file mode 100644 index dbb12e62d..000000000 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/ActiveDot.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { MotionBox } from "lib/components/MotionBox"; -import { ProposalStatus } from "lib/types"; - -interface ActiveDotProps { - status: ProposalStatus; -} - -export const ActiveDot = ({ status }: ActiveDotProps) => - status !== ProposalStatus.DEPOSIT_PERIOD && - status !== ProposalStatus.VOTING_PERIOD ? null : ( - - ); diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx index a9b8b71be..d5807c90d 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx @@ -3,9 +3,10 @@ import { SkeletonText, Text } from "@chakra-ui/react"; import big from "big.js"; import type { ProposalOverviewProps } from ".."; -import { ErrorFetching } from "lib/components/state"; +import { ErrorFetchingProposalInfos } from "../../ErrorFetchingProposalInfos"; import { extractParams, + formatPrettyPercent, mapDeposit, normalizeVotesInfo, } from "lib/pages/proposal-details/utils"; @@ -43,8 +44,7 @@ export const SummaryStatusBody = ({ }: ProposalOverviewProps) => { if (isLoading) return ; - if (!params || !votesInfo) - return ; + if (!params || !votesInfo) return ; const { minDeposit, quorum, threshold, vetoThreshold } = extractParams( params, @@ -95,7 +95,7 @@ export const SummaryStatusBody = ({ }} > “No with veto” vote surpassing{" "} - {Math.round(vetoThreshold * 10000) / 100}% + {formatPrettyPercent(vetoThreshold)} , the proposal will be regardless of other votes. @@ -157,7 +157,7 @@ export const SummaryStatusBody = ({ reached {" "} the voting quorum. But the voting period ended with “No with - veto” more than {Math.round(vetoThreshold * 10000) / 100}%, the + veto” more than {formatPrettyPercent(vetoThreshold)}, the proposal will be regardless of other votes. ); diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx index f695f5153..ceb5dfd83 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx @@ -2,9 +2,9 @@ import { Flex, Text } from "@chakra-ui/react"; import type { CSSProperties } from "react"; import type { ProposalOverviewProps } from ".."; +import { ActiveDot } from "../../ActiveDot"; import { ProposalStatus } from "lib/types"; -import { ActiveDot } from "./ActiveDot"; import { SummaryStatusBody } from "./SummaryStatusBody"; import { SummaryStatusChip } from "./SummaryStatusChip"; import { SummaryStatusTime } from "./SummaryStatusTime"; @@ -54,7 +54,7 @@ export const StatusSummary = ({ justify="space-between" > - + {isOngoing && } {isOngoing ? "Current" : "Final"} proposal result: diff --git a/src/lib/pages/proposal-details/components/proposal-stepper/StepIcon.tsx b/src/lib/pages/proposal-details/components/proposal-stepper/StepIcon.tsx new file mode 100644 index 000000000..b8a039be5 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-stepper/StepIcon.tsx @@ -0,0 +1,69 @@ +import { Flex, Text } from "@chakra-ui/react"; + +import { CustomIcon } from "lib/components/icon"; +import type { ProposalData } from "lib/types"; +import { ProposalStatus } from "lib/types"; + +import type { ProposalStepperProps } from "."; + +enum StepIconState { + ONGOING, + FAILED, + COMPLETE, +} + +const getStepIconState = (step: number, proposalData: ProposalData) => { + // Deposit Period + if (step === 1) { + if ( + proposalData.status === ProposalStatus.DEPOSIT_FAILED || + (proposalData.status === ProposalStatus.CANCELLED && + proposalData.votingEndTime === null) + ) + return StepIconState.FAILED; + + if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) + return StepIconState.ONGOING; + + return StepIconState.COMPLETE; + } + + // Voting Period + if ( + proposalData.status === ProposalStatus.DEPOSIT_PERIOD || + proposalData.status === ProposalStatus.DEPOSIT_FAILED || + proposalData.status === ProposalStatus.CANCELLED + ) + return StepIconState.FAILED; + + if (proposalData.status === ProposalStatus.VOTING_PERIOD) + return StepIconState.ONGOING; + + return StepIconState.COMPLETE; +}; + +export const StepIcon = ({ step, proposalData }: ProposalStepperProps) => { + const state = getStepIconState(step, proposalData); + const isFailed = state === StepIconState.FAILED; + return ( + + {state !== StepIconState.COMPLETE ? ( + + {step} + + ) : ( + + )} + + ); +}; diff --git a/src/lib/pages/proposal-details/components/proposal-stepper/index.tsx b/src/lib/pages/proposal-details/components/proposal-stepper/index.tsx new file mode 100644 index 000000000..1f3418654 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-stepper/index.tsx @@ -0,0 +1,35 @@ +import { Flex, Spacer, Text } from "@chakra-ui/react"; + +import { ProgressBadge } from "../ProgressBadge"; +import type { ProposalData } from "lib/types"; + +import { StepIcon } from "./StepIcon"; +import { getProgressBadgeProps, getStepperDescription } from "./utils"; + +export interface ProposalStepperProps { + step: number; + proposalData: ProposalData; + isOverview?: boolean; +} + +export const ProposalStepper = ({ + step, + proposalData, + isOverview = false, +}: ProposalStepperProps) => ( + + + + + {step === 1 ? "Deposit Period" : "Voting Period"} + + + + + {!isOverview && ( + + {getStepperDescription()} + + )} + +); diff --git a/src/lib/pages/proposal-details/components/proposal-stepper/utils.ts b/src/lib/pages/proposal-details/components/proposal-stepper/utils.ts new file mode 100644 index 000000000..3f0b9a91a --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-stepper/utils.ts @@ -0,0 +1,42 @@ +import { BadgeState, type ProgressBadgeProps } from "../ProgressBadge"; +import type { ProposalData } from "lib/types"; +import { ProposalStatus } from "lib/types"; + +export const getProgressBadgeProps = ( + step: number, + proposalData: ProposalData +): ProgressBadgeProps => { + // Deposit Period + if (step === 1) { + if (proposalData.status === ProposalStatus.DEPOSIT_FAILED) + return { state: BadgeState.FAILED, text: "Not enough deposit" }; + + if ( + proposalData.status === ProposalStatus.CANCELLED && + proposalData.votingEndTime === null + ) + return { state: BadgeState.FAILED, text: "Cancelled" }; + + if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) + return { state: BadgeState.ONGOING, text: "In Progress" }; + + return { state: BadgeState.COMPLETE, text: "Completed" }; + } + + // Voting Period + if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) + return { state: BadgeState.WAITING, text: "Waiting for deposit" }; + + if (proposalData.status === ProposalStatus.DEPOSIT_FAILED) + return { state: BadgeState.FAILED, text: "Not enough deposit" }; + + if (proposalData.status === ProposalStatus.CANCELLED) + return { state: BadgeState.FAILED, text: "Cancelled" }; + + if (proposalData.status === ProposalStatus.VOTING_PERIOD) + return { state: BadgeState.ONGOING, text: "In Progress" }; + + return { state: BadgeState.COMPLETE, text: "Vote Ended" }; +}; + +export const getStepperDescription = () => "Placeholder"; diff --git a/src/lib/pages/proposal-details/data.ts b/src/lib/pages/proposal-details/data.ts index 677b20c45..dede87c54 100644 --- a/src/lib/pages/proposal-details/data.ts +++ b/src/lib/pages/proposal-details/data.ts @@ -7,16 +7,18 @@ import { import type { Nullable, Option, ProposalData, ProposalParams } from "lib/types"; import { coinToTokenWithValue, compareTokenWithValues } from "lib/utils"; -export const useDerivedProposalParams = (): { +export const useDerivedProposalParams = ( + isMobile: boolean +): { data: Option; isLoading: boolean; } => { const { data, isLoading } = useProposalParams(); const { data: assetInfos, isLoading: isAssetInfosLoading } = useAssetInfos({ - withPrices: false, + withPrices: !isMobile, }); const { data: movePoolInfos, isLoading: isMovePoolInfosLoading } = - useMovePoolInfos({ withPrices: false }); + useMovePoolInfos({ withPrices: !isMobile }); if (isLoading || isAssetInfosLoading || isMovePoolInfosLoading || !data) return { diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index 1cc51338c..82414b2ec 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; import { useCallback, useEffect } from "react"; import { AmpEvent, track } from "lib/amplitude"; -import { useGovConfig, useInternalNavigate } from "lib/app-provider"; +import { useGovConfig, useInternalNavigate, useMobile } from "lib/app-provider"; import { CustomTab } from "lib/components/CustomTab"; import { Loading } from "lib/components/Loading"; import PageContainer from "lib/components/PageContainer"; @@ -22,12 +22,13 @@ const ProposalDetailsBody = ({ }: ProposalDetailsQueryParams) => { useGovConfig({ shouldRedirect: true }); + const isMobile = useMobile(); const navigate = useInternalNavigate(); const { data, isLoading } = useDerivedProposalData(id); const { data: votesInfo, isLoading: isVotesInfoLoading } = useProposalVotesInfo(id); const { data: params, isLoading: isParamsLoading } = - useDerivedProposalParams(); + useDerivedProposalParams(isMobile); const handleTabChange = useCallback( (nextTab: TabIndex) => () => { diff --git a/src/lib/pages/proposal-details/utils.ts b/src/lib/pages/proposal-details/utils.ts index 183d8a8f0..9239f5b8e 100644 --- a/src/lib/pages/proposal-details/utils.ts +++ b/src/lib/pages/proposal-details/utils.ts @@ -61,3 +61,6 @@ export const mapDeposit = ( min, }; }); + +export const formatPrettyPercent = (ratio: number) => + `${ratio < 0.01 ? "<0.01" : Math.round(ratio * 10000) / 100}%`; From d46e630fb35cf805b25eb17cd29a8143bab40255 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 9 Feb 2024 14:58:42 +0700 Subject: [PATCH 102/531] fix: changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a20422bbf..ee4b1483e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features -- [#775](https://github.com/alleslabs/celatone-frontend/pull/766) Proposal period overview deposit +- [#775](https://github.com/alleslabs/celatone-frontend/pull/775) Proposal period overview deposit - [#766](https://github.com/alleslabs/celatone-frontend/pull/766) Proposal status summary body - [#763](https://github.com/alleslabs/celatone-frontend/pull/763) Proposal status summary top - [#765](https://github.com/alleslabs/celatone-frontend/pull/765) Support Proposal Cancelled status From 3fb1af1498d290302066ba77ed4a59413279a07b Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 9 Feb 2024 15:02:59 +0700 Subject: [PATCH 103/531] fix: comment --- .../components/proposal-overview/status-summary/Countdown.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx index df50202f5..aa82c0748 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx @@ -33,7 +33,7 @@ export const Countdown = ({ endTime }: CountdownProps) => { const days = duration.days(); const timestamp = ( <> - {!!days && ( + {days > 0 && ( <> {days} {plur("day", days)} From aa2e7e569bdbb287071b91cd22e5d8d889e1b3a3 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Fri, 9 Feb 2024 15:34:33 +0700 Subject: [PATCH 104/531] fix(components): add n/a state for relevant contract --- .../pool-details/header/PoolInfo.tsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/lib/pages/pools/components/pool-details/header/PoolInfo.tsx b/src/lib/pages/pools/components/pool-details/header/PoolInfo.tsx index 5cce78660..f9b7a56ae 100644 --- a/src/lib/pages/pools/components/pool-details/header/PoolInfo.tsx +++ b/src/lib/pages/pools/components/pool-details/header/PoolInfo.tsx @@ -144,15 +144,21 @@ export const PoolInfo = ({ pool }: PoolInfoProps) => { /> )} - {pool.type === PoolType.COSMWASM && pool.contractAddress && ( + {pool.type === PoolType.COSMWASM && ( - - - + {pool.contractAddress ? ( + + + + ) : ( + + N/A + + )} )} From 7c8f04a9d8a1687c1b2e8d200ac65c1969c5a320 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 9 Feb 2024 16:29:21 +0700 Subject: [PATCH 105/531] fix: token list --- src/lib/components/token/TokenComposition.tsx | 27 +++++-------------- .../components/DepositList.tsx | 21 ++++++++++----- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/lib/components/token/TokenComposition.tsx b/src/lib/components/token/TokenComposition.tsx index 5fd7f98d2..e59b91934 100644 --- a/src/lib/components/token/TokenComposition.tsx +++ b/src/lib/components/token/TokenComposition.tsx @@ -9,14 +9,10 @@ import { interface TokenCompositionProps extends FlexProps { token: TokenWithValue; - decimal?: number; - displayValue?: boolean; } export const TokenComposition = ({ token, - decimal, - displayValue = true, ...flexProps }: TokenCompositionProps) => ( @@ -26,9 +22,7 @@ export const TokenComposition = ({ {formatUTokenWithPrecision( token.poolInfo.coinA.amount, - token.poolInfo.coinA.precision ?? 0, - true, - decimal + token.poolInfo.coinA.precision ?? 0 )} {getTokenLabel( @@ -43,9 +37,7 @@ export const TokenComposition = ({ {formatUTokenWithPrecision( token.poolInfo.coinB.amount, - token.poolInfo.coinB.precision ?? 0, - true, - decimal + token.poolInfo.coinB.precision ?? 0 )} {getTokenLabel( @@ -57,20 +49,13 @@ export const TokenComposition = ({ ) : ( - {formatUTokenWithPrecision( - token.amount, - token.precision ?? 0, - true, - decimal - )} + {formatUTokenWithPrecision(token.amount, token.precision ?? 0)} {getTokenLabel(token.denom, token.symbol)} )} - {displayValue && ( - - {token.value ? `(≈ ${formatPrice(token.value)})` : "-"} - - )} + + {token.value ? `(≈ ${formatPrice(token.value)})` : "-"} + ); diff --git a/src/lib/pages/proposal-details/components/DepositList.tsx b/src/lib/pages/proposal-details/components/DepositList.tsx index c9a353c91..8cd6c99b9 100644 --- a/src/lib/pages/proposal-details/components/DepositList.tsx +++ b/src/lib/pages/proposal-details/components/DepositList.tsx @@ -1,9 +1,10 @@ -import { Flex } from "@chakra-ui/react"; +import { Flex, Text } from "@chakra-ui/react"; import { useMobile } from "lib/app-provider"; import { ExplorerLink } from "lib/components/ExplorerLink"; -import { TokenComposition, TokenImageRender } from "lib/components/token"; +import { TokenImageRender } from "lib/components/token"; import type { ProposalDeposit } from "lib/types"; +import { formatUTokenWithPrecision, getTokenLabel } from "lib/utils"; interface DepositListProps { proposalDeposits: ProposalDeposit[]; @@ -28,11 +29,17 @@ export const DepositList = ({ proposalDeposits }: DepositListProps) => {
{deposit.amount.map((token) => ( - + + + {formatUTokenWithPrecision( + token.amount, + token.precision ?? 0, + true, + 2 + )} + + {getTokenLabel(token.denom, token.symbol)} + ))} From 28db3caa769699219e92f5ab3e9619edfeb36b2b Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 9 Feb 2024 16:34:10 +0700 Subject: [PATCH 106/531] fix: renaming --- .../{DepositPeriodOverview.tsx => DepositOverview.tsx} | 6 +++--- .../proposal-overview/proposal-period-overview/index.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/{DepositPeriodOverview.tsx => DepositOverview.tsx} (95%) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositPeriodOverview.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx similarity index 95% rename from src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositPeriodOverview.tsx rename to src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx index faaed29c5..1d49b8be3 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositPeriodOverview.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx @@ -12,7 +12,7 @@ import { extractParams } from "lib/pages/proposal-details/utils"; import { ProposalStatus } from "lib/types"; import { formatUTC } from "lib/utils"; -const DepositPeriodOverviewBody = ({ +const DepositOverviewBody = ({ proposalData, params, isLoading, @@ -69,7 +69,7 @@ const DepositPeriodOverviewBody = ({ ); }; -export const DepositPeriodOverview = ( +export const DepositOverview = ( props: Omit ) => ( - + ); diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx index 16094127f..8587974de 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx @@ -3,7 +3,7 @@ import { Heading } from "@chakra-ui/react"; import type { ProposalOverviewProps } from ".."; import { ProposalStepper } from "../../proposal-stepper"; -import { DepositPeriodOverview } from "./DepositPeriodOverview"; +import { DepositOverview } from "./DepositOverview"; export const ProposalPeriodOverview = ({ proposalData, @@ -14,7 +14,7 @@ export const ProposalPeriodOverview = ({ Proposal Period - +
); From ff4b11d7d34c7d79dade18272162d4a487aca401 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Fri, 9 Feb 2024 16:34:25 +0700 Subject: [PATCH 107/531] fix(components): add expand collapse all to proposal message accordion --- CHANGELOG.md | 2 + .../amplitude/track-event/trackInteraction.ts | 1 + .../resources/ResourceSectionBody.tsx | 1 + .../proposal-overview/ProposalMessageCard.tsx | 70 +++++++++++++++ .../proposal-overview/ProposalMessages.tsx | 88 +++++++++++++------ src/lib/styles/theme/components/accordion.ts | 1 + 6 files changed, 136 insertions(+), 27 deletions(-) create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/ProposalMessageCard.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 0196ba93c..05c2f15bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#776](https://github.com/alleslabs/celatone-frontend/pull/776) Add expand/collapse all to proposal messages in detail page +- [#771](https://github.com/alleslabs/celatone-frontend/pull/771) Adjust proposal detail - [#772](https://github.com/alleslabs/celatone-frontend/pull/772) Add zod validator to code details page code id params - [#770](https://github.com/alleslabs/celatone-frontend/pull/770) Add unit test for account store (mobx) - [#769](https://github.com/alleslabs/celatone-frontend/pull/769) Add unit test for format.test.ts on shortenName function diff --git a/src/lib/amplitude/track-event/trackInteraction.ts b/src/lib/amplitude/track-event/trackInteraction.ts index 8c60a76a3..edf65d57c 100644 --- a/src/lib/amplitude/track-event/trackInteraction.ts +++ b/src/lib/amplitude/track-event/trackInteraction.ts @@ -77,6 +77,7 @@ export const trackUseExpand = ({ | "module_interaction_function_accordion" | "module_interaction_selected_function_card" | "pool_tx_msg" + | "proposal_message_card" | "resources_detail_card" | "resources_by_account_card"; info?: object; diff --git a/src/lib/pages/account-details/components/resources/ResourceSectionBody.tsx b/src/lib/pages/account-details/components/resources/ResourceSectionBody.tsx index 90ce599c6..324e0cc87 100644 --- a/src/lib/pages/account-details/components/resources/ResourceSectionBody.tsx +++ b/src/lib/pages/account-details/components/resources/ResourceSectionBody.tsx @@ -50,6 +50,7 @@ export const ResourceSectionBody = ({ const selectedResource = resourcesByOwner ?.find((resource) => resource.owner === selectedAccountParam) ?.resources?.find((resource) => resource.group === selectedNameParam); + useEffect(() => { setExpandedIndexes(selectedResource?.items.length === 1 ? [0] : []); }, [resourcesByOwner, selectedResource]); diff --git a/src/lib/pages/proposal-details/components/proposal-overview/ProposalMessageCard.tsx b/src/lib/pages/proposal-details/components/proposal-overview/ProposalMessageCard.tsx new file mode 100644 index 000000000..e728b2624 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/ProposalMessageCard.tsx @@ -0,0 +1,70 @@ +import { + AccordionButton, + AccordionIcon, + AccordionItem, + AccordionPanel, + Flex, + Text, +} from "@chakra-ui/react"; + +import { trackUseExpand } from "lib/amplitude"; +import JsonReadOnly from "lib/components/json/JsonReadOnly"; + +interface ProposalMessageCardProps { + header: string; + jsonString: string; +} + +export const ProposalMessageCard = ({ + header, + jsonString, +}: ProposalMessageCardProps) => { + return ( + + {({ isExpanded }) => ( + <> + + trackUseExpand({ + action: !isExpanded ? "expand" : "collapse", + component: "proposal_message_card", + section: "proposal message", + }) + } + > + + + + {header} + + + + + + + + +
+ +
+
+ + )} +
+ ); +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/ProposalMessages.tsx b/src/lib/pages/proposal-details/components/proposal-overview/ProposalMessages.tsx index c4dd3e490..06a78fe2a 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/ProposalMessages.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/ProposalMessages.tsx @@ -1,39 +1,73 @@ -import { Flex, Heading, Text } from "@chakra-ui/react"; +import { Accordion, Button, Flex, Heading } from "@chakra-ui/react"; +import { useEffect, useState } from "react"; -import { JsonInfo } from "lib/components/json/JsonInfo"; +import { trackUseExpandAll } from "lib/amplitude"; +import { CustomIcon } from "lib/components/icon"; import type { ProposalData } from "lib/types"; import { jsonPrettify } from "lib/utils"; +import { ProposalMessageCard } from "./ProposalMessageCard"; + interface ProposalMessagesProps { messages: ProposalData["messages"]; } +export const ProposalMessages = ({ messages }: ProposalMessagesProps) => { + const [expandedIndexes, setExpandedIndexes] = useState([]); + + useEffect(() => { + setExpandedIndexes(messages?.length === 1 ? [0] : []); + }, [messages]); -export const ProposalMessages = ({ messages }: ProposalMessagesProps) => ( - - - Proposal Messages - - {messages?.length ? ( - <> - {messages.map((item, i) => ( - + + + Proposal Messages + + + + setExpandedIndexes(indexes)} + > + {messages?.map((item, i) => ( + ))} - - ) : ( - - No Messages - - )} - -); + +
+ ); +}; diff --git a/src/lib/styles/theme/components/accordion.ts b/src/lib/styles/theme/components/accordion.ts index 7076deb97..58637a6b0 100644 --- a/src/lib/styles/theme/components/accordion.ts +++ b/src/lib/styles/theme/components/accordion.ts @@ -16,6 +16,7 @@ const gray900 = definePartsStyle({ borderRadius: "0px 8px 8px 0px", }, }); + const transparent = definePartsStyle({ container: { bg: "transparent", From 16f1d17c9f8f1d615ed5dc89cda0856a33a66938 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 9 Feb 2024 16:43:49 +0700 Subject: [PATCH 108/531] fix: cancelled state --- .../proposal-period-overview/DepositOverview.tsx | 6 +++++- .../components/proposal-stepper/StepIcon.tsx | 2 +- .../proposal-details/components/proposal-stepper/utils.ts | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx index 1d49b8be3..57d230a50 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx @@ -21,7 +21,11 @@ const DepositOverviewBody = ({ if ( proposalData.status !== ProposalStatus.DEPOSIT_FAILED && - proposalData.status !== ProposalStatus.DEPOSIT_PERIOD + proposalData.status !== ProposalStatus.DEPOSIT_PERIOD && + !( + proposalData.status === ProposalStatus.CANCELLED && + proposalData.votingTime === null + ) ) return ( diff --git a/src/lib/pages/proposal-details/components/proposal-stepper/StepIcon.tsx b/src/lib/pages/proposal-details/components/proposal-stepper/StepIcon.tsx index b8a039be5..a95264a7d 100644 --- a/src/lib/pages/proposal-details/components/proposal-stepper/StepIcon.tsx +++ b/src/lib/pages/proposal-details/components/proposal-stepper/StepIcon.tsx @@ -18,7 +18,7 @@ const getStepIconState = (step: number, proposalData: ProposalData) => { if ( proposalData.status === ProposalStatus.DEPOSIT_FAILED || (proposalData.status === ProposalStatus.CANCELLED && - proposalData.votingEndTime === null) + proposalData.votingTime === null) ) return StepIconState.FAILED; diff --git a/src/lib/pages/proposal-details/components/proposal-stepper/utils.ts b/src/lib/pages/proposal-details/components/proposal-stepper/utils.ts index 3f0b9a91a..053f8cc71 100644 --- a/src/lib/pages/proposal-details/components/proposal-stepper/utils.ts +++ b/src/lib/pages/proposal-details/components/proposal-stepper/utils.ts @@ -13,7 +13,7 @@ export const getProgressBadgeProps = ( if ( proposalData.status === ProposalStatus.CANCELLED && - proposalData.votingEndTime === null + proposalData.votingTime === null ) return { state: BadgeState.FAILED, text: "Cancelled" }; From c4cfe0114da8912575b74e15c4444e5ff892902d Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 9 Feb 2024 17:06:45 +0700 Subject: [PATCH 109/531] fix: status chip loading --- .../proposal-overview/status-summary/SummaryStatusChip.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx index d2003fd69..683de31bd 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx @@ -14,12 +14,11 @@ export const SummaryStatusChip = ({ votesInfo, isLoading, }: ProposalOverviewProps) => { - if (isLoading) return ; - if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) return ; if (proposalData.status === ProposalStatus.VOTING_PERIOD) { + if (isLoading) return ; if (!params || !votesInfo) return ( From 12144ac475d0c2f9c332ecded5424f0b9d0979c3 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 9 Feb 2024 17:19:41 +0700 Subject: [PATCH 110/531] fix: error text condition --- .../proposal-details/components/ErrorFetchingProposalInfos.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/pages/proposal-details/components/ErrorFetchingProposalInfos.tsx b/src/lib/pages/proposal-details/components/ErrorFetchingProposalInfos.tsx index 4315b0fc5..5cbe9531b 100644 --- a/src/lib/pages/proposal-details/components/ErrorFetchingProposalInfos.tsx +++ b/src/lib/pages/proposal-details/components/ErrorFetchingProposalInfos.tsx @@ -8,6 +8,6 @@ export const ErrorFetchingProposalInfos = ({ isParamsOnly = false, }: ErrorFetchingProposalInfosProps) => ( ); From ef48dad525757aae92f0c8fa0eb5ecd2717398f6 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 9 Feb 2024 17:37:45 +0700 Subject: [PATCH 111/531] fix: summary text and loading --- .../status-summary/SummaryStatusBody.tsx | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx index a9b8b71be..a2046fd79 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx @@ -41,6 +41,22 @@ export const SummaryStatusBody = ({ votesInfo, isLoading, }: ProposalOverviewProps) => { + if (proposalData.status === ProposalStatus.DEPOSIT_FAILED) + return ( + + The proposal has not received the necessary deposits to advance to the + voting period. + + ); + + if (proposalData.status === ProposalStatus.CANCELLED) + return ( + + The proposal was cancelled by the proposer before the governance process + is complete. + + ); + if (isLoading) return ; if (!params || !votesInfo) @@ -170,35 +186,19 @@ export const SummaryStatusBody = ({ ); } - if (proposalData.status === ProposalStatus.PASSED) - return ( - - The proposal has successfully met the voting quorum with a{" "} - - {yes.mul(100).round(2, big.roundHalfUp).toNumber()}% of - “Yes” - {" "} - rate. As a result, the proposal has been passed, and its content will - now be implemented. - - ); - - if (proposalData.status === ProposalStatus.CANCELLED) - return ( - - The proposal was cancelled by the proposer before the governance process - is complete. - - ); - return ( - The voting for this proposal did not reach the required quorum. As a - result, the proposal is not considered valid and rejected. + The proposal has successfully met the voting quorum with a{" "} + + {yes.mul(100).round(2, big.roundHalfUp).toNumber()}% of + “Yes” + {" "} + rate. As a result, the proposal has been passed, and its content will now + be implemented. ); }; From a09b284b5a61d30191d49dc771139841cadff7ca Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 9 Feb 2024 17:45:35 +0700 Subject: [PATCH 112/531] fix: loading my --- .../proposal-period-overview/DepositOverview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx index 57d230a50..8cfea919e 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/DepositOverview.tsx @@ -34,7 +34,7 @@ const DepositOverviewBody = ({ ); - if (isLoading) return ; + if (isLoading) return ; if (!params) return ; const { minDeposit } = extractParams(params, proposalData.isExpedited); From f5d6df83731a2e7ac594dffc3d8695619f5dc6b9 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Sat, 10 Feb 2024 17:13:11 +0700 Subject: [PATCH 113/531] fix: yes threshold condition --- .../status-summary/SummaryStatusBody.tsx | 14 +++++++------- .../status-summary/SummaryStatusChip.tsx | 8 +++----- src/lib/pages/proposal-details/utils.ts | 10 ++++++++-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx index d5807c90d..02d64e8d6 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx @@ -50,7 +50,7 @@ export const SummaryStatusBody = ({ params, proposalData.isExpedited ); - const { yes, noWithVeto, currentTotalVotes } = normalizeVotesInfo(votesInfo); + const { noWithVeto, yesRatio, totalVotes } = normalizeVotesInfo(votesInfo); if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) { const required = mapDeposit(proposalData.totalDeposit, minDeposit).reduce< @@ -75,7 +75,7 @@ export const SummaryStatusBody = ({ } if (proposalData.status === ProposalStatus.VOTING_PERIOD) { - if (currentTotalVotes.lt(quorum)) + if (totalVotes.lt(quorum)) return ( As of now, the proposal has not yet reached the required quorum. If @@ -101,7 +101,7 @@ export const SummaryStatusBody = ({ ); - if (currentTotalVotes.eq(0) || yes.div(currentTotalVotes).lt(threshold)) + if (yesRatio.lt(threshold)) return ( The proposal has{" "} @@ -131,13 +131,13 @@ export const SummaryStatusBody = ({ return ( Although the proposal successfully reached the voting quorum with a{" "} - {yes.mul(100).round(2, big.roundHalfUp).toNumber()}% “Yes” - rate, it was not implemented due to technical reasons. + {yesRatio.mul(100).round(2, big.roundHalfUp).toNumber()}%{" "} + “Yes” rate, it was not implemented due to technical reasons. ); if (proposalData.status === ProposalStatus.REJECTED) { - if (currentTotalVotes.lt(quorum)) + if (totalVotes.lt(quorum)) return ( This proposal did not meet the required quorum, resulting in its @@ -179,7 +179,7 @@ export const SummaryStatusBody = ({ fontWeight: 700, }} > - {yes.mul(100).round(2, big.roundHalfUp).toNumber()}% of + {yesRatio.mul(100).round(2, big.roundHalfUp).toNumber()}% of “Yes” {" "} rate. As a result, the proposal has been passed, and its content will diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx index 683de31bd..f888a00d9 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx @@ -26,8 +26,7 @@ export const SummaryStatusChip = ({ ); - const { yes, noWithVeto, currentTotalVotes } = - normalizeVotesInfo(votesInfo); + const { noWithVeto, yesRatio, totalVotes } = normalizeVotesInfo(votesInfo); const { quorum, threshold, vetoThreshold } = extractParams( params, proposalData.isExpedited @@ -35,10 +34,9 @@ export const SummaryStatusChip = ({ return ( { if (votesInfo.totalVotingPower.eq(0)) @@ -17,7 +18,8 @@ export const normalizeVotesInfo = (votesInfo: ProposalVotesInfo) => { abstain: big(0), no: big(0), noWithVeto: big(0), - currentTotalVotes: big(0), + yesRatio: big(0), + totalVotes: big(0), }; const yes = votesInfo.yes.div(votesInfo.totalVotingPower); @@ -25,12 +27,16 @@ export const normalizeVotesInfo = (votesInfo: ProposalVotesInfo) => { const no = votesInfo.no.div(votesInfo.totalVotingPower); const noWithVeto = votesInfo.noWithVeto.div(votesInfo.totalVotingPower); + const nonAbstainVotes = yes.add(no).add(noWithVeto); + const yesRatio = divWithDefault(yes, nonAbstainVotes, 0); + return { yes, abstain, no, noWithVeto, - currentTotalVotes: yes.add(abstain).add(no).add(noWithVeto), + yesRatio, + totalVotes: nonAbstainVotes.add(abstain), }; }; From 8530e844958d8cba97711bb5deed5412e4aa8b83 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Sat, 10 Feb 2024 17:21:13 +0700 Subject: [PATCH 114/531] fix: change normalized variable --- .../proposal-overview/status-summary/SummaryStatusBody.tsx | 6 ++++-- .../proposal-overview/status-summary/SummaryStatusChip.tsx | 6 +++++- src/lib/pages/proposal-details/utils.ts | 7 ++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx index 02d64e8d6..2b5b8c9c7 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx @@ -12,7 +12,7 @@ import { } from "lib/pages/proposal-details/utils"; import type { Token, TokenWithValue, U } from "lib/types"; import { ProposalStatus } from "lib/types"; -import { formatTokenWithValueList } from "lib/utils"; +import { divWithDefault, formatTokenWithValueList } from "lib/utils"; const Passed = () => ( ); - const { noWithVeto, yesRatio, totalVotes } = normalizeVotesInfo(votesInfo); const { quorum, threshold, vetoThreshold } = extractParams( params, proposalData.isExpedited ); + const { yes, noWithVeto, nonAbstainVotes, totalVotes } = + normalizeVotesInfo(votesInfo); + const yesRatio = divWithDefault(yes, nonAbstainVotes, 0); + return ( { if (votesInfo.totalVotingPower.eq(0)) @@ -18,7 +17,7 @@ export const normalizeVotesInfo = (votesInfo: ProposalVotesInfo) => { abstain: big(0), no: big(0), noWithVeto: big(0), - yesRatio: big(0), + nonAbstainVotes: big(0), totalVotes: big(0), }; @@ -26,16 +25,14 @@ export const normalizeVotesInfo = (votesInfo: ProposalVotesInfo) => { const abstain = votesInfo.abstain.div(votesInfo.totalVotingPower); const no = votesInfo.no.div(votesInfo.totalVotingPower); const noWithVeto = votesInfo.noWithVeto.div(votesInfo.totalVotingPower); - const nonAbstainVotes = yes.add(no).add(noWithVeto); - const yesRatio = divWithDefault(yes, nonAbstainVotes, 0); return { yes, abstain, no, noWithVeto, - yesRatio, + nonAbstainVotes, totalVotes: nonAbstainVotes.add(abstain), }; }; From 6c1935549d8c508dadb350185e6b02d33ab12883 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Sat, 10 Feb 2024 17:33:53 +0700 Subject: [PATCH 115/531] fix: text align --- .../status-summary/SummaryStatusTime.tsx | 10 +++++++--- .../proposal-overview/status-summary/index.tsx | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx index e4dcd835f..0a1149772 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusTime.tsx @@ -1,5 +1,6 @@ import { Text } from "@chakra-ui/react"; +import { useMobile } from "lib/app-provider"; import type { ProposalData } from "lib/types"; import { ProposalStatus } from "lib/types"; import { formatUTC } from "lib/utils"; @@ -22,16 +23,19 @@ const getResolvedPrefix = (status: ProposalStatus) => { }; export const SummaryStatusTime = ({ proposalData }: StatusTimeProps) => { + const isMobile = useMobile(); + const textAlign = isMobile ? "start" : "end"; + if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) return ( - + Deposit ends in ); if (proposalData.status === ProposalStatus.VOTING_PERIOD) return ( - + Voting ends in{" "} {proposalData.votingEndTime ? ( @@ -42,7 +46,7 @@ export const SummaryStatusTime = ({ proposalData }: StatusTimeProps) => { ); return ( - + {getResolvedPrefix(proposalData.status)} {" at "} {proposalData.resolvedTimestamp diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx index ceb5dfd83..c5404ebc9 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/index.tsx @@ -53,7 +53,7 @@ export const StatusSummary = ({ w="full" justify="space-between" > - + {isOngoing && } {isOngoing ? "Current" : "Final"} proposal result: From 469a3fe8c393f8a63d1f6a35a0c7c7c218dc5b27 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Sat, 10 Feb 2024 17:47:22 +0700 Subject: [PATCH 116/531] fix: nowithveto condition --- .../proposal-overview/status-summary/SummaryStatusBody.tsx | 5 +++-- .../proposal-overview/status-summary/SummaryStatusChip.tsx | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx index 2b5b8c9c7..cf2c605d6 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx @@ -53,6 +53,7 @@ export const SummaryStatusBody = ({ const { yes, noWithVeto, nonAbstainVotes, totalVotes } = normalizeVotesInfo(votesInfo); const yesRatio = divWithDefault(yes, nonAbstainVotes, 0); + const noWithVetoRatio = divWithDefault(noWithVeto, totalVotes, 0); if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) { const required = mapDeposit(proposalData.totalDeposit, minDeposit).reduce< @@ -86,7 +87,7 @@ export const SummaryStatusBody = ({ ); - if (noWithVeto.gte(vetoThreshold)) + if (noWithVetoRatio.gte(vetoThreshold)) return ( The proposal has successfully met the voting quorum. However, if the @@ -147,7 +148,7 @@ export const SummaryStatusBody = ({ ); - if (noWithVeto.gte(vetoThreshold)) + if (noWithVetoRatio.gte(vetoThreshold)) return ( This proposal has{" "} diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx index 2af698870..7a2c2430e 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusChip.tsx @@ -34,12 +34,13 @@ export const SummaryStatusChip = ({ const { yes, noWithVeto, nonAbstainVotes, totalVotes } = normalizeVotesInfo(votesInfo); const yesRatio = divWithDefault(yes, nonAbstainVotes, 0); + const noWithVetoRatio = divWithDefault(noWithVeto, totalVotes, 0); return ( Date: Mon, 12 Feb 2024 02:25:00 +0700 Subject: [PATCH 117/531] feat: proposal overview voting --- CHANGELOG.md | 1 + package.json | 2 +- pnpm-lock.yaml | 135 ++++++------------ .../proposal-details/components/ActiveDot.tsx | 44 +++--- .../components/ProgressBadge.tsx | 9 +- .../components/VoteQuorumBadge.tsx | 55 +++++++ .../components/VoteQuorumCircle.tsx | 73 ++++++++++ .../components/VoteThresholdBadge.tsx | 36 +++++ .../components/VoteThresholdBar.tsx | 130 +++++++++++++++++ .../components/VpPercentCard.tsx | 0 .../components/VpPercentThreshold.tsx | 86 +++++++++++ .../components/proposal-overview/index.tsx | 2 +- .../VotingOverview.tsx | 89 ++++++++++++ .../VotingOverviewQuorum.tsx | 72 ++++++++++ .../VotingOverviewQuorumText.tsx | 66 +++++++++ .../VotingOverviewThreshold.tsx | 87 +++++++++++ .../proposal-period-overview/index.tsx | 2 + src/lib/pages/proposal-details/utils.ts | 32 ++++- src/lib/styles/theme/components/heading.ts | 6 + src/lib/utils/formatter/token.test.ts | 13 ++ src/lib/utils/formatter/token.ts | 1 + 21 files changed, 830 insertions(+), 111 deletions(-) create mode 100644 src/lib/pages/proposal-details/components/VoteQuorumBadge.tsx create mode 100644 src/lib/pages/proposal-details/components/VoteQuorumCircle.tsx create mode 100644 src/lib/pages/proposal-details/components/VoteThresholdBadge.tsx create mode 100644 src/lib/pages/proposal-details/components/VoteThresholdBar.tsx create mode 100644 src/lib/pages/proposal-details/components/VpPercentCard.tsx create mode 100644 src/lib/pages/proposal-details/components/VpPercentThreshold.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverview.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorumText.tsx create mode 100644 src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index ee4b1483e..3fe39ea32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#778](https://github.com/alleslabs/celatone-frontend/pull/778) Proposal period overview voting - [#775](https://github.com/alleslabs/celatone-frontend/pull/775) Proposal period overview deposit - [#766](https://github.com/alleslabs/celatone-frontend/pull/766) Proposal status summary body - [#763](https://github.com/alleslabs/celatone-frontend/pull/763) Proposal status summary top diff --git a/package.json b/package.json index 4607cc5eb..29257e5cc 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "cosmjs-types": "^0.9.0", "dayjs": "^1.11.6", "file-saver": "^2.0.5", - "framer-motion": "^7.6.12", + "framer-motion": "^11.0.3", "graphql": "^16.6.0", "graphql-request": "^5.0.0", "js-base64": "^3.7.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39ba30a15..b15ce61bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,7 +31,7 @@ dependencies: version: 2.1.1(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/react': specifier: 2.8.2 - version: 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0) + version: 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0) '@chakra-ui/styled-system': specifier: ^2.9.2 version: 2.9.2 @@ -103,7 +103,7 @@ dependencies: version: 4.6.0(monaco-editor@0.44.0)(react-dom@18.2.0)(react@18.2.0) '@rjsf/chakra-ui': specifier: v5.0.0-beta.10 - version: 5.0.0-beta.10(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/react@2.8.2)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@emotion/react@11.11.3)(@rjsf/core@5.0.0-beta.10)(@rjsf/utils@5.0.0-beta.10)(@types/react@18.2.48)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0) + version: 5.0.0-beta.10(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/react@2.8.2)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@emotion/react@11.11.3)(@rjsf/core@5.0.0-beta.10)(@rjsf/utils@5.0.0-beta.10)(@types/react@18.2.48)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0) '@rjsf/core': specifier: v5.0.0-beta.10 version: 5.0.0-beta.10(@rjsf/utils@5.0.0-beta.10)(react@18.2.0) @@ -177,8 +177,8 @@ dependencies: specifier: ^2.0.5 version: 2.0.5 framer-motion: - specifier: ^7.6.12 - version: 7.10.3(react-dom@18.2.0)(react@18.2.0) + specifier: ^11.0.3 + version: 11.0.3(react-dom@18.2.0)(react@18.2.0) graphql: specifier: ^16.6.0 version: 16.8.1 @@ -1815,7 +1815,7 @@ packages: '@babel/runtime': 7.23.8 dev: false - /@chakra-ui/accordion@2.3.1(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react@18.2.0): + /@chakra-ui/accordion@2.3.1(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react@18.2.0): resolution: {integrity: sha512-FSXRm8iClFyU+gVaXisOSEw0/4Q+qZbFRiuhIAkVU6Boj0FxAMrlo9a8AV5TuF77rgaHytCdHk0Ng+cyUijrag==} peerDependencies: '@chakra-ui/system': '>=2.0.0' @@ -1829,8 +1829,8 @@ packages: '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) '@chakra-ui/shared-utils': 2.0.5 '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) - '@chakra-ui/transition': 2.1.0(framer-motion@7.10.3)(react@18.2.0) - framer-motion: 7.10.3(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/transition': 2.1.0(framer-motion@11.0.3)(react@18.2.0) + framer-motion: 11.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 /@chakra-ui/alert@2.2.2(@chakra-ui/system@2.6.2)(react@18.2.0): @@ -2129,7 +2129,7 @@ packages: '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 - /@chakra-ui/menu@2.2.1(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react@18.2.0): + /@chakra-ui/menu@2.2.1(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react@18.2.0): resolution: {integrity: sha512-lJS7XEObzJxsOwWQh7yfG4H8FzFPRP5hVPN/CL+JzytEINCSBvsCDHrYPQGp7jzpCi8vnTqQQGQe0f8dwnXd2g==} peerDependencies: '@chakra-ui/system': '>=2.0.0' @@ -2151,11 +2151,11 @@ packages: '@chakra-ui/react-use-update-effect': 2.1.0(react@18.2.0) '@chakra-ui/shared-utils': 2.0.5 '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) - '@chakra-ui/transition': 2.1.0(framer-motion@7.10.3)(react@18.2.0) - framer-motion: 7.10.3(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/transition': 2.1.0(framer-motion@11.0.3)(react@18.2.0) + framer-motion: 11.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 - /@chakra-ui/modal@2.3.1(@chakra-ui/system@2.6.2)(@types/react@18.2.48)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0): + /@chakra-ui/modal@2.3.1(@chakra-ui/system@2.6.2)(@types/react@18.2.48)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-TQv1ZaiJMZN+rR9DK0snx/OPwmtaGH1HbZtlYt4W4s6CzyK541fxLRTjIXfEzIGpvNW+b6VFuFjbcR78p4DEoQ==} peerDependencies: '@chakra-ui/system': '>=2.0.0' @@ -2171,9 +2171,9 @@ packages: '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) '@chakra-ui/shared-utils': 2.0.5 '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) - '@chakra-ui/transition': 2.1.0(framer-motion@7.10.3)(react@18.2.0) + '@chakra-ui/transition': 2.1.0(framer-motion@11.0.3)(react@18.2.0) aria-hidden: 1.2.3 - framer-motion: 7.10.3(react-dom@18.2.0)(react@18.2.0) + framer-motion: 11.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-remove-scroll: 2.5.7(@types/react@18.2.48)(react@18.2.0) @@ -2222,7 +2222,7 @@ packages: '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 - /@chakra-ui/popover@2.2.1(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react@18.2.0): + /@chakra-ui/popover@2.2.1(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react@18.2.0): resolution: {integrity: sha512-K+2ai2dD0ljvJnlrzesCDT9mNzLifE3noGKZ3QwLqd/K34Ym1W/0aL1ERSynrcG78NKoXS54SdEzkhCZ4Gn/Zg==} peerDependencies: '@chakra-ui/system': '>=2.0.0' @@ -2241,7 +2241,7 @@ packages: '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) '@chakra-ui/shared-utils': 2.0.5 '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) - framer-motion: 7.10.3(react-dom@18.2.0)(react@18.2.0) + framer-motion: 11.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 /@chakra-ui/popper@3.1.0(react@18.2.0): @@ -2481,7 +2481,7 @@ packages: '@chakra-ui/utils': 2.0.15 react: 18.2.0 - /@chakra-ui/react@2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0): + /@chakra-ui/react@2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Hn0moyxxyCDKuR9ywYpqgX8dvjqwu9ArwpIb9wHNYjnODETjLwazgNIliCVBRcJvysGRiV51U2/JtJVrpeCjUQ==} peerDependencies: '@emotion/react': ^11.0.0 @@ -2490,7 +2490,7 @@ packages: react: '>=18' react-dom: '>=18' dependencies: - '@chakra-ui/accordion': 2.3.1(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react@18.2.0) + '@chakra-ui/accordion': 2.3.1(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react@18.2.0) '@chakra-ui/alert': 2.2.2(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/avatar': 2.3.0(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/breadcrumb': 2.2.0(@chakra-ui/system@2.6.2)(react@18.2.0) @@ -2511,11 +2511,11 @@ packages: '@chakra-ui/layout': 2.3.1(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/live-region': 2.1.0(react@18.2.0) '@chakra-ui/media-query': 3.3.0(@chakra-ui/system@2.6.2)(react@18.2.0) - '@chakra-ui/menu': 2.2.1(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react@18.2.0) - '@chakra-ui/modal': 2.3.1(@chakra-ui/system@2.6.2)(@types/react@18.2.48)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/menu': 2.2.1(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react@18.2.0) + '@chakra-ui/modal': 2.3.1(@chakra-ui/system@2.6.2)(@types/react@18.2.48)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0) '@chakra-ui/number-input': 2.1.2(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/pin-input': 2.1.0(@chakra-ui/system@2.6.2)(react@18.2.0) - '@chakra-ui/popover': 2.2.1(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react@18.2.0) + '@chakra-ui/popover': 2.2.1(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react@18.2.0) '@chakra-ui/popper': 3.1.0(react@18.2.0) '@chakra-ui/portal': 2.1.0(react-dom@18.2.0)(react@18.2.0) '@chakra-ui/progress': 2.2.0(@chakra-ui/system@2.6.2)(react@18.2.0) @@ -2530,7 +2530,7 @@ packages: '@chakra-ui/stat': 2.1.1(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/stepper': 2.3.1(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/styled-system': 2.9.2 - '@chakra-ui/switch': 2.1.2(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react@18.2.0) + '@chakra-ui/switch': 2.1.2(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react@18.2.0) '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) '@chakra-ui/table': 2.1.0(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/tabs': 3.0.0(@chakra-ui/system@2.6.2)(react@18.2.0) @@ -2538,14 +2538,14 @@ packages: '@chakra-ui/textarea': 2.1.2(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/theme': 3.3.1(@chakra-ui/styled-system@2.9.2) '@chakra-ui/theme-utils': 2.0.21 - '@chakra-ui/toast': 7.0.2(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/tooltip': 2.3.1(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/transition': 2.1.0(framer-motion@7.10.3)(react@18.2.0) + '@chakra-ui/toast': 7.0.2(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/tooltip': 2.3.1(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/transition': 2.1.0(framer-motion@11.0.3)(react@18.2.0) '@chakra-ui/utils': 2.0.15 '@chakra-ui/visually-hidden': 2.2.0(@chakra-ui/system@2.6.2)(react@18.2.0) '@emotion/react': 11.11.3(@types/react@18.2.48)(react@18.2.0) '@emotion/styled': 11.11.0(@emotion/react@11.11.3)(@types/react@18.2.48)(react@18.2.0) - framer-motion: 7.10.3(react-dom@18.2.0)(react@18.2.0) + framer-motion: 11.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) transitivePeerDependencies: @@ -2655,7 +2655,7 @@ packages: react-dom: optional: true dependencies: - '@chakra-ui/react': 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/react': 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0) '@storybook/components': 7.6.9(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) '@storybook/manager-api': 7.6.9(react-dom@18.2.0)(react@18.2.0) '@storybook/preview-api': 7.6.9 @@ -2671,7 +2671,7 @@ packages: csstype: 3.1.3 lodash.mergewith: 4.6.2 - /@chakra-ui/switch@2.1.2(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react@18.2.0): + /@chakra-ui/switch@2.1.2(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react@18.2.0): resolution: {integrity: sha512-pgmi/CC+E1v31FcnQhsSGjJnOE2OcND4cKPyTE+0F+bmGm48Q/b5UmKD9Y+CmZsrt/7V3h8KNczowupfuBfIHA==} peerDependencies: '@chakra-ui/system': '>=2.0.0' @@ -2681,7 +2681,7 @@ packages: '@chakra-ui/checkbox': 2.3.2(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/shared-utils': 2.0.5 '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) - framer-motion: 7.10.3(react-dom@18.2.0)(react@18.2.0) + framer-motion: 11.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 /@chakra-ui/system@2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0): @@ -2781,7 +2781,7 @@ packages: '@chakra-ui/styled-system': 2.9.2 '@chakra-ui/theme-tools': 2.1.2(@chakra-ui/styled-system@2.9.2) - /@chakra-ui/toast@7.0.2(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0): + /@chakra-ui/toast@7.0.2(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-yvRP8jFKRs/YnkuE41BVTq9nB2v/KDRmje9u6dgDmE5+1bFt3bwjdf9gVbif4u5Ve7F7BGk5E093ARRVtvLvXA==} peerDependencies: '@chakra-ui/system': 2.6.2 @@ -2799,11 +2799,11 @@ packages: '@chakra-ui/styled-system': 2.9.2 '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) '@chakra-ui/theme': 3.3.1(@chakra-ui/styled-system@2.9.2) - framer-motion: 7.10.3(react-dom@18.2.0)(react@18.2.0) + framer-motion: 11.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - /@chakra-ui/tooltip@2.3.1(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0): + /@chakra-ui/tooltip@2.3.1(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Rh39GBn/bL4kZpuEMPPRwYNnccRCL+w9OqamWHIB3Qboxs6h8cOyXfIdGxjo72lvhu1QI/a4KFqkM3St+WfC0A==} peerDependencies: '@chakra-ui/system': '>=2.0.0' @@ -2820,18 +2820,18 @@ packages: '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) '@chakra-ui/shared-utils': 2.0.5 '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) - framer-motion: 7.10.3(react-dom@18.2.0)(react@18.2.0) + framer-motion: 11.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - /@chakra-ui/transition@2.1.0(framer-motion@7.10.3)(react@18.2.0): + /@chakra-ui/transition@2.1.0(framer-motion@11.0.3)(react@18.2.0): resolution: {integrity: sha512-orkT6T/Dt+/+kVwJNy7zwJ+U2xAZ3EU7M3XCs45RBvUnZDr/u9vdmaM/3D/rOpmQJWgQBwKPJleUXrYWUagEDQ==} peerDependencies: framer-motion: '>=4.0.0' react: '>=18' dependencies: '@chakra-ui/shared-utils': 2.0.5 - framer-motion: 7.10.3(react-dom@18.2.0)(react@18.2.0) + framer-motion: 11.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 /@chakra-ui/utils@2.0.15: @@ -5426,47 +5426,6 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /@motionone/animation@10.17.0: - resolution: {integrity: sha512-ANfIN9+iq1kGgsZxs+Nz96uiNcPLGTXwfNo2Xz/fcJXniPYpaz/Uyrfa+7I5BPLxCP82sh7quVDudf1GABqHbg==} - dependencies: - '@motionone/easing': 10.17.0 - '@motionone/types': 10.17.0 - '@motionone/utils': 10.17.0 - tslib: 2.4.0 - - /@motionone/dom@10.17.0: - resolution: {integrity: sha512-cMm33swRlCX/qOPHWGbIlCl0K9Uwi6X5RiL8Ma6OrlJ/TP7Q+Np5GE4xcZkFptysFjMTi4zcZzpnNQGQ5D6M0Q==} - dependencies: - '@motionone/animation': 10.17.0 - '@motionone/generators': 10.17.0 - '@motionone/types': 10.17.0 - '@motionone/utils': 10.17.0 - hey-listen: 1.0.8 - tslib: 2.4.0 - - /@motionone/easing@10.17.0: - resolution: {integrity: sha512-Bxe2wSuLu/qxqW4rBFS5m9tMLOw+QBh8v5A7Z5k4Ul4sTj5jAOfZG5R0bn5ywmk+Fs92Ij1feZ5pmC4TeXA8Tg==} - dependencies: - '@motionone/utils': 10.17.0 - tslib: 2.4.0 - - /@motionone/generators@10.17.0: - resolution: {integrity: sha512-T6Uo5bDHrZWhIfxG/2Aut7qyWQyJIWehk6OB4qNvr/jwA/SRmixwbd7SOrxZi1z5rH3LIeFFBKK1xHnSbGPZSQ==} - dependencies: - '@motionone/types': 10.17.0 - '@motionone/utils': 10.17.0 - tslib: 2.4.0 - - /@motionone/types@10.17.0: - resolution: {integrity: sha512-EgeeqOZVdRUTEHq95Z3t8Rsirc7chN5xFAPMYFobx8TPubkEfRSm5xihmMUkbaR2ErKJTUw3347QDPTHIW12IA==} - - /@motionone/utils@10.17.0: - resolution: {integrity: sha512-bGwrki4896apMWIj9yp5rAS2m0xyhxblg6gTB/leWDPt+pb410W8lYWsxyurX+DH+gO1zsQsfx2su/c1/LtTpg==} - dependencies: - '@motionone/types': 10.17.0 - hey-listen: 1.0.8 - tslib: 2.4.0 - /@mysten/bcs@0.8.1: resolution: {integrity: sha512-wSEdP7QEfGQdb34g+7R0f3OdRqrv88iIABfJVDVJ6IsGLYVILreh8dZfNpZNUUyzctiyhX7zB9e/lR5qkddFPA==} dependencies: @@ -7639,7 +7598,7 @@ packages: resolution: {integrity: sha512-l3YHBLAol6d/IKnB9LhpD0cEZWAoe3eFKUyTYWmFmCO2Q/WOckxLQAUyMZWwZV2M/m3+4vgRoaolFqaII82/TA==} dev: false - /@rjsf/chakra-ui@5.0.0-beta.10(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/react@2.8.2)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@emotion/react@11.11.3)(@rjsf/core@5.0.0-beta.10)(@rjsf/utils@5.0.0-beta.10)(@types/react@18.2.48)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0): + /@rjsf/chakra-ui@5.0.0-beta.10(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/icons@2.1.1)(@chakra-ui/layout@2.3.1)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/react@2.8.2)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@emotion/react@11.11.3)(@rjsf/core@5.0.0-beta.10)(@rjsf/utils@5.0.0-beta.10)(@types/react@18.2.48)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-WHTOLrim5SgSR6rfxr+gu2fjIo69W0mL6dYngI9mI6Ep7xlpA9OLtE/njDDnwMczTVo4MkbCx/D1y5eqPeZyoQ==} engines: {node: '>=14'} peerDependencies: @@ -7651,11 +7610,11 @@ packages: react: ^16.14.0 || >=17 dependencies: '@chakra-ui/icons': 2.1.1(@chakra-ui/system@2.6.2)(react@18.2.0) - '@chakra-ui/react': 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/react': 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0) '@rjsf/core': 5.0.0-beta.10(@rjsf/utils@5.0.0-beta.10)(react@18.2.0) '@rjsf/utils': 5.0.0-beta.10(react@18.2.0) chakra-react-select: 4.7.6(@chakra-ui/form-control@2.2.0)(@chakra-ui/icon@3.2.0)(@chakra-ui/layout@2.3.1)(@chakra-ui/media-query@3.3.0)(@chakra-ui/menu@2.2.1)(@chakra-ui/spinner@2.1.0)(@chakra-ui/system@2.6.2)(@emotion/react@11.11.3)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) - framer-motion: 7.10.3(react-dom@18.2.0)(react@18.2.0) + framer-motion: 11.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-select: 5.8.0(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) transitivePeerDependencies: @@ -11373,7 +11332,7 @@ packages: '@chakra-ui/icon': 3.2.0(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/layout': 2.3.1(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/media-query': 3.3.0(@chakra-ui/system@2.6.2)(react@18.2.0) - '@chakra-ui/menu': 2.2.1(@chakra-ui/system@2.6.2)(framer-motion@7.10.3)(react@18.2.0) + '@chakra-ui/menu': 2.2.1(@chakra-ui/system@2.6.2)(framer-motion@11.0.3)(react@18.2.0) '@chakra-ui/spinner': 2.1.0(@chakra-ui/system@2.6.2)(react@18.2.0) '@chakra-ui/system': 2.6.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(react@18.2.0) '@emotion/react': 11.11.3(@types/react@18.2.48)(react@18.2.0) @@ -11390,7 +11349,7 @@ packages: '@chakra-ui/react': ^1.6.1 || ^2 react-markdown: ^7 || ^8 dependencies: - '@chakra-ui/react': 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@7.10.3)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/react': 2.8.2(@emotion/react@11.11.3)(@emotion/styled@11.11.0)(@types/react@18.2.48)(framer-motion@11.0.3)(react-dom@18.2.0)(react@18.2.0) deepmerge: 4.3.1 react-markdown: 9.0.1(@types/react@18.2.48)(react@18.2.0) dev: false @@ -13873,17 +13832,20 @@ packages: engines: {node: '>= 0.6'} dev: true - /framer-motion@7.10.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-k2ccYeZNSpPg//HTaqrU+4pRq9f9ZpaaN7rr0+Rx5zA4wZLbk547wtDzge2db1sB+1mnJ6r59P4xb+aEIi/W+w==} + /framer-motion@11.0.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-6x2poQpIWBdbZwLd73w6cKZ1I9IEPIU94C6/Swp1Zt3LJ+sB5bPe1E2wC6EH5hSISXNkMJ4afH7AdwS7MrtkWw==} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true dependencies: - '@motionone/dom': 10.17.0 - hey-listen: 1.0.8 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - tslib: 2.4.0 + tslib: 2.6.2 optionalDependencies: '@emotion/is-prop-valid': 0.8.8 @@ -14411,9 +14373,6 @@ packages: tslib: 2.6.2 dev: false - /hey-listen@1.0.8: - resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} - /hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} dependencies: diff --git a/src/lib/pages/proposal-details/components/ActiveDot.tsx b/src/lib/pages/proposal-details/components/ActiveDot.tsx index c3b81bff8..98bf8d49d 100644 --- a/src/lib/pages/proposal-details/components/ActiveDot.tsx +++ b/src/lib/pages/proposal-details/components/ActiveDot.tsx @@ -1,19 +1,29 @@ -import type { BoxProps } from "@chakra-ui/react"; +import { Box, type BoxProps } from "@chakra-ui/react"; +import { easeInOut, transform, useAnimationFrame } from "framer-motion"; +import { useRef } from "react"; -import { MotionBox } from "lib/components/MotionBox"; +import { getCurrentDate } from "lib/utils"; -export const ActiveDot = (props: BoxProps) => ( - -); +const DURATION = 1500; // in milliseconds +const opacityMap = transform([0, 0.5, 1], [1, 0.25, 1]); + +export const ActiveDot = (props: BoxProps) => { + const ref = useRef(null); + + useAnimationFrame(() => { + if (ref.current?.style) { + const time = getCurrentDate().getTime(); + ref.current.style.opacity = `${opacityMap(easeInOut((time % DURATION) / DURATION))}`; + } + }); + + return ( + + ); +}; diff --git a/src/lib/pages/proposal-details/components/ProgressBadge.tsx b/src/lib/pages/proposal-details/components/ProgressBadge.tsx index 1c803ed4a..ff85bd258 100644 --- a/src/lib/pages/proposal-details/components/ProgressBadge.tsx +++ b/src/lib/pages/proposal-details/components/ProgressBadge.tsx @@ -22,6 +22,7 @@ export enum BadgeState { export interface ProgressBadgeProps { state: BadgeState; text: string; + bgColor?: string; } const BadgeIcon = ({ state }: { state: BadgeState }) => { @@ -39,13 +40,17 @@ const BadgeIcon = ({ state }: { state: BadgeState }) => { } }; -export const ProgressBadge = ({ state, text }: ProgressBadgeProps) => ( +export const ProgressBadge = ({ + state, + text, + bgColor = "gray.900", +}: ProgressBadgeProps) => ( diff --git a/src/lib/pages/proposal-details/components/VoteQuorumBadge.tsx b/src/lib/pages/proposal-details/components/VoteQuorumBadge.tsx new file mode 100644 index 000000000..98a29ed2f --- /dev/null +++ b/src/lib/pages/proposal-details/components/VoteQuorumBadge.tsx @@ -0,0 +1,55 @@ +import { CustomIcon } from "lib/components/icon"; +import { ProposalStatus } from "lib/types"; + +import { ActiveDot } from "./ActiveDot"; +import { BadgeState, ProgressBadge } from "./ProgressBadge"; + +interface VoteQuorumBadgeProps { + status: ProposalStatus; + quorum: number; + totalVotes: Big; + isCompact: boolean; +} + +export const VoteQuorumBadge = ({ + status, + quorum, + totalVotes, + isCompact, +}: VoteQuorumBadgeProps) => { + if (totalVotes.gte(quorum)) + return isCompact ? ( + + ) : ( + + ); + + if (status === ProposalStatus.VOTING_PERIOD) + return isCompact ? ( + + ) : ( + + ); + + return isCompact ? ( + + ) : ( + + ); +}; diff --git a/src/lib/pages/proposal-details/components/VoteQuorumCircle.tsx b/src/lib/pages/proposal-details/components/VoteQuorumCircle.tsx new file mode 100644 index 000000000..a8ce1d29a --- /dev/null +++ b/src/lib/pages/proposal-details/components/VoteQuorumCircle.tsx @@ -0,0 +1,73 @@ +import { Circle, Heading, Text } from "@chakra-ui/react"; +import type Big from "big.js"; + +import { formatPrettyPercent } from "../utils"; + +interface VoteQuorumCircleProps { + quorum: number; + nonAbstainVotes: Big; + totalVotes: Big; + isCompact: boolean; +} + +export const VoteQuorumCircle = ({ + quorum, + nonAbstainVotes, + totalVotes, + isCompact, +}: VoteQuorumCircleProps) => { + const nonAbstainVotesAngle = nonAbstainVotes.toNumber() * 360; + + const totalVotesAngle = totalVotes.toNumber() * 360; + const totalVotesPercent = formatPrettyPercent(totalVotes.toNumber()); + + const quorumAngle = quorum * 360; + const quorumPercent = formatPrettyPercent(quorum); + + return ( + + + {!isCompact && ( + + {quorumPercent} + + )} + + + {!isCompact && ( + + Voted + + )} + + {totalVotesPercent} + + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/VoteThresholdBadge.tsx b/src/lib/pages/proposal-details/components/VoteThresholdBadge.tsx new file mode 100644 index 000000000..41700bee9 --- /dev/null +++ b/src/lib/pages/proposal-details/components/VoteThresholdBadge.tsx @@ -0,0 +1,36 @@ +import { CustomIcon } from "lib/components/icon"; +import { ProposalStatus } from "lib/types"; + +import { ActiveDot } from "./ActiveDot"; +import { BadgeState, ProgressBadge } from "./ProgressBadge"; + +interface VoteThresholdBadgeProps { + status: ProposalStatus; + isCompact: boolean; +} + +export const VoteThresholdBadge = ({ + status, + isCompact, +}: VoteThresholdBadgeProps) => { + if (status === ProposalStatus.VOTING_PERIOD) + return isCompact ? ( + + ) : ( + + ); + + return isCompact ? ( + + ) : ( + + ); +}; diff --git a/src/lib/pages/proposal-details/components/VoteThresholdBar.tsx b/src/lib/pages/proposal-details/components/VoteThresholdBar.tsx new file mode 100644 index 000000000..ccebaaa8b --- /dev/null +++ b/src/lib/pages/proposal-details/components/VoteThresholdBar.tsx @@ -0,0 +1,130 @@ +import { Flex, Text } from "@chakra-ui/react"; + +import { formatPrettyPercent, normalizeVotesInfo } from "../utils"; +import type { ProposalVotesInfo } from "lib/types"; +import { divWithDefault } from "lib/utils"; + +interface BarSectionProps { + percent: string; + color: string; + option: string; + textColor: string; + isCompact: boolean; +} + +const BarSection = ({ + percent, + color, + option, + textColor, + isCompact, +}: BarSectionProps) => ( + + {!isCompact && ( + <> + + {percent} + + + {option} + + + )} + +); + +interface VoteThresholdBarProps { + threshold: number; + votesInfo: ProposalVotesInfo; + isCompact: boolean; +} + +export const VoteThresholdBar = ({ + threshold, + votesInfo, + isCompact, +}: VoteThresholdBarProps) => { + const thresholdPercent = formatPrettyPercent(threshold); + + const { yes, no, noWithVeto, nonAbstainVotes } = + normalizeVotesInfo(votesInfo); + const yesRatioPercent = formatPrettyPercent( + divWithDefault(yes, nonAbstainVotes, 0).toNumber() + ); + const noRatioPercent = formatPrettyPercent( + divWithDefault(no, nonAbstainVotes, 0).toNumber() + ); + const noWithVetoRatioPercent = formatPrettyPercent( + divWithDefault(noWithVeto, nonAbstainVotes, 0).toNumber() + ); + + return ( + + + + Threshold{isCompact && ": "} + + + {thresholdPercent} + + + + + + + + + + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/VpPercentCard.tsx b/src/lib/pages/proposal-details/components/VpPercentCard.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/src/lib/pages/proposal-details/components/VpPercentThreshold.tsx b/src/lib/pages/proposal-details/components/VpPercentThreshold.tsx new file mode 100644 index 000000000..c48d75fb2 --- /dev/null +++ b/src/lib/pages/proposal-details/components/VpPercentThreshold.tsx @@ -0,0 +1,86 @@ +import { Flex, Text } from "@chakra-ui/react"; + +import { formatPrettyPercent, normalizeVotesInfo } from "../utils"; +import { CustomIcon } from "lib/components/icon"; +import type { ProposalVotesInfo } from "lib/types"; +import { d0Formatter, divWithDefault } from "lib/utils"; + +interface VpPercentThresholdProps { + votesInfo: ProposalVotesInfo; + isCompact: boolean; +} + +export const VpPercentThreshold = ({ + votesInfo, + isCompact, +}: VpPercentThresholdProps) => { + const { yes, no, noWithVeto, nonAbstainVotes } = + normalizeVotesInfo(votesInfo); + + const options = [ + { + option: "Yes", + color: "success.main", + percent: formatPrettyPercent( + divWithDefault(yes, nonAbstainVotes, 0).toNumber(), + true + ), + votingPower: d0Formatter(votesInfo.yes, "0"), + }, + { + option: "No", + color: "error.main", + percent: formatPrettyPercent( + divWithDefault(no, nonAbstainVotes, 0).toNumber(), + true + ), + votingPower: d0Formatter(votesInfo.no, "0"), + }, + { + option: "No with veto", + color: "error.dark", + percent: formatPrettyPercent( + divWithDefault(noWithVeto, nonAbstainVotes, 0).toNumber(), + true + ), + votingPower: d0Formatter(votesInfo.noWithVeto, "0"), + }, + ]; + + return isCompact ? ( +
+ + + Options + + + % (Voting Power) + + + {options.map(({ option, color, percent, votingPower }) => ( + + + + + {option} + + + + + {percent} + + + ({votingPower}) + + + + ))} +
+ ) : null; // TODO: will handle the vote detail desktop case here using `VpPercentCard` +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/index.tsx index 02e889f4e..7630904cb 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/index.tsx @@ -27,7 +27,7 @@ export const ProposalOverview = ({ isLoading, }: ProposalOverviewProps) => ( diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverview.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverview.tsx new file mode 100644 index 000000000..982c2b07a --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverview.tsx @@ -0,0 +1,89 @@ +import { Button, Flex, Text } from "@chakra-ui/react"; + +import type { ProposalOverviewProps } from "../.."; +import { ErrorFetchingProposalInfos } from "../../ErrorFetchingProposalInfos"; +import { useInternalNavigate } from "lib/app-provider"; +import { CustomIcon } from "lib/components/icon"; +import { Loading } from "lib/components/Loading"; +import { TabIndex, VoteTabIndex } from "lib/pages/proposal-details/type"; +import { ProposalStatus } from "lib/types"; +import { formatUTC } from "lib/utils"; + +import { VotingOverviewQuorum } from "./VotingOverviewQuorum"; +import { VotingOverviewThreshold } from "./VotingOverviewThreshold"; + +const VotingOverviewBody = ({ + proposalData, + params, + votesInfo, + isLoading, +}: ProposalOverviewProps) => { + const navigate = useInternalNavigate(); + + if (proposalData.status === ProposalStatus.DEPOSIT_PERIOD) + return ( + + The proposal will progress to voting period after meet the minimum + required deposit. + + ); + if (proposalData.status === ProposalStatus.DEPOSIT_FAILED) + return ( + + The proposal is rejected as it did not meet the required deposit. + + ); + if (proposalData.status === ProposalStatus.CANCELLED) + return ( + + The proposal was cancelled during the{" "} + {proposalData.votingTime ? "voting" : "deposit"} period at{" "} + {proposalData.resolvedTimestamp + ? formatUTC(proposalData.resolvedTimestamp) + : "N/A"} + + ); + + if (isLoading) return ; + if (!params || !votesInfo) return ; + + return ( + <> + + + + + ); +}; + +export const VotingOverview = (props: ProposalOverviewProps) => ( + + + +); diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx new file mode 100644 index 000000000..4848e6ee7 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx @@ -0,0 +1,72 @@ +import { Divider, Flex, Text } from "@chakra-ui/react"; + +import { VoteQuorumBadge } from "../../VoteQuorumBadge"; +import { VoteQuorumCircle } from "../../VoteQuorumCircle"; +import { + extractParams, + normalizeVotesInfo, +} from "lib/pages/proposal-details/utils"; +import type { + ProposalData, + ProposalParams, + ProposalVotesInfo, +} from "lib/types"; +import { dateFromNow, formatUTC } from "lib/utils"; + +import { VotingOverviewQuorumText } from "./VotingOverviewQuorumText"; + +interface VotingOverviewQuorumProps { + proposalData: ProposalData; + params: ProposalParams; + votesInfo: ProposalVotesInfo; +} + +export const VotingOverviewQuorum = ({ + proposalData, + params, + votesInfo, +}: VotingOverviewQuorumProps) => { + const { quorum } = extractParams(params, proposalData.isExpedited); + const { nonAbstainVotes, totalVotes } = normalizeVotesInfo(votesInfo); + + const endTime = proposalData.resolvedTimestamp ?? proposalData.votingEndTime; + return ( + + + + + Quorum + + + + + + + +
+ + Voting ended {endTime ? dateFromNow(endTime) : "N/A"} + + + {endTime ? formatUTC(endTime) : "N/A"} + +
+
+
+
+ ); +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorumText.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorumText.tsx new file mode 100644 index 000000000..487322f6b --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorumText.tsx @@ -0,0 +1,66 @@ +import { Text } from "@chakra-ui/react"; + +import { formatPrettyPercent } from "lib/pages/proposal-details/utils"; +import { ProposalStatus } from "lib/types"; + +interface VotingOverviewQuorumTextProps { + status: ProposalStatus; + quorum: number; + totalVotes: Big; +} + +const Established = () => ( + + established + +); + +export const VotingOverviewQuorumText = ({ + status, + quorum, + totalVotes, +}: VotingOverviewQuorumTextProps) => { + const quorumPercent = formatPrettyPercent(quorum); + const isPassingQuorum = totalVotes.gte(quorum); + + if (status === ProposalStatus.VOTING_PERIOD) + return isPassingQuorum ? ( + + The proposal has successfully met the voting{" "} + {quorumPercent} quorum and will + be after the voting period ends. + + ) : ( + + The proposal required{" "} + {quorumPercent} vote quorum to + establish. + + ); + + return isPassingQuorum ? ( + + The proposal has successfully met the voting{" "} + {quorumPercent} quorum and{" "} + . + + ) : ( + + This proposal{" "} + + did not meet the required {quorumPercent} quorum + + , resulting in its rejection regardless of the voting outcomes. + + ); +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx new file mode 100644 index 000000000..55d393ed2 --- /dev/null +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx @@ -0,0 +1,87 @@ +import { Flex, Text } from "@chakra-ui/react"; + +import { VoteThresholdBadge } from "../../VoteThresholdBadge"; +import { VoteThresholdBar } from "../../VoteThresholdBar"; +import { VpPercentThreshold } from "../../VpPercentThreshold"; +import { CustomIcon } from "lib/components/icon"; +import { StatusChip } from "lib/components/table"; +import { + extractParams, + getVoteResult, + normalizeVotesInfo, +} from "lib/pages/proposal-details/utils"; +import { + ProposalStatus, + type ProposalData, + type ProposalParams, + type ProposalVotesInfo, +} from "lib/types"; + +interface VotingOverviewThresholdProps { + proposalData: ProposalData; + params: ProposalParams; + votesInfo: ProposalVotesInfo; +} + +export const VotingOverviewThreshold = ({ + proposalData, + params, + votesInfo, +}: VotingOverviewThresholdProps) => { + const { quorum, threshold, vetoThreshold } = extractParams( + params, + proposalData.isExpedited + ); + const { totalVotes } = normalizeVotesInfo(votesInfo); + + const { result, resultColor } = getVoteResult( + threshold, + vetoThreshold, + votesInfo + ); + + return ( + + {(proposalData.status === ProposalStatus.VOTING_PERIOD || + totalVotes.gte(quorum)) && ( + + + {proposalData.status === ProposalStatus.VOTING_PERIOD ? ( + + Current Voting Result + + ) : ( + + + Final Vote Result: + + {proposalData.status === ProposalStatus.FAILED ? ( + + ) : ( + <> + + + {result} + + + )} + + )} + + )} + + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx index 8587974de..9c46baa17 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/index.tsx @@ -4,6 +4,7 @@ import type { ProposalOverviewProps } from ".."; import { ProposalStepper } from "../../proposal-stepper"; import { DepositOverview } from "./DepositOverview"; +import { VotingOverview } from "./VotingOverview"; export const ProposalPeriodOverview = ({ proposalData, @@ -16,5 +17,6 @@ export const ProposalPeriodOverview = ({ + ); diff --git a/src/lib/pages/proposal-details/utils.ts b/src/lib/pages/proposal-details/utils.ts index 383b73a54..caf258877 100644 --- a/src/lib/pages/proposal-details/utils.ts +++ b/src/lib/pages/proposal-details/utils.ts @@ -9,6 +9,7 @@ import type { TokenWithValue, U, } from "lib/types"; +import { divWithDefault } from "lib/utils"; export const normalizeVotesInfo = (votesInfo: ProposalVotesInfo) => { if (votesInfo.totalVotingPower.eq(0)) @@ -65,5 +66,32 @@ export const mapDeposit = ( }; }); -export const formatPrettyPercent = (ratio: number) => - `${ratio < 0.01 ? "<0.01" : Math.round(ratio * 10000) / 100}%`; +export const getVoteResult = ( + threshold: number, + vetoThreshold: number, + votesInfo: ProposalVotesInfo +) => { + const { yes, noWithVeto, nonAbstainVotes, totalVotes } = + normalizeVotesInfo(votesInfo); + + if (divWithDefault(noWithVeto, totalVotes, 0).gte(vetoThreshold)) + return { + result: "No with veto", + resultColor: "error.dark", + }; + if (divWithDefault(yes, nonAbstainVotes, 0).gte(threshold)) + return { + result: "Yes", + resultColor: "success.main", + }; + return { + result: "No", + resultColor: "error.main", + }; +}; + +export const formatPrettyPercent = (ratio: number, fixedFp = false) => { + if (ratio > 0 && ratio < 0.01) return "<0.01%"; + const percent = big(ratio * 100).round(2); + return `${fixedFp ? percent.toFixed(2) : percent.toNumber()}%`; +}; diff --git a/src/lib/styles/theme/components/heading.ts b/src/lib/styles/theme/components/heading.ts index 516d4a5e0..55068c5f5 100644 --- a/src/lib/styles/theme/components/heading.ts +++ b/src/lib/styles/theme/components/heading.ts @@ -45,5 +45,11 @@ export const Heading: ComponentStyleConfig = { lineHeight: 1.2, letterSpacing: "0.15px", }, + h7: { + fontSize: "16px", + fontWeight: 500, + lineHeight: 1.2, + letterSpacing: "0px", + }, }, }; diff --git a/src/lib/utils/formatter/token.test.ts b/src/lib/utils/formatter/token.test.ts index e95317a10..c7a454e04 100644 --- a/src/lib/utils/formatter/token.test.ts +++ b/src/lib/utils/formatter/token.test.ts @@ -12,6 +12,7 @@ import { formatUTokenWithPrecision, formatPrice, formatInteger, + d0Formatter, } from "./token"; const FALLBACK = "fallback"; @@ -107,6 +108,18 @@ describe("formatDecimal", () => { }); }); +describe("d0Formatter", () => { + test("from string", () => { + expect(d0Formatter("-1234.5678", FALLBACK)).toEqual("-1,234"); + expect(d0Formatter("1234", FALLBACK)).toEqual("1,234"); + }); + test("from number", () => { + expect(d0Formatter(1234.5, FALLBACK)).toEqual("1,234"); + expect(d0Formatter(1234, FALLBACK)).toEqual("1,234"); + expect(d0Formatter(-1234.5, FALLBACK)).toEqual("-1,234"); + }); +}); + describe("d2Formatter", () => { test("from string", () => { expect(d2Formatter("-1234.5678", FALLBACK)).toEqual("-1,234.56"); diff --git a/src/lib/utils/formatter/token.ts b/src/lib/utils/formatter/token.ts index e5a29c488..d4606c68e 100644 --- a/src/lib/utils/formatter/token.ts +++ b/src/lib/utils/formatter/token.ts @@ -42,6 +42,7 @@ export const formatDecimal = } }; +export const d0Formatter = formatDecimal({ decimalPoints: 0, delimiter: true }); export const d2Formatter = formatDecimal({ decimalPoints: 2, delimiter: true }); export const d6Formatter = formatDecimal({ decimalPoints: 6, delimiter: true }); From b8bfcdae2ab8c68d331a298a7feaf463d5f03400 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Mon, 12 Feb 2024 11:06:17 +0700 Subject: [PATCH 118/531] fix: remove unnecessary ml --- .../proposal-period-overview/VotingOverviewQuorum.tsx | 2 +- .../proposal-period-overview/VotingOverviewThreshold.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx index 4848e6ee7..25546bd58 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx @@ -31,7 +31,7 @@ export const VotingOverviewQuorum = ({ const endTime = proposalData.resolvedTimestamp ?? proposalData.votingEndTime; return ( - + Date: Mon, 12 Feb 2024 13:25:19 +0700 Subject: [PATCH 119/531] fix: no with veto status --- .../status-summary/SummaryStatusBody.tsx | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx index 14098d1ca..c1b62810b 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/SummaryStatusBody.tsx @@ -106,17 +106,33 @@ export const SummaryStatusBody = ({ if (noWithVetoRatio.gte(vetoThreshold)) return ( - The proposal has successfully met the voting quorum. However, if the - voting period concludes with a{" "} + The proposal has{" "} + + successfully met + {" "} + the voting quorum. However, the “No with veto” vote + proportion currently constitutes{" "} + + {formatPrettyPercent(noWithVetoRatio.toNumber())} + {" "} + of the total votes, including “Abstain”, which exceeds the{" "} - “No with veto” vote surpassing{" "} - {formatPrettyPercent(vetoThreshold)} + {formatPrettyPercent(vetoThreshold)} threshold - , the proposal will be regardless of other votes. + . If the proposal concludes with this voting outcome, it will be + rejected regardless of “Yes” votes. ); @@ -167,17 +183,23 @@ export const SummaryStatusBody = ({ if (noWithVetoRatio.gte(vetoThreshold)) return ( - This proposal has{" "} + Due to the “No with veto” vote proportion constitutes{" "} - reached - {" "} - the voting quorum. But the voting period ended with “No with - veto” more than {formatPrettyPercent(vetoThreshold)}, the - proposal will be regardless of other votes. + {formatPrettyPercent(noWithVetoRatio.toNumber())}{" "} +
+ of the total votes including “Abstain”, which exceeds the{" "} + + {formatPrettyPercent(vetoThreshold)} threshold + + , the proposal is regardless of “Yes” votes.
); From c18544a4a5433f269ec27da9076cbfe30f9eec4c Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Mon, 12 Feb 2024 13:59:53 +0700 Subject: [PATCH 120/531] feat: add quorum tooltip --- .../VotingOverviewQuorum.tsx | 45 ++++++++++++++++--- src/lib/pages/proposal-details/utils.ts | 2 +- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx index 25546bd58..aa76a7e27 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx @@ -2,8 +2,11 @@ import { Divider, Flex, Text } from "@chakra-ui/react"; import { VoteQuorumBadge } from "../../VoteQuorumBadge"; import { VoteQuorumCircle } from "../../VoteQuorumCircle"; +import { CustomIcon } from "lib/components/icon"; +import { Tooltip } from "lib/components/Tooltip"; import { extractParams, + formatPrettyPercent, normalizeVotesInfo, } from "lib/pages/proposal-details/utils"; import type { @@ -27,7 +30,8 @@ export const VotingOverviewQuorum = ({ votesInfo, }: VotingOverviewQuorumProps) => { const { quorum } = extractParams(params, proposalData.isExpedited); - const { nonAbstainVotes, totalVotes } = normalizeVotesInfo(votesInfo); + const { abstain, nonAbstainVotes, totalVotes } = + normalizeVotesInfo(votesInfo); const endTime = proposalData.resolvedTimestamp ?? proposalData.votingEndTime; return ( @@ -45,12 +49,39 @@ export const VotingOverviewQuorum = ({
- + + + + + {formatPrettyPercent(nonAbstainVotes.toNumber())} Vote + response + + + + + + {formatPrettyPercent(abstain.toNumber())} Vote abstain + + + + } + bgColor="gray.700" + > +
+ +
+
{ - if (ratio > 0 && ratio < 0.01) return "<0.01%"; + if (ratio > 0 && ratio < 0.0001) return "<0.01%"; const percent = big(ratio * 100).round(2); return `${fixedFp ? percent.toFixed(2) : percent.toNumber()}%`; }; From 4932404bbf65504e7d0366cc7cb3962833ac816e Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Mon, 12 Feb 2024 14:05:10 +0700 Subject: [PATCH 121/531] fix: box --- .../proposal-period-overview/VotingOverviewQuorum.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx index aa76a7e27..12a2c172b 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewQuorum.tsx @@ -1,4 +1,4 @@ -import { Divider, Flex, Text } from "@chakra-ui/react"; +import { Box, Divider, Flex, Text } from "@chakra-ui/react"; import { VoteQuorumBadge } from "../../VoteQuorumBadge"; import { VoteQuorumCircle } from "../../VoteQuorumCircle"; @@ -73,14 +73,14 @@ export const VotingOverviewQuorum = ({ } bgColor="gray.700" > -
+ -
+ Date: Mon, 12 Feb 2024 18:47:01 +0700 Subject: [PATCH 122/531] fix: ui --- .../proposal-details/components/VoteQuorumBadge.tsx | 10 +++------- .../proposal-details/components/VoteQuorumCircle.tsx | 5 ++++- .../components/VoteThresholdBadge.tsx | 4 ++-- .../components/VpPercentThreshold.tsx | 3 +++ .../VotingOverviewQuorum.tsx | 2 +- .../VotingOverviewThreshold.tsx | 2 +- src/lib/pages/proposal-details/utils.ts | 12 ++++++++---- 7 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/lib/pages/proposal-details/components/VoteQuorumBadge.tsx b/src/lib/pages/proposal-details/components/VoteQuorumBadge.tsx index 98a29ed2f..858558b57 100644 --- a/src/lib/pages/proposal-details/components/VoteQuorumBadge.tsx +++ b/src/lib/pages/proposal-details/components/VoteQuorumBadge.tsx @@ -19,11 +19,7 @@ export const VoteQuorumBadge = ({ }: VoteQuorumBadgeProps) => { if (totalVotes.gte(quorum)) return isCompact ? ( - + ) : ( + ) : ( + ) : ( { if (status === ProposalStatus.VOTING_PERIOD) return isCompact ? ( - + ) : ( + ) : ( - + {(proposalData.status === ProposalStatus.VOTING_PERIOD || totalVotes.gte(quorum)) && ( - + {proposalData.status === ProposalStatus.VOTING_PERIOD ? ( diff --git a/src/lib/pages/proposal-details/utils.ts b/src/lib/pages/proposal-details/utils.ts index 186d83128..7bde55d4a 100644 --- a/src/lib/pages/proposal-details/utils.ts +++ b/src/lib/pages/proposal-details/utils.ts @@ -90,8 +90,12 @@ export const getVoteResult = ( }; }; -export const formatPrettyPercent = (ratio: number, fixedFp = false) => { - if (ratio > 0 && ratio < 0.0001) return "<0.01%"; - const percent = big(ratio * 100).round(2); - return `${fixedFp ? percent.toFixed(2) : percent.toNumber()}%`; +export const formatPrettyPercent = (ratio: number, fp = 2, fixedFp = false) => { + const lowestPercent = 10 ** -fp; + + const percent = ratio * 100; + if (percent > 0 && percent < lowestPercent) return `<${lowestPercent}%`; + + const rounded = big(percent).round(fp); + return `${fixedFp ? rounded.toFixed(fp) : rounded.toNumber()}%`; }; From c99c2ce89ad355ab9b09c7b5d3a136bc5f5711d4 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:56:29 +0700 Subject: [PATCH 123/531] feat: voting overview veto alert --- CHANGELOG.md | 1 + .../VotingOverviewThreshold.tsx | 150 +++++++++++++----- 2 files changed, 113 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fe39ea32..6fd11dfea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#779](https://github.com/alleslabs/celatone-frontend/pull/779) Proposal period overview voting - no with veto alert - [#778](https://github.com/alleslabs/celatone-frontend/pull/778) Proposal period overview voting - [#775](https://github.com/alleslabs/celatone-frontend/pull/775) Proposal period overview deposit - [#766](https://github.com/alleslabs/celatone-frontend/pull/766) Proposal status summary body diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx index dad7dc72a..6d8c88163 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx @@ -7,6 +7,7 @@ import { CustomIcon } from "lib/components/icon"; import { StatusChip } from "lib/components/table"; import { extractParams, + formatPrettyPercent, getVoteResult, normalizeVotesInfo, } from "lib/pages/proposal-details/utils"; @@ -16,6 +17,7 @@ import { type ProposalParams, type ProposalVotesInfo, } from "lib/types"; +import { divWithDefault } from "lib/utils"; interface VotingOverviewThresholdProps { proposalData: ProposalData; @@ -32,7 +34,8 @@ export const VotingOverviewThreshold = ({ params, proposalData.isExpedited ); - const { totalVotes } = normalizeVotesInfo(votesInfo); + const { noWithVeto, totalVotes } = normalizeVotesInfo(votesInfo); + const noWithVetoRatio = divWithDefault(noWithVeto, totalVotes, 0); const { result, resultColor } = getVoteResult( threshold, @@ -41,46 +44,117 @@ export const VotingOverviewThreshold = ({ ); return ( - - {(proposalData.status === ProposalStatus.VOTING_PERIOD || - totalVotes.gte(quorum)) && ( - - - {proposalData.status === ProposalStatus.VOTING_PERIOD ? ( - - Current Voting Result - - ) : ( - + <> + + {(proposalData.status === ProposalStatus.VOTING_PERIOD || + totalVotes.gte(quorum)) && ( + + + {proposalData.status === ProposalStatus.VOTING_PERIOD ? ( - Final Vote Result: + Current Voting Result - {proposalData.status === ProposalStatus.FAILED ? ( - - ) : ( - <> - - - {result} - - - )} - - )} + ) : ( + + + Final Vote Result: + + {proposalData.status === ProposalStatus.FAILED ? ( + + ) : ( + <> + + + {result} + + + )} + + )} + + )} + + + + {noWithVetoRatio.gte(vetoThreshold) && ( + + + + {proposalData.status === ProposalStatus.VOTING_PERIOD ? ( + <> + Currently, the “No with veto” vote proportion + constitutes{" "} + + {formatPrettyPercent(noWithVetoRatio.toNumber())}{" "} + + of the total votes, including “Abstain”, which + exceeds the{" "} + + {formatPrettyPercent(vetoThreshold)} threshold + + . If the proposal concludes with this voting outcome, it will be + regardless of “Yes” votes. + + ) : ( + <> + Due to the “No with veto” vote proportion + constitutes{" "} + + {formatPrettyPercent(noWithVetoRatio.toNumber())}{" "} + + of the total votes including “Abstain”, which + exceeds the{" "} + + {formatPrettyPercent(vetoThreshold)} threshold + + , the proposal is rejected regardless of “Yes” + votes. + + )} + )} - - - + ); }; From 0eb38d6ee661a29231008a62bb14d3c6a8a22290 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Sun, 11 Feb 2024 22:38:33 +0700 Subject: [PATCH 124/531] feat: proposal votes table --- src/lib/app-provider/env.ts | 2 + src/lib/components/ValidatorBadge.tsx | 3 + .../components/AllVotesTable.tsx | 39 ---- .../proposal-details/components/index.ts | 2 +- .../{ => vote-details}/ProposalStepper.tsx | 0 .../{ => vote-details}/VoteDetailTab.tsx | 0 .../deposit-period}/DepositPeriodSection.tsx | 0 .../index.tsx} | 47 ++-- .../voting-period/ProposalVotesPanel.tsx | 50 ++++ .../voting-period/ValidatorVotesPanel.tsx} | 6 +- .../voting-period/index.tsx} | 87 ++++--- .../voting-period/votes-table/Answer.tsx | 43 ++++ .../votes-table/ProposalVotesTableHeader.tsx | 38 +++ .../votes-table/ProposalVotesTableRow.tsx | 99 ++++++++ .../voting-period/votes-table/Voter.tsx | 45 ++++ .../voting-period/votes-table/index.tsx | 216 ++++++++++++++++++ src/lib/pages/proposal-details/index.tsx | 4 +- src/lib/providers/utils.ts | 11 + src/lib/services/proposal.ts | 53 ++++- src/lib/services/proposalService.ts | 40 ++++ src/lib/types/proposal.ts | 2 +- 21 files changed, 683 insertions(+), 104 deletions(-) delete mode 100644 src/lib/pages/proposal-details/components/AllVotesTable.tsx rename src/lib/pages/proposal-details/components/{ => vote-details}/ProposalStepper.tsx (100%) rename src/lib/pages/proposal-details/components/{ => vote-details}/VoteDetailTab.tsx (100%) rename src/lib/pages/proposal-details/components/{ => vote-details/deposit-period}/DepositPeriodSection.tsx (100%) rename src/lib/pages/proposal-details/components/{VoteDetail.tsx => vote-details/index.tsx} (72%) create mode 100644 src/lib/pages/proposal-details/components/vote-details/voting-period/ProposalVotesPanel.tsx rename src/lib/pages/proposal-details/components/{ValidatorVotesTable.tsx => vote-details/voting-period/ValidatorVotesPanel.tsx} (88%) rename src/lib/pages/proposal-details/components/{VotingPeriodSection.tsx => vote-details/voting-period/index.tsx} (70%) create mode 100644 src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/Answer.tsx create mode 100644 src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/ProposalVotesTableHeader.tsx create mode 100644 src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/ProposalVotesTableRow.tsx create mode 100644 src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/Voter.tsx create mode 100644 src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/index.tsx create mode 100644 src/lib/providers/utils.ts diff --git a/src/lib/app-provider/env.ts b/src/lib/app-provider/env.ts index dfdcae140..b959c86e3 100644 --- a/src/lib/app-provider/env.ts +++ b/src/lib/app-provider/env.ts @@ -53,7 +53,9 @@ export enum CELATONE_QUERY_KEYS { // X/GOV PROPOSAL_DATA = "CELATONE_QUERY_PROPOSAL_DATA", PROPOSAL_VALIDATOR_VOTES_INFO = "CELATONE_QUERY_PROPOSAL_VALIDATOR_VOTES_INFO", + PROPOSAL_VOTES = "CELATONE_QUERY_PROPOSAL_VOTES", PROPOSAL_VALIDATOR_VOTES = "CELATONE_QUERY_PROPOSAL_VALIDATOR_VOTES", + PROPOSAL_ANSWER_COUNTS = "CELATONE_QUERY_PROPOSAL_ANSWER_COUNTS", RELATED_PROPOSALS_BY_CONTRACT_ADDRESS = "CELATONE_QUERY_RELATED_PROPOSALS_BY_CONTRACT_ADDRESS", PROPOSALS_BY_MODULE_ID = "CELATONE_QUERY_PROPOSALS_BY_MODULE_ID", PROPOSALS_COUNT_BY_MODULE_ID = "CELATONE_QUERY_PROPOSALS_COUNT_BY_MODULE_ID", diff --git a/src/lib/components/ValidatorBadge.tsx b/src/lib/components/ValidatorBadge.tsx index f1c2ec92d..e6b7d66e4 100644 --- a/src/lib/components/ValidatorBadge.tsx +++ b/src/lib/components/ValidatorBadge.tsx @@ -14,6 +14,7 @@ interface ValidatorBadgeProps { ampCopierSection?: string; maxWidth?: string; hasLabel?: boolean; + moreInfo?: JSX.Element; } const FallbackRender = ({ @@ -40,6 +41,7 @@ export const ValidatorBadge = ({ ampCopierSection, maxWidth = "160px", hasLabel = true, + moreInfo, }: ValidatorBadgeProps) => { const { data: valImgSrc, isLoading } = useValidatorImage(validator); const isMobile = useMobile(); @@ -71,6 +73,7 @@ export const ValidatorBadge = ({ maxWidth={maxWidth} fixedHeight /> + {moreInfo} ) : ( diff --git a/src/lib/pages/proposal-details/components/AllVotesTable.tsx b/src/lib/pages/proposal-details/components/AllVotesTable.tsx deleted file mode 100644 index 10d93cd3a..000000000 --- a/src/lib/pages/proposal-details/components/AllVotesTable.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import type { FlexProps } from "@chakra-ui/react"; -import { Button, Flex } from "@chakra-ui/react"; - -import { useMobile } from "lib/app-provider"; -import { CustomIcon } from "lib/components/icon"; -import { TableTitle } from "lib/components/table"; - -interface AllVotesTableProps extends FlexProps { - onBack: () => void; -} - -export const AllVotesTable = ({ onBack, ...props }: AllVotesTableProps) => { - const isMobile = useMobile(); - return ( - - - - - - - - - ); -}; diff --git a/src/lib/pages/proposal-details/components/index.ts b/src/lib/pages/proposal-details/components/index.ts index 1e1ac9a84..d49ecfafc 100644 --- a/src/lib/pages/proposal-details/components/index.ts +++ b/src/lib/pages/proposal-details/components/index.ts @@ -1,3 +1,3 @@ export * from "./proposal-overview"; export * from "./proposal-top"; -export * from "./VoteDetail"; +export * from "./vote-details"; diff --git a/src/lib/pages/proposal-details/components/ProposalStepper.tsx b/src/lib/pages/proposal-details/components/vote-details/ProposalStepper.tsx similarity index 100% rename from src/lib/pages/proposal-details/components/ProposalStepper.tsx rename to src/lib/pages/proposal-details/components/vote-details/ProposalStepper.tsx diff --git a/src/lib/pages/proposal-details/components/VoteDetailTab.tsx b/src/lib/pages/proposal-details/components/vote-details/VoteDetailTab.tsx similarity index 100% rename from src/lib/pages/proposal-details/components/VoteDetailTab.tsx rename to src/lib/pages/proposal-details/components/vote-details/VoteDetailTab.tsx diff --git a/src/lib/pages/proposal-details/components/DepositPeriodSection.tsx b/src/lib/pages/proposal-details/components/vote-details/deposit-period/DepositPeriodSection.tsx similarity index 100% rename from src/lib/pages/proposal-details/components/DepositPeriodSection.tsx rename to src/lib/pages/proposal-details/components/vote-details/deposit-period/DepositPeriodSection.tsx diff --git a/src/lib/pages/proposal-details/components/VoteDetail.tsx b/src/lib/pages/proposal-details/components/vote-details/index.tsx similarity index 72% rename from src/lib/pages/proposal-details/components/VoteDetail.tsx rename to src/lib/pages/proposal-details/components/vote-details/index.tsx index 76d790169..aba460339 100644 --- a/src/lib/pages/proposal-details/components/VoteDetail.tsx +++ b/src/lib/pages/proposal-details/components/vote-details/index.tsx @@ -10,14 +10,14 @@ import { TabPanels, Tabs, } from "@chakra-ui/react"; -import type { ReactNode } from "react"; +import { useMemo, type ReactNode } from "react"; import { useMobile } from "lib/app-provider"; -import { DepositPeriodSection } from "./DepositPeriodSection"; +import { DepositPeriodSection } from "./deposit-period/DepositPeriodSection"; import { ProposalStepper } from "./ProposalStepper"; import { VoteDetailTab } from "./VoteDetailTab"; -import { VotingPeriodSection } from "./VotingPeriodSection"; +import { VotingPeriod } from "./voting-period"; const AccordionItemComponent = ({ step, @@ -47,22 +47,31 @@ const AccordionItemComponent = ({ ); -export const VoteDetail = () => { +interface VoteDetailProps { + id: number; +} + +export const VoteDetail = ({ id }: VoteDetailProps) => { const isMobile = useMobile(); - const accordionData = [ - { - step: 1, - title: "Deposit Period", - description: "Deposit ends in 4 days 21:00:11", - content: , - }, - { - step: 2, - title: "Voting Period", - description: "Voting ends in 3 days 12:00:10", - content: , - }, - ]; + + const accordionData = useMemo( + () => [ + { + step: 1, + title: "Deposit Period", + description: "Deposit ends in 4 days 21:00:11", + content: , + }, + { + step: 2, + title: "Voting Period", + description: "Voting ends in 3 days 12:00:10", + content: , + }, + ], + // TODO: Add dependencies + [id] + ); return isMobile ? ( @@ -95,7 +104,7 @@ export const VoteDetail = () => { borderRadius="0px 0px 8px 8px" > {accordionData.map((item) => ( - {item.content} + {item.content} ))} diff --git a/src/lib/pages/proposal-details/components/vote-details/voting-period/ProposalVotesPanel.tsx b/src/lib/pages/proposal-details/components/vote-details/voting-period/ProposalVotesPanel.tsx new file mode 100644 index 000000000..60b12d8f9 --- /dev/null +++ b/src/lib/pages/proposal-details/components/vote-details/voting-period/ProposalVotesPanel.tsx @@ -0,0 +1,50 @@ +import { Button, Flex } from "@chakra-ui/react"; + +import { useMobile } from "lib/app-provider"; +import { CustomIcon } from "lib/components/icon"; +import { TableTitle } from "lib/components/table"; +import type { ProposalAnswerCountsResponse } from "lib/services/proposal"; +import type { Option } from "lib/types"; + +import { ProposalVotesTable } from "./votes-table"; + +interface ProposalVotesPanelProps { + isOpen: boolean; + onBack: () => void; + answers: Option; + id: number; +} + +export const ProposalVotesPanel = ({ + isOpen, + onBack, + answers, + id, +}: ProposalVotesPanelProps) => { + const isMobile = useMobile(); + + return ( + + + + + + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx b/src/lib/pages/proposal-details/components/vote-details/voting-period/ValidatorVotesPanel.tsx similarity index 88% rename from src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx rename to src/lib/pages/proposal-details/components/vote-details/voting-period/ValidatorVotesPanel.tsx index c8e0bb416..d4410c347 100644 --- a/src/lib/pages/proposal-details/components/ValidatorVotesTable.tsx +++ b/src/lib/pages/proposal-details/components/vote-details/voting-period/ValidatorVotesPanel.tsx @@ -5,14 +5,14 @@ import { useMobile } from "lib/app-provider"; import { CustomIcon } from "lib/components/icon"; import { TableTitle } from "lib/components/table"; -interface ValidatorVotesTableProps extends FlexProps { +interface ValidatorVotesPanelProps extends FlexProps { onBack: () => void; } -export const ValidatorVotesTable = ({ +export const ValidatorVotesPanel = ({ onBack, ...props -}: ValidatorVotesTableProps) => { +}: ValidatorVotesPanelProps) => { const isMobile = useMobile(); return ( { - const isMobile = useMobile(); - return ( - - {children} - - ); -}; + transparent?: boolean; +}) => ( + + {children} + +); + +interface VotingPeriodProps { + id: number; +} -export const VotingPeriodSection = () => { +export const VotingPeriod = ({ id }: VotingPeriodProps) => { const isMobile = useMobile(); const validatorVoteDisclosure = useDisclosure(); const allVoteDisclosure = useDisclosure(); + const { data: answers } = useProposalAnswerCounts(id); + return ( { gap={4} > {/* Vote Participations */} - + {!isMobile && } Vote Participations Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta pariatur eveniet ducimus quasi veritatis labore aut @@ -66,7 +71,7 @@ export const VotingPeriodSection = () => { reiciendis voluptatum, aliquid quam ullam! {/* Vote Results */} - + {!isMobile && } Vote Results Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta pariatur eveniet ducimus quasi veritatis labore aut minima @@ -76,9 +81,13 @@ export const VotingPeriodSection = () => { {/* Validator Votes */} - + - + - Recent Votes Lorem ipsum dolor, sit amet consectetur adipisicing - elit. Necessitatibus ipsam perspiciatis eius illo maiores, magnam - architecto nesciunt esse animi obcaecati voluptates delectus - doloribus magni alias a eligendi odio nam iure? + - - diff --git a/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/Answer.tsx b/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/Answer.tsx new file mode 100644 index 000000000..16016959b --- /dev/null +++ b/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/Answer.tsx @@ -0,0 +1,43 @@ +import { Box, HStack, Text } from "@chakra-ui/react"; + +import { TooltipInfo } from "lib/components/Tooltip"; +import type { ProposalVote } from "lib/types"; + +interface AnswerProps { + proposalVote: ProposalVote; +} + +const resolveVote = (proposalVote: ProposalVote): [string, string] => { + if (proposalVote.isVoteWeighted) { + return ["primary.light", "Weighted"]; + } + if (proposalVote.yes === 1) { + return ["success.main", "Yes"]; + } + if (proposalVote.no === 1) { + return ["error.main", "No"]; + } + if (proposalVote.noWithVeto === 1) { + return ["error.dark", "No with veto"]; + } + if (proposalVote.abstain === 1) { + return ["gray.600", "Abstain"]; + } + return ["gray.600", "Did not vote"]; +}; + +export const Answer = ({ proposalVote }: AnswerProps) => { + const [color, text] = resolveVote(proposalVote); + return ( + + + {text} + {proposalVote.isVoteWeighted && } + + ); +}; diff --git a/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/ProposalVotesTableHeader.tsx b/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/ProposalVotesTableHeader.tsx new file mode 100644 index 000000000..9aea20d7e --- /dev/null +++ b/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/ProposalVotesTableHeader.tsx @@ -0,0 +1,38 @@ +import type { GridProps } from "@chakra-ui/react"; +import { Grid } from "@chakra-ui/react"; + +import { useMobile } from "lib/app-provider"; +import { TableHeader } from "lib/components/table"; + +interface ProposalVotesTableHeaderProps { + templateColumns: GridProps["templateColumns"]; + fullVersion: boolean; +} + +export const ProposalVotesTableHeader = ({ + templateColumns, + fullVersion, +}: ProposalVotesTableHeaderProps) => { + const isMobile = useMobile(); + + if (isMobile) + return ( + + Address (Vote Answer) + + + ); + + return ( + + Voters + Answer + {fullVersion && ( + <> + Timestamp + Transaction Hash + + )} + + ); +}; diff --git a/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/ProposalVotesTableRow.tsx b/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/ProposalVotesTableRow.tsx new file mode 100644 index 000000000..79a4fc9a3 --- /dev/null +++ b/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/ProposalVotesTableRow.tsx @@ -0,0 +1,99 @@ +import { Button, Flex, Grid, Text } from "@chakra-ui/react"; + +import { useMobile } from "lib/app-provider"; +import { ExplorerLink } from "lib/components/ExplorerLink"; +import { TableRow } from "lib/components/table"; +import { useOpenTxTab } from "lib/hooks"; +import type { ProposalVote } from "lib/types"; +import { dateFromNow, formatUTC } from "lib/utils"; + +import { Answer } from "./Answer"; +import { Voter } from "./Voter"; + +interface ProposalVotesTableRowProps { + proposalVote: ProposalVote; + templateColumns: string; + fullVersion: boolean; +} + +export const ProposalVotesTableRow = ({ + proposalVote, + templateColumns, + fullVersion, +}: ProposalVotesTableRowProps) => { + const isMobile = useMobile(); + const openTxTab = useOpenTxTab("tx-page"); + + if (isMobile) + return ( + + + + + + + {proposalVote.timestamp ? ( + + {dateFromNow(proposalVote.timestamp)} + + ) : ( + N/A + )} + {proposalVote.txHash ? ( + + ) : ( + N/A + )} + + + + ); + + return ( + + + + + + + + {fullVersion && !isMobile && ( + <> + + {proposalVote.timestamp ? ( + + {formatUTC(proposalVote.timestamp)} + + ({dateFromNow(proposalVote.timestamp)}) + + + ) : ( + N/A + )} + + + {proposalVote.txHash ? ( + + ) : ( + N/A + )} + + + )} + + ); +}; diff --git a/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/Voter.tsx b/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/Voter.tsx new file mode 100644 index 000000000..f1373a3c8 --- /dev/null +++ b/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/Voter.tsx @@ -0,0 +1,45 @@ +import { Text, VStack } from "@chakra-ui/react"; + +import { useMobile } from "lib/app-provider"; +import { ExplorerLink } from "lib/components/ExplorerLink"; +import { ValidatorBadge } from "lib/components/ValidatorBadge"; +import type { ProposalVote } from "lib/types"; + +import { Answer } from "./Answer"; + +interface VoterProps { + proposalVote: ProposalVote; +} + +export const Voter = ({ proposalVote }: VoterProps) => { + const isMobile = useMobile(); + + if (proposalVote.validator) { + return ( + : undefined} + /> + ); + } + + if (proposalVote.voter) { + return ( + + + {isMobile && } + + ); + } + + return ( + + - + + ); +}; diff --git a/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/index.tsx b/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/index.tsx new file mode 100644 index 000000000..4fdf4fc50 --- /dev/null +++ b/src/lib/pages/proposal-details/components/vote-details/voting-period/votes-table/index.tsx @@ -0,0 +1,216 @@ +import { Box, Grid, GridItem, TableContainer } from "@chakra-ui/react"; +import { useState, type ChangeEvent, useMemo } from "react"; + +import { useMobile } from "lib/app-provider"; +import { SelectInput } from "lib/components/forms"; +import InputWithIcon from "lib/components/InputWithIcon"; +import { Loading } from "lib/components/Loading"; +import { Pagination } from "lib/components/pagination"; +import { usePaginator } from "lib/components/pagination/usePaginator"; +import { EmptyState, ErrorFetching } from "lib/components/state"; +import { useDebounce } from "lib/hooks"; +import type { ProposalAnswerCountsResponse } from "lib/services/proposal"; +import { useProposalVotes } from "lib/services/proposalService"; +import type { Option, ProposalVote } from "lib/types"; + +import { ProposalVotesTableHeader } from "./ProposalVotesTableHeader"; +import { ProposalVotesTableRow } from "./ProposalVotesTableRow"; + +interface ProposalVotesTableBodyProps { + proposalVotes: Option; + fullVersion: boolean; + isLoading: boolean; +} + +export const ProposalVotesTableBody = ({ + proposalVotes, + fullVersion, + isLoading, +}: ProposalVotesTableBodyProps) => { + const isMobile = useMobile(); + const templateColumns = + fullVersion && !isMobile ? `1fr 0.8fr 1.5fr 1fr` : `2fr 1fr`; + + if (isLoading) return ; + if (!proposalVotes) return ; + + if (proposalVotes.length === 0) { + return ( + + ); + } + return ( + + + {proposalVotes.map((each, idx) => ( + + ))} + + ); +}; + +interface ProposalVotesTableProps { + id: number; + answers: Option; + fullVersion: boolean; +} + +// pass it to api +enum AnswerType { + ALL = "all", + YES = "yes", + NO = "no", + NO_WITH_VETO = "no_with_veto", + ABSTAIN = "abstain", + WEIGHTED = "weighted", +} + +export const ProposalVotesTable = ({ + id, + answers, + fullVersion, +}: ProposalVotesTableProps) => { + const [answerFilter, setAnswerFilter] = useState(AnswerType.ALL); + const [search, setSearch] = useState(""); + const debouncedSearch = useDebounce(search); + + const { data, isLoading } = useProposalVotes( + id, + 10, + 0, + answerFilter, + debouncedSearch + ); + + const { + pagesQuantity, + currentPage, + setCurrentPage, + pageSize, + setPageSize, + offset, + } = usePaginator({ + total: answers?.total, + initialState: { + pageSize: 10, + currentPage: 1, + isDisabled: false, + }, + }); + + const total = answers?.total ?? 0; + + const answerOptions = useMemo( + () => [ + { + label: `All votes (${total})`, + value: AnswerType.ALL, + disabled: false, + }, + { + label: `Yes (${answers?.yes ?? 0})`, + value: AnswerType.YES, + disabled: false, + }, + { + label: `No (${answers?.no ?? 0})`, + value: AnswerType.NO, + disabled: false, + }, + { + label: `No with veto (${answers?.noWithVeto ?? 0})`, + value: AnswerType.NO_WITH_VETO, + disabled: false, + }, + { + label: `Abstain (${answers?.abstain ?? 0})`, + value: AnswerType.ABSTAIN, + disabled: false, + }, + { + label: `Weighted (${answers?.weighted ?? 0})`, + value: AnswerType.WEIGHTED, + disabled: false, + }, + ], + // eslint-disable-next-line react-hooks/exhaustive-deps + [total, JSON.stringify(answers)] + ); + + const handleOnSearchChange = (e: ChangeEvent) => { + setCurrentPage(1); + setSearch(e.target.value); + }; + + const handleOnAnswerFilterChange = (newAnswer: AnswerType) => { + setCurrentPage(1); + setAnswerFilter(newAnswer); + }; + + const onPageChange = (nextPage: number) => { + setCurrentPage(nextPage); + }; + + const onPageSizeChange = (e: ChangeEvent) => { + const size = Number(e.target.value); + setPageSize(size); + setCurrentPage(1); + }; + + return ( + + {fullVersion && ( + + + + formLabel="Filter by Answer" + options={answerOptions} + onChange={handleOnAnswerFilterChange} + initialSelected={answerFilter} + /> + + + + + + )} + + {!!total && fullVersion && ( + + )} + + ); +}; diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index 1cc51338c..be21ada26 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -1,6 +1,6 @@ import { TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"; import { useRouter } from "next/router"; -import { useCallback, useEffect } from "react"; +import { useCallback } from "react"; import { AmpEvent, track } from "lib/amplitude"; import { useGovConfig, useInternalNavigate } from "lib/app-provider"; @@ -80,7 +80,7 @@ const ProposalDetailsBody = ({ /> - + diff --git a/src/lib/providers/utils.ts b/src/lib/providers/utils.ts new file mode 100644 index 000000000..18889f9f9 --- /dev/null +++ b/src/lib/providers/utils.ts @@ -0,0 +1,11 @@ +import React from "react"; + +export default function createContext(name: string) { + const context = React.createContext(undefined); + const useContext = () => { + const state = React.useContext(context); + if (!state) throw new Error(`use${name} must be inside a provider`); + return state; + }; + return [useContext, context.Provider] as const; +} diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 4fa226606..440257776 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -279,12 +279,15 @@ const zProposalVotesResponseItem = z no_with_veto: z.number().nonnegative(), yes: z.number().nonnegative(), is_vote_weighted: z.boolean(), - validator: zValidator, + validator: zValidator.nullable(), voter: zBechAddr.nullable(), timestamp: zUtcDate.nullable(), tx_hash: z.string().nullable(), }) - .transform(snakeToCamel); + .transform((val) => ({ + ...snakeToCamel(val), + txHash: val.tx_hash ? parseTxHash(val.tx_hash) : null, + })); const zProposalVotesResponse = z.object({ items: z.array(zProposalVotesResponseItem), @@ -299,3 +302,49 @@ export const getProposalValidatorVotes = async ( axios .get(`${endpoint}/${encodeURIComponent(id)}/validator-votes`) .then(({ data }) => zProposalVotesResponse.parse(data)); + +export const getProposalVotes = async ( + endpoint: string, + id: number, + limit: number, + offset: number, + answer?: string, + search?: string +): Promise => { + let url = `${endpoint}/${encodeURIComponent(id)}/votes?limit=${limit}&offset=${offset}`; + url = url.concat(search ? `&search=${encodeURIComponent(search)}` : ""); + url = url.concat(answer ? `&answer=${encodeURIComponent(answer)}` : ""); + + return axios.get(url).then(({ data }) => zProposalVotesResponse.parse(data)); +}; + +const zProposalAnswerCounts = z.object({ + yes: z.number().nonnegative(), + abstain: z.number().nonnegative(), + no: z.number().nonnegative(), + no_with_veto: z.number().nonnegative(), + total: z.number().nonnegative(), + weighted: z.number().nonnegative(), +}); + +const zProposalAnswerCountsResponse = z + .object({ + all: zProposalAnswerCounts, + validator: zProposalAnswerCounts, + }) + .transform(snakeToCamel); + +export type ProposalAnswerCountsResponse = z.infer< + typeof zProposalAnswerCountsResponse +>; + +export const getProposalAnswerCounts = async ( + endpoint: string, + id: number, + validatorOnly: boolean +): Promise => + axios + .get( + `${endpoint}/${encodeURIComponent(id)}/answer-counts?validator=${validatorOnly}` + ) + .then(({ data }) => zProposalAnswerCountsResponse.parse(data)); diff --git a/src/lib/services/proposalService.ts b/src/lib/services/proposalService.ts index e867de4ad..6e278cc10 100644 --- a/src/lib/services/proposalService.ts +++ b/src/lib/services/proposalService.ts @@ -41,6 +41,7 @@ import { useAssetInfos } from "./assetService"; import { useMovePoolInfos } from "./move"; import type { DepositParamsInternal, + ProposalAnswerCountsResponse, ProposalDataResponse, ProposalVotesResponse, ProposalsResponse, @@ -57,6 +58,8 @@ import { getProposalData, getProposalParams, getProposalTypes, + getProposalAnswerCounts, + getProposalVotes, getProposalValidatorVotes, getProposalVotesInfo, getRelatedProposalsByContractAddress, @@ -359,3 +362,40 @@ export const useProposalValidatorVotes = (id: number) => { { retry: 1, refetchOnWindowFocus: false } ); }; + +export const useProposalVotes = ( + id: number, + limit: number, + offset: number, + answer?: string, + search?: string +): UseQueryResult => { + const endpoint = useBaseApiRoute("proposals"); + + return useQuery( + [ + CELATONE_QUERY_KEYS.PROPOSAL_VOTES, + endpoint, + id, + limit, + offset, + search, + answer, + ], + async () => getProposalVotes(endpoint, id, limit, offset, answer, search), + { retry: 1, refetchOnWindowFocus: false } + ); +}; + +export const useProposalAnswerCounts = ( + id: number, + validatorOnly = false +): UseQueryResult => { + const endpoint = useBaseApiRoute("proposals"); + + return useQuery( + [CELATONE_QUERY_KEYS.PROPOSAL_ANSWER_COUNTS, endpoint, id, validatorOnly], + async () => getProposalAnswerCounts(endpoint, id, validatorOnly), + { retry: 1, refetchOnWindowFocus: false } + ); +}; diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 846a11df7..69b6b84a7 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -143,7 +143,7 @@ export interface ProposalVote { noWithVeto: number; yes: number; isVoteWeighted: boolean; - validator: Validator; + validator: Nullable; voter: Nullable; timestamp: Nullable; txHash: Nullable; From 09b51acf73550f3e283a095e378be8320d314e10 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Sun, 11 Feb 2024 22:42:34 +0700 Subject: [PATCH 125/531] docs: add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c350fe4f..709fc695f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#777](https://github.com/alleslabs/celatone-frontend/pull/777) Proposal votes table including filter and search functionality - [#766](https://github.com/alleslabs/celatone-frontend/pull/766) Proposal status summary body - [#763](https://github.com/alleslabs/celatone-frontend/pull/763) Proposal status summary top - [#765](https://github.com/alleslabs/celatone-frontend/pull/765) Support Proposal Cancelled status From 41083041f0489c7c49de55c472cafa13ef5f5745 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Sun, 11 Feb 2024 22:44:35 +0700 Subject: [PATCH 126/531] refactor: remove unused --- src/lib/providers/utils.ts | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 src/lib/providers/utils.ts diff --git a/src/lib/providers/utils.ts b/src/lib/providers/utils.ts deleted file mode 100644 index 18889f9f9..000000000 --- a/src/lib/providers/utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; - -export default function createContext(name: string) { - const context = React.createContext(undefined); - const useContext = () => { - const state = React.useContext(context); - if (!state) throw new Error(`use${name} must be inside a provider`); - return state; - }; - return [useContext, context.Provider] as const; -} From 440f70b7134a079d214d0b7d954b73832c8a2762 Mon Sep 17 00:00:00 2001 From: evilpeach Date: Tue, 13 Feb 2024 12:01:54 +0700 Subject: [PATCH 127/531] fix: as comments --- src/lib/components/forms/SelectInput.tsx | 4 +++- src/lib/components/pagination/PageDetail.tsx | 1 + .../components/vote-details/index.tsx | 4 ++-- .../voting-period/votes-table/Answer.tsx | 24 ++++++++++++++++--- .../voting-period/votes-table/index.tsx | 17 ++++++++++--- src/lib/pages/proposal-details/index.tsx | 6 ++--- 6 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/lib/components/forms/SelectInput.tsx b/src/lib/components/forms/SelectInput.tsx index 574f7113c..8ff8056bf 100644 --- a/src/lib/components/forms/SelectInput.tsx +++ b/src/lib/components/forms/SelectInput.tsx @@ -34,6 +34,7 @@ interface SelectInputProps { hasDivider?: boolean; helperTextComponent?: ReactNode; labelBgColor?: string; + popoverBgColor?: string; size?: string | object; } @@ -69,6 +70,7 @@ export const SelectInput = ({ hasDivider = false, helperTextComponent, labelBgColor = "background.main", + popoverBgColor = "gray.900", size = "lg", }: SelectInputProps) => { const inputRef = useRef() as MutableRefObject; @@ -149,7 +151,7 @@ export const SelectInput = ({ value === isActive)} + onChange={(selectedOption) => + selectedOption && setIsActive(selectedOption.value) + } + chakraStyles={{ + valueContainer: (provided) => ({ + ...provided, + pl: 3, + pr: 0, + }), + dropdownIndicator: (provided) => ({ + ...provided, + px: 2, + }), + option: (provided) => ({ + ...provided, + color: "text.main", + fontSize: "16px", + _hover: { + bg: "gray.700", + }, + _selected: { + bg: "gray.800", + }, + }), + }} + isSearchable={false} + /> + + ); +}; diff --git a/src/lib/pages/validators/components/OrderSelect.tsx b/src/lib/pages/validators/components/OrderSelect.tsx new file mode 100644 index 000000000..c109a7b30 --- /dev/null +++ b/src/lib/pages/validators/components/OrderSelect.tsx @@ -0,0 +1,95 @@ +import { Flex, Text } from "@chakra-ui/react"; +import { Select } from "chakra-react-select"; + +import { ValidatorOrder } from "../types"; + +const ORDER_OPTIONS = [ + { + label: "Name (A to Z)", + value: { order: ValidatorOrder.Moniker, isDesc: false }, + }, + { + label: "Name (Z to A)", + value: { order: ValidatorOrder.Moniker, isDesc: true }, + }, + { + label: "Voting Power (High to Low)", + value: { order: ValidatorOrder.VotingPower, isDesc: true }, + }, + { + label: "Voting Power (Low to High)", + value: { order: ValidatorOrder.VotingPower, isDesc: false }, + }, + { + label: "Uptime (High to Low)", + value: { order: ValidatorOrder.Uptime, isDesc: true }, + }, + { + label: "Uptime (Low to High)", + value: { order: ValidatorOrder.Uptime, isDesc: false }, + }, + { + label: "Commission (High to Low)", + value: { order: ValidatorOrder.Commission, isDesc: true }, + }, + { + label: "Commission (Low to High)", + value: { order: ValidatorOrder.Commission, isDesc: false }, + }, +]; + +interface OrderSelectProps { + order: ValidatorOrder; + setOrder: (value: ValidatorOrder) => void; + isDesc: boolean; + setIsDesc: (value: boolean) => void; +} + +export const OrderSelect = ({ + order, + setOrder, + isDesc, + setIsDesc, +}: OrderSelectProps) => ( + + + Sorted by + + ` component for the `core` theme. + * It is used as the template for rendering many of the based widgets that differ by `type` and callbacks only. + * It can be customized/overridden for other themes or individual implementations as needed. + * + * @param props - The `WidgetProps` for this template + */ +export default function BaseInputTemplate< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +>(props: BaseInputTemplateProps) { const { id, - type, + name, // remove this from ...rest value, label, - schema, - uiSchema, - onChange, + readonly, + disabled, + autofocus, onBlur, onFocus, + onChange, + onChangeOverride, options, required = false, - readonly, - rawErrors, - autofocus, - // placeholder, - disabled, - // formContext, + schema, + uiSchema, + formContext, registry, + rawErrors, + type, + hideLabel, // remove this from ...rest + hideError, // remove this from ...rest + ...rest } = props; - const inputProps = getInputProps(schema, type, options); - - const uiOptions = getUiOptions(uiSchema); const DescriptionFieldTemplate = getTemplate< "DescriptionFieldTemplate", T, + S, F - >("DescriptionFieldTemplate", registry, uiOptions); + >("DescriptionFieldTemplate", registry, options); const { schemaUtils } = registry; const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema) && (!!label || !!schema.title); - const handleOnChange = ({ target }: ChangeEvent) => - onChange(target.value === "" ? options.emptyValue : target.value); - const handleOnBlur = ({ target }: FocusEvent) => - onBlur(id, target.value); - const handleOnFocus = ({ target }: FocusEvent) => - onFocus(id, target.value); + // Note: since React 15.2.0 we can't forward unknown element attributes, so we + // exclude the "options" and "schema" ones here. + if (!id) { + // console.log("No id for", props); + throw new Error(`no id for props ${JSON.stringify(props)}`); + } + const inputProps = { + ...rest, + ...getInputProps(schema, type, options), + }; + let inputValue; + if (inputProps.type === "number" || inputProps.type === "integer") { + inputValue = value || value === 0 ? value : ""; + } else { + inputValue = value == null ? "" : value; + } + + const handleOnChange = useCallback( + ({ target }: ChangeEvent) => + onChange(value === "" ? options.emptyValue : target.value), + [onChange, options.emptyValue, value] + ); + const handleOnBlur = useCallback( + ({ target }: FocusEvent) => onBlur(id, target.value), + [onBlur, id] + ); + const handleOnFocus = useCallback( + ({ target }: FocusEvent) => onFocus(id, target.value), + [onFocus, id] + ); // const rightAddon = renderRightAddOn( // value, // label, @@ -127,9 +176,9 @@ const BaseInputTemplate = (props: WidgetProps) => { // ); const isStringType = isSchemaTypeString(schema.type); - return ( (props: WidgetProps) => { (props: WidgetProps) => { // )?.[1] } {...inputProps} - list={schema.examples ? `examples_${id}` : undefined} + list={schema.examples ? examplesId(id) : undefined} + onChange={handleOnChange} + onBlur={handleOnBlur} + onFocus={handleOnFocus} + aria-describedby={ariaDescribedByIds(id, !!schema.examples)} _disabled={{ color: "text.main", cursor: "not-allowed", @@ -188,8 +238,9 @@ const BaseInputTemplate = (props: WidgetProps) => { /> {/* {rightAddon && {rightAddon}} */} - {!readonly && isStringType && ( + {isStringType && ( { @@ -201,8 +252,8 @@ const BaseInputTemplate = (props: WidgetProps) => { )} - {Array.isArray(schema.examples) ? ( - + {Array.isArray(schema.examples) && ( + (id)}> {(schema.examples as string[]) .concat( schema.default && !schema.examples.includes(schema.default) @@ -215,18 +266,17 @@ const BaseInputTemplate = (props: WidgetProps) => { ); })} - ) : null} + )} {!!schema.description && ( (id)} description={schema.description} + schema={schema} registry={registry} /> )} ); -}; - -export default BaseInputTemplate; +} diff --git a/src/lib/components/json-schema/form/templates/DescriptionFieldTemplate.tsx b/src/lib/components/json-schema/form/templates/DescriptionFieldTemplate.tsx index 744a4f834..c9e11aa23 100644 --- a/src/lib/components/json-schema/form/templates/DescriptionFieldTemplate.tsx +++ b/src/lib/components/json-schema/form/templates/DescriptionFieldTemplate.tsx @@ -1,15 +1,21 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Text } from "@chakra-ui/react"; -import type { DescriptionFieldProps } from "@rjsf/utils"; +import type { + DescriptionFieldProps, + FormContextType, + RJSFSchema, + StrictRJSFSchema, +} from "@rjsf/utils"; -/** - * Description Field for the jsonschema forms. - * @param description - * @param id +/** The `DescriptionField` is the template to use to render the description of a field + * + * @param props - The `DescriptionFieldProps` for this component */ -const DescriptionFieldTemplate = ( - props: DescriptionFieldProps -) => { +export default function DescriptionField< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +>(props: DescriptionFieldProps) { const { id, description } = props; if (!description) { return null; @@ -32,6 +38,4 @@ const DescriptionFieldTemplate = ( {description} ); -}; - -export default DescriptionFieldTemplate; +} diff --git a/src/lib/components/json-schema/form/templates/FieldTemplate.tsx b/src/lib/components/json-schema/form/templates/FieldTemplate.tsx index 8399b4713..eaaefc48e 100644 --- a/src/lib/components/json-schema/form/templates/FieldTemplate.tsx +++ b/src/lib/components/json-schema/form/templates/FieldTemplate.tsx @@ -1,11 +1,23 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { FormControl } from "@chakra-ui/react"; -import type { FieldTemplateProps } from "@rjsf/utils"; +import type { + FieldTemplateProps, + FormContextType, + RJSFSchema, + StrictRJSFSchema, +} from "@rjsf/utils"; import { getTemplate, getUiOptions } from "@rjsf/utils"; -export default function FieldTemplate( - props: FieldTemplateProps -) { +/** The `FieldTemplate` component is the template used by `SchemaField` to render any field. It renders the field + * content, (label, description, children, errors and help) inside of a `WrapIfAdditional` component. + * + * @param props - The `FieldTemplateProps` for this component + */ +export default function FieldTemplate< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +>(props: FieldTemplateProps) { const { id, children, @@ -24,16 +36,17 @@ export default function FieldTemplate( schema, uiSchema, } = props; - const uiOptions = getUiOptions(uiSchema); + const uiOptions = getUiOptions(uiSchema); const WrapIfAdditionalTemplate = getTemplate< "WrapIfAdditionalTemplate", T, + S, F >("WrapIfAdditionalTemplate", registry, uiOptions); - - return hidden ? ( -
{children}
- ) : ( + if (hidden) { + return
{children}
; + } + return ( ( - props: ObjectFieldTemplateProps -) => { +/** The `ObjectFieldTemplate` is the template to use to render all the inner properties of an object along with the + * title and description if available. If the object is expandable, then an `AddButton` is also rendered after all + * the properties. + * + * @param props - The `ObjectFieldTemplateProps` for this component + */ +export default function ObjectFieldTemplate< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +>(props: ObjectFieldTemplateProps) { const { description, - properties, disabled, - readonly, - uiSchema, - idSchema, - schema, formData, + idSchema, onAddClick, + properties, + readonly, registry, + schema, + uiSchema, } = props; - const uiOptions = getUiOptions(uiSchema); - const DescriptionFieldTemplate = getTemplate<"DescriptionFieldTemplate">( + const options = getUiOptions(uiSchema); + const DescriptionFieldTemplate = getTemplate< "DescriptionFieldTemplate", - registry, - uiOptions - ); + T, + S, + F + >("DescriptionFieldTemplate", registry, options); // Button templates are not overridden in the uiSchema const { ButtonTemplates: { AddButton }, } = registry.templates; - return ( - <> - {(uiOptions.description || description) && ( +
+ {description && ( (idSchema)} + description={description} + schema={schema} + uiSchema={uiSchema} registry={registry} /> )} @@ -42,7 +63,11 @@ const ObjectFieldTemplate = ( {properties.length > 0 ? ( properties.map((element, index) => element.hidden ? ( - element.content + + {element.content} + ) : ( ( object with no properties )} - {canExpand(schema, uiSchema, formData) && ( + {canExpand(schema, uiSchema, formData) && ( )} - +
); -}; - -export default ObjectFieldTemplate; +} diff --git a/src/lib/components/json-schema/form/templates/TitleFieldTemplate.tsx b/src/lib/components/json-schema/form/templates/TitleFieldTemplate.tsx index 7b033586e..4d0d6e409 100644 --- a/src/lib/components/json-schema/form/templates/TitleFieldTemplate.tsx +++ b/src/lib/components/json-schema/form/templates/TitleFieldTemplate.tsx @@ -1,13 +1,21 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Text } from "@chakra-ui/react"; -import type { TitleFieldProps } from "@rjsf/utils"; +import type { + FormContextType, + RJSFSchema, + StrictRJSFSchema, + TitleFieldProps, +} from "@rjsf/utils"; + /** The `TitleField` is the template to use to render the title of a field * * @param props - The `TitleFieldProps` for this component */ -export default function TitleFieldTemplate( - props: TitleFieldProps -) { +export default function TitleField< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +>(props: TitleFieldProps) { const { id, title } = props; return ( diff --git a/src/lib/components/json-schema/form/templates/button-templates/AddButton.tsx b/src/lib/components/json-schema/form/templates/button-templates/AddButton.tsx index a6107dc6b..cef8ffb24 100644 --- a/src/lib/components/json-schema/form/templates/button-templates/AddButton.tsx +++ b/src/lib/components/json-schema/form/templates/button-templates/AddButton.tsx @@ -1,13 +1,24 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Button } from "@chakra-ui/react"; -import type { IconButtonProps } from "@rjsf/utils"; +import { TranslatableString } from "@rjsf/utils"; +import type { + FormContextType, + IconButtonProps, + RJSFSchema, + StrictRJSFSchema, +} from "@rjsf/utils"; -export default function AddButton({ - uiSchema, - ...props -}: IconButtonProps) { +export default function AddButton< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +>(props: IconButtonProps) { + const { + registry: { translateString }, + } = props; return ( + + + + + ); +}; diff --git a/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts b/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts index c587bcb62..814e501db 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts +++ b/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts @@ -19,7 +19,11 @@ type Story = StoryObj; const data: Omit< ProposalData, - "status" | "depositEndTime" | "votingEndTime" | "resolvedTimestamp" + | "status" + | "failedReason" + | "depositEndTime" + | "votingEndTime" + | "resolvedTimestamp" > = { id: 999, title: "storybook", @@ -77,6 +81,7 @@ export const DepositPeriod: Story = { proposalData: { ...data, status: ProposalStatus.DEPOSIT_PERIOD, + failedReason: "", depositEndTime: dayjs().utc().add(2, "days").toDate(), votingEndTime: null, resolvedTimestamp: null, @@ -97,6 +102,7 @@ export const VotingPeriodRejectedQuorum: Story = { proposalData: { ...data, status: ProposalStatus.VOTING_PERIOD, + failedReason: "", depositEndTime: dayjs().utc().toDate(), votingEndTime: dayjs().utc().add(2, "days").toDate(), resolvedTimestamp: null, @@ -117,6 +123,7 @@ export const VotingPeriodRejectedNoWithVeto: Story = { proposalData: { ...data, status: ProposalStatus.VOTING_PERIOD, + failedReason: "", depositEndTime: dayjs().utc().toDate(), votingEndTime: dayjs().utc().add(2, "days").toDate(), resolvedTimestamp: null, @@ -137,6 +144,7 @@ export const VotingPeriodRejectedNotPassed: Story = { proposalData: { ...data, status: ProposalStatus.VOTING_PERIOD, + failedReason: "", depositEndTime: dayjs().utc().toDate(), votingEndTime: dayjs().utc().add(2, "days").toDate(), resolvedTimestamp: null, @@ -157,6 +165,7 @@ export const VotingPeriodPassed: Story = { proposalData: { ...data, status: ProposalStatus.VOTING_PERIOD, + failedReason: "", depositEndTime: dayjs().utc().toDate(), votingEndTime: dayjs().utc().add(2, "days").toDate(), resolvedTimestamp: null, @@ -177,6 +186,8 @@ export const Failed: Story = { proposalData: { ...data, status: ProposalStatus.FAILED, + failedReason: + "VM error: status BACKWARD_INCOMPATIBLE_MODULE_UPDATE of type Verification with message Module Update Failure: Public function/struct signature of new module differs from existing module in 0000000000000000000000000000000000000000000000000000000000000001::simple_json", depositEndTime: dayjs().utc().toDate(), votingEndTime: dayjs().utc().toDate(), resolvedTimestamp: dayjs().utc().toDate(), @@ -197,6 +208,7 @@ export const RejectedQuorum: Story = { proposalData: { ...data, status: ProposalStatus.REJECTED, + failedReason: "", depositEndTime: dayjs().utc().toDate(), votingEndTime: dayjs().utc().toDate(), resolvedTimestamp: dayjs().utc().toDate(), @@ -217,6 +229,7 @@ export const RejectedNoWithVeto: Story = { proposalData: { ...data, status: ProposalStatus.REJECTED, + failedReason: "", depositEndTime: dayjs().utc().toDate(), votingEndTime: dayjs().utc().toDate(), resolvedTimestamp: dayjs().utc().toDate(), @@ -237,6 +250,7 @@ export const RejectedNotPassed: Story = { proposalData: { ...data, status: ProposalStatus.REJECTED, + failedReason: "", depositEndTime: dayjs().utc().toDate(), votingEndTime: dayjs().utc().toDate(), resolvedTimestamp: dayjs().utc().toDate(), @@ -257,6 +271,7 @@ export const Passed: Story = { proposalData: { ...data, status: ProposalStatus.PASSED, + failedReason: "", depositEndTime: dayjs().utc().toDate(), votingEndTime: dayjs().utc().toDate(), resolvedTimestamp: dayjs().utc().toDate(), @@ -277,6 +292,7 @@ export const Cancelled: Story = { proposalData: { ...data, status: ProposalStatus.CANCELLED, + failedReason: "", depositEndTime: dayjs().utc().toDate(), votingEndTime: dayjs().utc().toDate(), resolvedTimestamp: dayjs().utc().toDate(), @@ -297,6 +313,7 @@ export const DepositFailed: Story = { proposalData: { ...data, status: ProposalStatus.DEPOSIT_FAILED, + failedReason: "", depositEndTime: dayjs().utc().toDate(), votingEndTime: null, resolvedTimestamp: dayjs().utc().toDate(), diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 65e50dcd3..d4864ad10 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -198,6 +198,7 @@ export const getRelatedProposalsByContractAddress = async ( const zProposalDataResponse = z.object({ info: zProposal .extend({ + failed_reason: z.string(), created_height: z.number().nullable(), created_timestamp: zUtcDate.nullable(), created_tx_hash: z.string().nullable(), diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 42f929423..27589c24b 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -114,6 +114,7 @@ interface Message { export interface ProposalData extends Proposal { + failedReason: string; createdHeight: Nullable; createdTimestamp: Nullable; createdTxHash: Nullable; From 05f37de8bba5bcff37ef41659e8549ff002fd52b Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Mon, 1 Apr 2024 17:30:18 +0700 Subject: [PATCH 415/531] fix(components): add link to doc for move --- src/lib/components/PageHeader.tsx | 10 +++-- src/lib/components/UserDocsLink.tsx | 2 +- src/lib/pages/account-details/index.tsx | 41 +++++++++++++------ .../block-details/components/BlockInfo.tsx | 6 --- src/lib/pages/block-details/index.tsx | 6 +++ src/lib/pages/code-details/index.tsx | 4 +- src/lib/pages/contract-details/index.tsx | 10 ++--- src/lib/pages/contract-list/index.tsx | 2 +- src/lib/pages/contract-list/slug.tsx | 2 +- src/lib/pages/deploy-script/index.tsx | 27 ++++++++---- src/lib/pages/deploy/index.tsx | 2 +- src/lib/pages/interact/index.tsx | 17 ++------ .../migrate/components/MigrateOptions.tsx | 2 +- src/lib/pages/module-details/index.tsx | 21 ++++++++++ src/lib/pages/modules/index.tsx | 13 +++--- .../pages/nft-collection-details/index.tsx | 6 +++ src/lib/pages/nft-collections/index.tsx | 14 +++---- src/lib/pages/nft-details/index.tsx | 6 +++ .../components/pool-details/PoolAssets.tsx | 2 +- src/lib/pages/pools/poolId.tsx | 2 +- src/lib/pages/proposal-details/index.tsx | 4 +- src/lib/pages/publish-module/publish.tsx | 12 +++++- src/lib/pages/saved-accounts/index.tsx | 4 +- src/lib/pages/saved-codes/index.tsx | 2 +- 24 files changed, 139 insertions(+), 78 deletions(-) diff --git a/src/lib/components/PageHeader.tsx b/src/lib/components/PageHeader.tsx index a60cc82e4..b1ab02368 100644 --- a/src/lib/components/PageHeader.tsx +++ b/src/lib/components/PageHeader.tsx @@ -6,7 +6,7 @@ import { UserDocsLink } from "./UserDocsLink"; interface PageHeaderProps { title: string; - subtitle: string; + subtitle?: string; docHref: string; } @@ -27,9 +27,11 @@ export const PageHeader = ({ title, subtitle, docHref }: PageHeaderProps) => { {isMobile && }
- - {subtitle} - + {subtitle && ( + + {subtitle} + + )} {!isMobile && }
diff --git a/src/lib/components/UserDocsLink.tsx b/src/lib/components/UserDocsLink.tsx index 42543a612..87dead567 100644 --- a/src/lib/components/UserDocsLink.tsx +++ b/src/lib/components/UserDocsLink.tsx @@ -78,7 +78,7 @@ export const UserDocsLink = ({ }} > - + {cta}
diff --git a/src/lib/pages/account-details/index.tsx b/src/lib/pages/account-details/index.tsx index 4e52921ca..9dd5e8509 100644 --- a/src/lib/pages/account-details/index.tsx +++ b/src/lib/pages/account-details/index.tsx @@ -404,28 +404,33 @@ const AccountDetailsBody = ({ )} + @@ -448,7 +453,7 @@ const AccountDetailsBody = ({ /> @@ -461,7 +466,7 @@ const AccountDetailsBody = ({ /> @@ -474,7 +479,7 @@ const AccountDetailsBody = ({ /> @@ -485,6 +490,11 @@ const AccountDetailsBody = ({ resourcesByOwner={resourcesData?.groupedByOwner} isLoading={isResourceLoading} /> + + diff --git a/src/lib/pages/block-details/components/BlockInfo.tsx b/src/lib/pages/block-details/components/BlockInfo.tsx index 8db1d2a35..5bdbfd414 100644 --- a/src/lib/pages/block-details/components/BlockInfo.tsx +++ b/src/lib/pages/block-details/components/BlockInfo.tsx @@ -2,7 +2,6 @@ import { Box, Flex, Heading } from "@chakra-ui/react"; import { useCelatoneApp } from "lib/app-provider"; import { LabelText } from "lib/components/LabelText"; -import { UserDocsLink } from "lib/components/UserDocsLink"; import { ValidatorBadge } from "lib/components/ValidatorBadge"; import type { BlockData } from "lib/types"; import { formatInteger } from "lib/utils"; @@ -19,11 +18,6 @@ export const BlockInfo = ({ blockData }: BlockInfoProps) => { Block Info -
diff --git a/src/lib/pages/block-details/index.tsx b/src/lib/pages/block-details/index.tsx index 8acd9fc23..7487d210a 100644 --- a/src/lib/pages/block-details/index.tsx +++ b/src/lib/pages/block-details/index.tsx @@ -6,6 +6,7 @@ import { Breadcrumb } from "lib/components/Breadcrumb"; import { Loading } from "lib/components/Loading"; import PageContainer from "lib/components/PageContainer"; import { InvalidState } from "lib/components/state"; +import { UserDocsLink } from "lib/components/UserDocsLink"; import { useBlockData } from "lib/services/blockService"; import { BlockDetailsTop, BlockInfo, BlockTxsTable } from "./components"; @@ -33,6 +34,11 @@ const BlockDetailsBody = ({ height }: BlockDetailsBodyProps) => { + ); }; diff --git a/src/lib/pages/code-details/index.tsx b/src/lib/pages/code-details/index.tsx index eb922eff5..8b5164fa8 100644 --- a/src/lib/pages/code-details/index.tsx +++ b/src/lib/pages/code-details/index.tsx @@ -111,7 +111,7 @@ const CodeDetailsBody = observer(({ codeId, tab }: CodeDetailsBodyProps) => { @@ -123,7 +123,7 @@ const CodeDetailsBody = observer(({ codeId, tab }: CodeDetailsBodyProps) => { /> diff --git a/src/lib/pages/contract-details/index.tsx b/src/lib/pages/contract-details/index.tsx index 2fcc9f268..396ff7716 100644 --- a/src/lib/pages/contract-details/index.tsx +++ b/src/lib/pages/contract-details/index.tsx @@ -237,7 +237,7 @@ const ContractDetailsBody = observer( @@ -245,7 +245,7 @@ const ContractDetailsBody = observer( @@ -253,7 +253,7 @@ const ContractDetailsBody = observer( @@ -261,7 +261,7 @@ const ContractDetailsBody = observer( @@ -269,7 +269,7 @@ const ContractDetailsBody = observer( diff --git a/src/lib/pages/contract-list/index.tsx b/src/lib/pages/contract-list/index.tsx index 9d0d7cc92..2c9c3cc04 100644 --- a/src/lib/pages/contract-list/index.tsx +++ b/src/lib/pages/contract-list/index.tsx @@ -53,7 +53,7 @@ const AllContractListsPage = observer(() => { diff --git a/src/lib/pages/contract-list/slug.tsx b/src/lib/pages/contract-list/slug.tsx index 0804aa565..3e3f991d9 100644 --- a/src/lib/pages/contract-list/slug.tsx +++ b/src/lib/pages/contract-list/slug.tsx @@ -176,7 +176,7 @@ const ContractsByList = observer(() => { {!isInstantiatedByMe && ( )} diff --git a/src/lib/pages/deploy-script/index.tsx b/src/lib/pages/deploy-script/index.tsx index 8b1c55f94..b48b3c5ec 100644 --- a/src/lib/pages/deploy-script/index.tsx +++ b/src/lib/pages/deploy-script/index.tsx @@ -13,6 +13,7 @@ import { useDeployScriptTx } from "lib/app-provider/tx/script"; import { ConnectWalletAlert } from "lib/components/ConnectWalletAlert"; import { ErrorMessageRender } from "lib/components/ErrorMessageRender"; import { EstimatedFeeRender } from "lib/components/EstimatedFeeRender"; +import { UserDocsLink } from "lib/components/UserDocsLink"; import WasmPageContainer from "lib/components/WasmPageContainer"; import { useTxBroadcast } from "lib/providers/tx-broadcast"; import type { AbiFormData, ExposedFunction, Option } from "lib/types"; @@ -135,13 +136,25 @@ export const DeployScript = () => { return ( <> - - Script - - - Upload a .mv file to deploy one-time use Script which execute - messages. - + + + Script + + + Upload a .mv file to deploy one-time use Script which execute + messages. + + + {
diff --git a/src/lib/pages/interact/index.tsx b/src/lib/pages/interact/index.tsx index 7ef75535b..af9d75ec3 100644 --- a/src/lib/pages/interact/index.tsx +++ b/src/lib/pages/interact/index.tsx @@ -1,12 +1,4 @@ -import { - Box, - Button, - Flex, - Grid, - Heading, - Text, - useDisclosure, -} from "@chakra-ui/react"; +import { Box, Button, Flex, Grid, Text, useDisclosure } from "@chakra-ui/react"; import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; @@ -16,6 +8,7 @@ import { CustomIcon } from "lib/components/icon"; import { LabelText } from "lib/components/LabelText"; import { ModuleSourceCode } from "lib/components/module"; import PageContainer from "lib/components/PageContainer"; +import { PageHeader } from "lib/components/PageHeader"; import { useOpenNewTab } from "lib/hooks"; import type { IndexedModule } from "lib/services/move/moduleService"; import { @@ -150,16 +143,14 @@ export const Interact = () => { display="grid" gridTemplateRows="auto auto 1fr" > - - Module Interactions - + {module ? ( <> diff --git a/src/lib/pages/migrate/components/MigrateOptions.tsx b/src/lib/pages/migrate/components/MigrateOptions.tsx index 47077da05..b36823dec 100644 --- a/src/lib/pages/migrate/components/MigrateOptions.tsx +++ b/src/lib/pages/migrate/components/MigrateOptions.tsx @@ -41,7 +41,7 @@ export const MigrateOptions = ({ diff --git a/src/lib/pages/module-details/index.tsx b/src/lib/pages/module-details/index.tsx index b8e691b7b..9dc38f5d2 100644 --- a/src/lib/pages/module-details/index.tsx +++ b/src/lib/pages/module-details/index.tsx @@ -9,6 +9,7 @@ import { CustomTab } from "lib/components/CustomTab"; import { Loading } from "lib/components/Loading"; import PageContainer from "lib/components/PageContainer"; import { InvalidState } from "lib/components/state"; +import { UserDocsLink } from "lib/components/UserDocsLink"; import { useAccountModules, useModuleDetailsQuery, @@ -223,6 +224,11 @@ export const ModuleDetailsBody = ({ moduleData }: ModuleDetailsBodyProps) => { }} />
+ { viewFns={moduleData.viewFunctions} executeFns={moduleData.executeFunctions} /> + { tab={tableTabIndex} setTab={setTableTabIndex} /> + + diff --git a/src/lib/pages/modules/index.tsx b/src/lib/pages/modules/index.tsx index f0addd06f..85362ba3b 100644 --- a/src/lib/pages/modules/index.tsx +++ b/src/lib/pages/modules/index.tsx @@ -1,9 +1,9 @@ -import { Heading, Text } from "@chakra-ui/react"; import { useRouter } from "next/router"; import { useEffect } from "react"; import { AmpEvent, track } from "lib/amplitude"; import PageContainer from "lib/components/PageContainer"; +import { PageHeader } from "lib/components/PageHeader"; import { RecentModulesTable } from "./components/RecentModulesTable"; @@ -16,12 +16,11 @@ const RecentModules = () => { return ( - - Modules - - - These modules are the most recently published on this network - + ); diff --git a/src/lib/pages/nft-collection-details/index.tsx b/src/lib/pages/nft-collection-details/index.tsx index 2ac301758..7c70d671a 100644 --- a/src/lib/pages/nft-collection-details/index.tsx +++ b/src/lib/pages/nft-collection-details/index.tsx @@ -21,6 +21,7 @@ import { Loading } from "lib/components/Loading"; import PageContainer from "lib/components/PageContainer"; import { ErrorFetching, InvalidState } from "lib/components/state"; import { Tooltip } from "lib/components/Tooltip"; +import { UserDocsLink } from "lib/components/UserDocsLink"; import { useCollectionActivitiesCount, useCollectionByCollectionAddress, @@ -245,6 +246,11 @@ const CollectionDetailsBody = ({ onClickMutateEvents={handleTabChange(TabIndex.MutateEvents)} />
+ ( - - NFT Collections - - - These are the most recently NFT collections created on this network - + ); diff --git a/src/lib/pages/nft-details/index.tsx b/src/lib/pages/nft-details/index.tsx index 9391a9c5f..d18164238 100644 --- a/src/lib/pages/nft-details/index.tsx +++ b/src/lib/pages/nft-details/index.tsx @@ -22,6 +22,7 @@ import { Loading } from "lib/components/Loading"; import PageContainer from "lib/components/PageContainer"; import { ErrorFetching, InvalidState } from "lib/components/state"; import { Tooltip } from "lib/components/Tooltip"; +import { UserDocsLink } from "lib/components/UserDocsLink"; import { NFT_IMAGE_PLACEHOLDER } from "lib/data"; import { useCollectionByCollectionAddress, @@ -264,6 +265,11 @@ const NftDetailsBody = ({ +
); diff --git a/src/lib/pages/pools/components/pool-details/PoolAssets.tsx b/src/lib/pages/pools/components/pool-details/PoolAssets.tsx index 20e9893aa..eada0691b 100644 --- a/src/lib/pages/pools/components/pool-details/PoolAssets.tsx +++ b/src/lib/pages/pools/components/pool-details/PoolAssets.tsx @@ -69,7 +69,7 @@ export const PoolAssets = ({ pool }: PoolAssetsProps) => { > - Read more + View more diff --git a/src/lib/pages/pools/poolId.tsx b/src/lib/pages/pools/poolId.tsx index b6e425eaf..f458a9afd 100644 --- a/src/lib/pages/pools/poolId.tsx +++ b/src/lib/pages/pools/poolId.tsx @@ -35,7 +35,7 @@ export const PoolId = () => { diff --git a/src/lib/pages/proposal-details/index.tsx b/src/lib/pages/proposal-details/index.tsx index e4f14ce88..88daf8026 100644 --- a/src/lib/pages/proposal-details/index.tsx +++ b/src/lib/pages/proposal-details/index.tsx @@ -80,7 +80,7 @@ const ProposalDetailsBody = ({ id, tab }: ProposalDetailsQueryParams) => { /> @@ -93,7 +93,7 @@ const ProposalDetailsBody = ({ id, tab }: ProposalDetailsQueryParams) => { /> diff --git a/src/lib/pages/publish-module/publish.tsx b/src/lib/pages/publish-module/publish.tsx index 3f6541c4d..546d17228 100644 --- a/src/lib/pages/publish-module/publish.tsx +++ b/src/lib/pages/publish-module/publish.tsx @@ -19,6 +19,7 @@ import { ErrorMessageRender } from "lib/components/ErrorMessageRender"; import { EstimatedFeeRender } from "lib/components/EstimatedFeeRender"; import { CustomIcon } from "lib/components/icon"; import PageContainer from "lib/components/PageContainer"; +import { UserDocsLink } from "lib/components/UserDocsLink"; import { useTxBroadcast } from "lib/providers/tx-broadcast"; import type { DecodeModuleQueryResponse } from "lib/services/move/moduleService"; import type { Option } from "lib/types"; @@ -223,6 +224,9 @@ export const PublishModule = ({ {publishModuleText.description} + + + + + + @@ -324,7 +335,6 @@ export const PublishModule = ({ const republishModules = modules.filter((ampTrackRepublish) => ampTrackRepublish.publishStatus.text.includes("republish") ); - track(AmpEvent.ACTION_MOVE_PUBLISH, { numberOfModule: modules.length, numberOfRepublishModules: republishModules.length, diff --git a/src/lib/pages/saved-accounts/index.tsx b/src/lib/pages/saved-accounts/index.tsx index 70441827e..5f3419ff9 100644 --- a/src/lib/pages/saved-accounts/index.tsx +++ b/src/lib/pages/saved-accounts/index.tsx @@ -94,8 +94,8 @@ const SavedAccounts = observer(() => { )} ); diff --git a/src/lib/pages/saved-codes/index.tsx b/src/lib/pages/saved-codes/index.tsx index 01bc4d743..df7aad996 100644 --- a/src/lib/pages/saved-codes/index.tsx +++ b/src/lib/pages/saved-codes/index.tsx @@ -102,7 +102,7 @@ const SavedCodes = observer(() => { /> From 7ecc599e282e797225106cb6579c79b10d8ae0f0 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Mon, 1 Apr 2024 17:38:56 +0700 Subject: [PATCH 416/531] fix(components): fix pr comments --- CHANGELOG.md | 2 +- .../components/bonded-token-changes/VotingPowerChart.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc00abf0a..8bfc30ef3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features -- [#859](https://github.com/alleslabs/celatone-frontend/pull/859) Fix voting power chart display data - [#857](https://github.com/alleslabs/celatone-frontend/pull/857) Migrate osmosis-1 graphql - [#854](https://github.com/alleslabs/celatone-frontend/pull/854) Create PageHeaderContainer component - [#851](https://github.com/alleslabs/celatone-frontend/pull/851) Add amp validator list page @@ -123,6 +122,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Bug fixes +- [#859](https://github.com/alleslabs/celatone-frontend/pull/859) Fix voting power chart display data - [#852](https://github.com/alleslabs/celatone-frontend/pull/852) Show quorum only during the voting period since past total voting power is not available - [#849](https://github.com/alleslabs/celatone-frontend/pull/849) Fix validator list empty state and voting percent dividers - [#846](https://github.com/alleslabs/celatone-frontend/pull/846) Fix voting period status badge diff --git a/src/lib/pages/validator-details/components/bonded-token-changes/VotingPowerChart.tsx b/src/lib/pages/validator-details/components/bonded-token-changes/VotingPowerChart.tsx index ba34861bb..d2c396e52 100644 --- a/src/lib/pages/validator-details/components/bonded-token-changes/VotingPowerChart.tsx +++ b/src/lib/pages/validator-details/components/bonded-token-changes/VotingPowerChart.tsx @@ -44,6 +44,10 @@ export const VotingPowerChart = ({ ? assetInfos?.[singleStakingDenom] : undefined; + const currency = singleStakingDenom + ? `${getTokenLabel(singleStakingDenom, assetInfo?.symbol)}` + : ""; + const labels = historicalPowers.items.map((item) => formatHHmm(item.hourRoundedTimestamp as Date) ); @@ -68,10 +72,6 @@ export const VotingPowerChart = ({ const customizeTooltip = (tooltip: TooltipModel<"line">) => { const { raw, dataIndex } = tooltip.dataPoints[0]; - const currency = singleStakingDenom - ? `${getTokenLabel(singleStakingDenom, assetInfo?.symbol)}` - : ""; - const formattedAmount = formatUTokenWithPrecision( raw as U>, assetInfo?.precision ?? 0, From 6c480cc21314f1ffdfa32339a413fdd354cdda2d Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Mon, 1 Apr 2024 17:45:27 +0700 Subject: [PATCH 417/531] fix: div with default --- .../components/deposit-bar/ProgressBar.tsx | 4 ++-- .../validators-table/ValidatorsTableMobileCard.tsx | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/lib/pages/proposal-details/components/deposit-bar/ProgressBar.tsx b/src/lib/pages/proposal-details/components/deposit-bar/ProgressBar.tsx index 2660a0a28..60dabe857 100644 --- a/src/lib/pages/proposal-details/components/deposit-bar/ProgressBar.tsx +++ b/src/lib/pages/proposal-details/components/deposit-bar/ProgressBar.tsx @@ -2,7 +2,7 @@ import { Box, Flex, Text } from "@chakra-ui/react"; import type Big from "big.js"; import type { Ratio } from "lib/types"; -import { formatPrettyPercent } from "lib/utils"; +import { divWithDefault, formatPrettyPercent } from "lib/utils"; interface ProgressBarProps { value: Big; @@ -11,7 +11,7 @@ interface ProgressBarProps { } export const ProgressBar = ({ value, max, isCompact }: ProgressBarProps) => { - const ratio = value.div(max).toNumber() as Ratio; + const ratio = divWithDefault(value, max, 0).toNumber() as Ratio; const percent = formatPrettyPercent(ratio); return ( diff --git a/src/lib/pages/validators/components/validators-table/ValidatorsTableMobileCard.tsx b/src/lib/pages/validators/components/validators-table/ValidatorsTableMobileCard.tsx index 05dd15aa8..e05227f2a 100644 --- a/src/lib/pages/validators/components/validators-table/ValidatorsTableMobileCard.tsx +++ b/src/lib/pages/validators/components/validators-table/ValidatorsTableMobileCard.tsx @@ -13,6 +13,7 @@ import type { ValidatorData, } from "lib/types"; import { + divWithDefault, formatPrettyPercent, formatUTokenWithPrecision, getTokenLabel, @@ -77,9 +78,11 @@ export const ValidatorsTableMobileCard = ({ {formatPrettyPercent( - validator.votingPower - .div(totalVotingPower) - .toNumber() as Ratio, + divWithDefault( + validator.votingPower, + totalVotingPower, + 0 + ).toNumber() as Ratio, 2, true )} From d49e0a903d1b241b269b82548f2fffe6e4f557c9 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Mon, 1 Apr 2024 18:04:33 +0700 Subject: [PATCH 418/531] fix: comment --- src/lib/pages/proposal-details/components/ViewFailedReason.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/pages/proposal-details/components/ViewFailedReason.tsx b/src/lib/pages/proposal-details/components/ViewFailedReason.tsx index 162467e1b..88ba2028f 100644 --- a/src/lib/pages/proposal-details/components/ViewFailedReason.tsx +++ b/src/lib/pages/proposal-details/components/ViewFailedReason.tsx @@ -28,6 +28,7 @@ export const ViewFailedReason = ({ text }: ViewFailedReasonProps) => { variant="body2" color="text.disabled" cursor="not-allowed" + whiteSpace="nowrap" > View Failed Reason @@ -55,7 +56,7 @@ export const ViewFailedReason = ({ text }: ViewFailedReasonProps) => { returnFocusOnClose={false} > - + Failed Reason From 521ec7d33c1f36aec196bcfadfd7e67d0d898e8f Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Mon, 1 Apr 2024 18:42:32 +0700 Subject: [PATCH 419/531] fix: zod ratio --- src/lib/components/Expedited.tsx | 13 +++++-------- .../components/ResultExplanation.tsx | 5 ++--- .../components/VoteQuorumCircle.tsx | 4 ++-- .../proposal-details/components/VoteQuorumText.tsx | 4 ++-- .../__stories__/StatusSummary.stories.ts | 8 ++++---- .../VotingOverviewThreshold.tsx | 7 ++----- .../components/validator-top/ValidatorStats.tsx | 4 ++-- .../validators-table/ValidatorsTableMobileCard.tsx | 6 +----- .../validators-table/ValidatorsTableRow.tsx | 6 +----- src/lib/services/proposal.ts | 11 ++++++----- src/lib/types/converter.ts | 4 ++-- src/lib/types/currency/token.ts | 5 ++++- src/lib/types/proposal.ts | 11 ++++++----- src/lib/types/validator.ts | 3 ++- 14 files changed, 41 insertions(+), 50 deletions(-) diff --git a/src/lib/components/Expedited.tsx b/src/lib/components/Expedited.tsx index 56bec373f..d4050b89a 100644 --- a/src/lib/components/Expedited.tsx +++ b/src/lib/components/Expedited.tsx @@ -13,8 +13,8 @@ const ExpeditedText = ({ votingPeriod, isLoading, }: { - quorum: Option; - threshold: Option; + quorum: Option>; + threshold: Option>; votingPeriod: Option; isLoading: boolean; }) => { @@ -31,13 +31,10 @@ const ExpeditedText = ({ An expedited governance proposal is required to{" "} - pass a quorum of{" "} - {quorum ? formatPrettyPercent(quorum as Ratio, 1, true) : "N/A"}{" "} + pass a quorum of {quorum ? formatPrettyPercent(quorum, 1, true) : "N/A"}{" "} and a high threshold of{" "} - {threshold - ? formatPrettyPercent(threshold as Ratio, 1, true) - : "N/A"}{" "} - within {formatSeconds(votingPeriod)} voting period + {threshold ? formatPrettyPercent(threshold, 1, true) : "N/A"} within{" "} + {formatSeconds(votingPeriod)} voting period {" "} in order to pass. diff --git a/src/lib/pages/proposal-details/components/ResultExplanation.tsx b/src/lib/pages/proposal-details/components/ResultExplanation.tsx index 35c1ea32b..dd32e8601 100644 --- a/src/lib/pages/proposal-details/components/ResultExplanation.tsx +++ b/src/lib/pages/proposal-details/components/ResultExplanation.tsx @@ -11,7 +11,6 @@ import type { ProposalData, ProposalParams, ProposalVotesInfo, - Ratio, Token, TokenWithValue, U, @@ -141,7 +140,7 @@ export const ResultExplanation = ({ fontWeight: 700, }} > - {formatPrettyPercent(vetoThreshold as Ratio)} threshold + {formatPrettyPercent(vetoThreshold)} threshold . If the proposal concludes with this voting outcome, it will be rejected regardless of “Yes” votes. @@ -210,7 +209,7 @@ export const ResultExplanation = ({ fontWeight: 700, }} > - {formatPrettyPercent(vetoThreshold as Ratio)} threshold + {formatPrettyPercent(vetoThreshold)} threshold . diff --git a/src/lib/pages/proposal-details/components/VoteQuorumCircle.tsx b/src/lib/pages/proposal-details/components/VoteQuorumCircle.tsx index 7084ecf6b..3f4788fb7 100644 --- a/src/lib/pages/proposal-details/components/VoteQuorumCircle.tsx +++ b/src/lib/pages/proposal-details/components/VoteQuorumCircle.tsx @@ -4,7 +4,7 @@ import type { Ratio } from "lib/types"; import { formatPrettyPercent } from "lib/utils"; interface VoteQuorumCircleProps { - quorum: number; + quorum: Ratio; nonAbstainVotes: Ratio; totalVotes: Ratio; isCompact: boolean; @@ -24,7 +24,7 @@ export const VoteQuorumCircle = ({ const totalVotesPercent = formatPrettyPercent(totalVotes, 1); const quorumAngle = quorum * 360; - const quorumPercent = formatPrettyPercent(quorum as Ratio); + const quorumPercent = formatPrettyPercent(quorum); return ( ; totalVotes: Ratio; isCompact: boolean; } @@ -29,7 +29,7 @@ export const VoteQuorumText = ({ isCompact, }: VoteQuorumTextProps) => { const fontVariant = isCompact ? "body2" : "body1"; - const quorumPercent = formatPrettyPercent(quorum as Ratio); + const quorumPercent = formatPrettyPercent(quorum); const isPassingQuorum = totalVotes >= quorum; if (status === ProposalStatus.VOTING_PERIOD) diff --git a/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts b/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts index c587bcb62..754951750 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts +++ b/src/lib/pages/proposal-details/components/proposal-overview/__stories__/StatusSummary.stories.ts @@ -4,7 +4,7 @@ import dayjs from "dayjs"; import { StatusSummary } from "../status-summary"; import { big, ProposalStatus } from "lib/types"; -import type { ProposalData, ProposalParams, Token, U } from "lib/types"; +import type { ProposalData, ProposalParams, Ratio, Token, U } from "lib/types"; const meta: Meta = { component: StatusSummary, @@ -67,9 +67,9 @@ const params: ProposalParams = { minInitialDepositRatio: 0.2, maxDepositPeriod: "", votingPeriod: "", - vetoThreshold: 0.3, - quorum: 0.3, - threshold: 0.5, + vetoThreshold: 0.3 as Ratio, + quorum: 0.3 as Ratio, + threshold: 0.5 as Ratio, }; export const DepositPeriod: Story = { diff --git a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx index 7845c9b4a..63f2e295a 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/proposal-period-overview/VotingOverviewThreshold.tsx @@ -15,7 +15,6 @@ import type { ProposalData, ProposalParams, ProposalVotesInfo, - Ratio, } from "lib/types"; import { formatPrettyPercent } from "lib/utils"; @@ -122,8 +121,7 @@ export const VotingOverviewThreshold = ({ fontWeight: 700, }} > - {formatPrettyPercent(vetoThreshold as Ratio)}{" "} - threshold + {formatPrettyPercent(vetoThreshold)} threshold . If the proposal concludes with this voting outcome, it will be regardless of “Yes” votes. @@ -146,8 +144,7 @@ export const VotingOverviewThreshold = ({ fontWeight: 700, }} > - {formatPrettyPercent(vetoThreshold as Ratio)}{" "} - threshold + {formatPrettyPercent(vetoThreshold)} threshold , the proposal is rejected regardless of “Yes” votes. diff --git a/src/lib/pages/validator-details/components/validator-top/ValidatorStats.tsx b/src/lib/pages/validator-details/components/validator-top/ValidatorStats.tsx index 54bcd0ef2..90d8d6d03 100644 --- a/src/lib/pages/validator-details/components/validator-top/ValidatorStats.tsx +++ b/src/lib/pages/validator-details/components/validator-top/ValidatorStats.tsx @@ -37,7 +37,7 @@ const StatWithLabel = ({ interface ValidatorStatsProps { validatorAddress: ValidatorAddr; - commissionRate: number; + commissionRate: Ratio; totalVotingPower: Big; singleStakingDenom: Option; } @@ -83,7 +83,7 @@ export const ValidatorStats = ({ > , 2, true)} + value={formatPrettyPercent(commissionRate, 2, true)} isLoading={false} /> {singleStakingDenom && ( diff --git a/src/lib/pages/validators/components/validators-table/ValidatorsTableMobileCard.tsx b/src/lib/pages/validators/components/validators-table/ValidatorsTableMobileCard.tsx index e05227f2a..ad0eefc89 100644 --- a/src/lib/pages/validators/components/validators-table/ValidatorsTableMobileCard.tsx +++ b/src/lib/pages/validators/components/validators-table/ValidatorsTableMobileCard.tsx @@ -123,11 +123,7 @@ export const ValidatorsTableMobileCard = ({ color={isMinCommissionRate ? "success.main" : "text.main"} fontWeight={isMinCommissionRate ? 700 : undefined} > - {formatPrettyPercent( - validator.commissionRate as Ratio, - 2, - true - )} + {formatPrettyPercent(validator.commissionRate, 2, true)} diff --git a/src/lib/pages/validators/components/validators-table/ValidatorsTableRow.tsx b/src/lib/pages/validators/components/validators-table/ValidatorsTableRow.tsx index 9842cdc5b..915faa6cc 100644 --- a/src/lib/pages/validators/components/validators-table/ValidatorsTableRow.tsx +++ b/src/lib/pages/validators/components/validators-table/ValidatorsTableRow.tsx @@ -118,11 +118,7 @@ export const ValidatorsTableRow = ({ color={isMinCommissionRate ? "success.main" : "text.main"} fontWeight={isMinCommissionRate ? 700 : undefined} > - {formatPrettyPercent( - validator.commissionRate as Ratio, - 2, - true - )} + {formatPrettyPercent(validator.commissionRate, 2, true)} diff --git a/src/lib/services/proposal.ts b/src/lib/services/proposal.ts index 65e50dcd3..88bd686d2 100644 --- a/src/lib/services/proposal.ts +++ b/src/lib/services/proposal.ts @@ -8,6 +8,7 @@ import { zCoin, zProposalStatus, zProposalType, + zRatio, zUtcDate, zValidator, } from "lib/types"; @@ -86,14 +87,14 @@ const zProposalParamsResponse = z min_initial_deposit_ratio: z.coerce.number(), max_deposit_period: z.string(), voting_period: z.string(), - veto_threshold: z.coerce.number(), - quorum: z.coerce.number(), - threshold: z.coerce.number(), + veto_threshold: zRatio(z.coerce.number()), + quorum: zRatio(z.coerce.number()), + threshold: zRatio(z.coerce.number()), // expedited expedited_voting_period: z.string().optional(), - expedited_threshold: z.coerce.number().optional(), + expedited_threshold: zRatio(z.coerce.number()).optional(), expedited_min_deposit: zCoin.array().optional(), - expedited_quorum: z.coerce.number().optional(), // only in sei + expedited_quorum: zRatio(z.coerce.number()).optional(), // only in sei // emergency - only in initia emergency_min_deposit: zCoin.array().optional(), emergency_tally_interval: z.string().optional(), diff --git a/src/lib/types/converter.ts b/src/lib/types/converter.ts index ab0c1c562..80d12ca4c 100644 --- a/src/lib/types/converter.ts +++ b/src/lib/types/converter.ts @@ -8,7 +8,7 @@ export type SnakeToCamelCaseNested = T extends (...args: any[]) => any ? T : T extends Array ? Array> - : T extends string + : T extends string | number ? T : T extends Date ? T @@ -31,7 +31,7 @@ export type CamelToSnakeCaseNested = T extends (...args: any[]) => any ? T : T extends Array ? Array> - : T extends string + : T extends string | number ? T : T extends Date ? T diff --git a/src/lib/types/currency/token.ts b/src/lib/types/currency/token.ts index 73c69e271..e771c6584 100644 --- a/src/lib/types/currency/token.ts +++ b/src/lib/types/currency/token.ts @@ -1,3 +1,5 @@ +import type { z } from "zod"; + import type { NominalType } from "../common"; export type U = T & { __micro: true }; @@ -11,7 +13,8 @@ export type Token = T & NominalType; export type USD = T & NominalType<"usd">; // Percentage -export type Ratio = T & NominalType<"ratio">; +export const zRatio = (zType: T) => zType.brand("ratio"); +export type Ratio = T & z.BRAND<"ratio">; export type Percent = T & NominalType<"percent">; diff --git a/src/lib/types/proposal.ts b/src/lib/types/proposal.ts index 42f929423..65e5560ac 100644 --- a/src/lib/types/proposal.ts +++ b/src/lib/types/proposal.ts @@ -6,6 +6,7 @@ import type { BechAddr, Nullable, Option, + Ratio, TokenWithValue, Validator, } from "lib/types"; @@ -84,14 +85,14 @@ export interface ProposalParams< minInitialDepositRatio: number; maxDepositPeriod: string; votingPeriod: string; - vetoThreshold: number; - quorum: number; - threshold: number; + vetoThreshold: Ratio; + quorum: Ratio; + threshold: Ratio; // expedited expeditedVotingPeriod?: string; - expeditedThreshold?: number; + expeditedThreshold?: Ratio; expeditedMinDeposit?: T[]; - expeditedQuorum?: number; // only in sei + expeditedQuorum?: Ratio; // only in sei // emergency - only in initia emergencyMinDeposit?: T[]; emergencyTallyInterval?: string; diff --git a/src/lib/types/validator.ts b/src/lib/types/validator.ts index 241cfd008..a6e7df7bf 100644 --- a/src/lib/types/validator.ts +++ b/src/lib/types/validator.ts @@ -5,6 +5,7 @@ import { formatUrl } from "lib/utils/formatter/url"; import { zBechAddr20, zValidatorAddr } from "./addrs"; import { zBig } from "./big"; +import { zRatio } from "./currency"; import type { Ratio } from "./currency"; export const zValidator = z @@ -29,7 +30,7 @@ export const zValidatorData = z identity: z.string(), moniker: z.string(), details: z.string(), - commission_rate: z.coerce.number(), + commission_rate: zRatio(z.coerce.number()), is_jailed: z.boolean(), is_active: z.boolean(), voting_power: zBig, From 3584f16904a5900e9d6943374223312d3df7ce24 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 2 Apr 2024 10:29:29 +0700 Subject: [PATCH 420/531] fix: change type --- src/lib/types/currency/token.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/types/currency/token.ts b/src/lib/types/currency/token.ts index e771c6584..02aa3d3a9 100644 --- a/src/lib/types/currency/token.ts +++ b/src/lib/types/currency/token.ts @@ -13,7 +13,8 @@ export type Token = T & NominalType; export type USD = T & NominalType<"usd">; // Percentage -export const zRatio = (zType: T) => zType.brand("ratio"); +export const zRatio = (zType: T) => + zType.brand("ratio"); export type Ratio = T & z.BRAND<"ratio">; export type Percent = T & NominalType<"percent">; From c13813284ae0c4d7046cdb3cc7ff901888869819 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Tue, 2 Apr 2024 10:34:50 +0700 Subject: [PATCH 421/531] feat(components): add filter and search input --- .../tables/voted-proposals/index.tsx | 115 ++++++++++++++---- 1 file changed, 89 insertions(+), 26 deletions(-) diff --git a/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx b/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx index 56aedc29b..210b5cda0 100644 --- a/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx +++ b/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx @@ -1,8 +1,9 @@ import { Alert, Flex, Grid, GridItem, Text } from "@chakra-ui/react"; import type { ChangeEvent } from "react"; -import { useState } from "react"; +import { useMemo, useState } from "react"; import { useMobile } from "lib/app-provider"; +import { SelectInput } from "lib/components/forms"; import { CustomIcon } from "lib/components/icon"; import InputWithIcon from "lib/components/InputWithIcon"; import { Pagination } from "lib/components/pagination"; @@ -10,6 +11,7 @@ import { usePaginator } from "lib/components/pagination/usePaginator"; import { TableTitle, ViewMore } from "lib/components/table"; import { useDebounce } from "lib/hooks"; import { useValidatorVotedProposals } from "lib/services/validatorService"; +import { ProposalValidatorVoteType } from "lib/types"; import type { ValidatorAddr } from "lib/types"; import { VotedProposalsTableBody } from "./VotedProposalsTableBody"; @@ -27,6 +29,10 @@ export const VotedProposalsTable = ({ }: VotedProposalsTableProps) => { const isMobile = useMobile(); const isMobileOverview = isMobile && !!onViewMore; + + const [answerFilter, setAnswerFilter] = useState( + ProposalValidatorVoteType.ALL + ); const [search, setSearch] = useState(""); const debouncedSearch = useDebounce(search); @@ -53,16 +59,61 @@ export const VotedProposalsTable = ({ { onSuccess: ({ total }) => setTotalData(total), }, - // answerFilter, - undefined, + answerFilter, debouncedSearch ); + const answerOptions = useMemo( + () => [ + { + label: `All votes`, + value: ProposalValidatorVoteType.ALL, + disabled: false, + }, + { + label: `Yes`, + value: ProposalValidatorVoteType.YES, + disabled: false, + }, + { + label: `No`, + value: ProposalValidatorVoteType.NO, + disabled: false, + }, + { + label: `No with veto`, + value: ProposalValidatorVoteType.NO_WITH_VETO, + disabled: false, + }, + { + label: `Abstain`, + value: ProposalValidatorVoteType.ABSTAIN, + disabled: false, + }, + { + label: `Weighted`, + value: ProposalValidatorVoteType.WEIGHTED, + disabled: false, + }, + { + label: `Did not vote`, + value: ProposalValidatorVoteType.DID_NOT_VOTE, + disabled: false, + }, + ], + [] + ); + const handleOnSearchChange = (e: ChangeEvent) => { setCurrentPage(1); setSearch(e.target.value); }; + const handleOnAnswerFilterChange = (newAnswer: ProposalValidatorVoteType) => { + setCurrentPage(1); + setAnswerFilter(newAnswer); + }; + return ( {isMobileOverview ? ( @@ -82,30 +133,42 @@ export const VotedProposalsTable = ({ <> {!onViewMore && ( - - - - Kindly note that the validator may not have voted on the - proposal due to ineligibility, such as being recently added to - the network. - - + <> + + + + Kindly note that the validator may not have voted on the + proposal due to ineligibility, such as being recently added to + the network. + + + + + + formLabel="Filter by vote answer" + options={answerOptions} + onChange={handleOnAnswerFilterChange} + labelBgColor="gray.900" + initialSelected={answerFilter} + popoverBgColor="gray.800" + disableMaxH + /> + + + + + + )} - - {/* // TODO: Add filter here... */} - - - - Date: Tue, 2 Apr 2024 11:19:37 +0700 Subject: [PATCH 422/531] fix: div default --- .../components/validators-table/ValidatorsTableRow.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib/pages/validators/components/validators-table/ValidatorsTableRow.tsx b/src/lib/pages/validators/components/validators-table/ValidatorsTableRow.tsx index 915faa6cc..0a475b7c1 100644 --- a/src/lib/pages/validators/components/validators-table/ValidatorsTableRow.tsx +++ b/src/lib/pages/validators/components/validators-table/ValidatorsTableRow.tsx @@ -15,6 +15,7 @@ import type { ValidatorData, } from "lib/types"; import { + divWithDefault, formatPrettyPercent, formatUTokenWithPrecision, getTokenLabel, @@ -77,9 +78,11 @@ export const ValidatorsTableRow = ({
{formatPrettyPercent( - validator.votingPower - .div(totalVotingPower) - .toNumber() as Ratio, + divWithDefault( + validator.votingPower, + totalVotingPower, + 0 + ).toNumber() as Ratio, 2, true )} From 886b842b9c06ef768338706eba0f63a184a9568a Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Tue, 2 Apr 2024 14:05:11 +0700 Subject: [PATCH 423/531] feat(components): move filter and search to only show on voted section --- .../tables/voted-proposals/index.tsx | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx b/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx index a5d22159a..51eadf5ec 100644 --- a/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx +++ b/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx @@ -128,35 +128,37 @@ export const VotedProposalsTable = ({ {!onViewMore && ( - - - - Kindly note that the validator may not have voted on the proposal - due to ineligibility, such as being recently added to the network. - - + <> + + + + Kindly note that the validator may not have voted on the proposal + due to ineligibility, such as being recently added to the network. + + + + + + formLabel="Filter by vote answer" + options={answerOptions} + onChange={handleOnAnswerFilterChange} + labelBgColor="gray.900" + initialSelected={answerFilter} + popoverBgColor="gray.800" + disableMaxH + /> + + + + + + )} - - - - formLabel="Filter by vote answer" - options={answerOptions} - onChange={handleOnAnswerFilterChange} - labelBgColor="gray.900" - initialSelected={answerFilter} - popoverBgColor="gray.800" - disableMaxH - /> - - - - - Date: Tue, 2 Apr 2024 14:06:25 +0700 Subject: [PATCH 424/531] docs: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e3577f40..43480b191 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#860](https://github.com/alleslabs/celatone-frontend/pull/860) Add voted proposals in voted tab - [#853](https://github.com/alleslabs/celatone-frontend/pull/853) Add voted proposals in overview - [#847](https://github.com/alleslabs/celatone-frontend/pull/847) Add amp proposal details page - [#857](https://github.com/alleslabs/celatone-frontend/pull/857) Migrate osmosis-1 graphql From fc20af4f321f681e836bbb4cdb08fb194f6e56fc Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Tue, 2 Apr 2024 14:16:46 +0700 Subject: [PATCH 425/531] feat(components): fix pr comment --- .../components/tables/voted-proposals/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx b/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx index 51eadf5ec..f568c8dc1 100644 --- a/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx +++ b/src/lib/pages/validator-details/components/tables/voted-proposals/index.tsx @@ -142,7 +142,7 @@ export const VotedProposalsTable = ({ formLabel="Filter by vote answer" options={answerOptions} onChange={handleOnAnswerFilterChange} - labelBgColor="gray.900" + labelBgColor="background.main" initialSelected={answerFilter} popoverBgColor="gray.800" disableMaxH From 2fb14e12e51860cf806c063b3d1181df6dad505a Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:24:09 +0700 Subject: [PATCH 426/531] fix: comment --- .../json-schema/form/templates/BaseInputTemplate.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib/components/json-schema/form/templates/BaseInputTemplate.tsx b/src/lib/components/json-schema/form/templates/BaseInputTemplate.tsx index 749cbb012..4393de420 100644 --- a/src/lib/components/json-schema/form/templates/BaseInputTemplate.tsx +++ b/src/lib/components/json-schema/form/templates/BaseInputTemplate.tsx @@ -122,6 +122,7 @@ export default function BaseInputTemplate< type, hideLabel, // remove this from ...rest hideError, // remove this from ...rest + placeholder, ...rest } = props; const DescriptionFieldTemplate = getTemplate< @@ -156,8 +157,8 @@ export default function BaseInputTemplate< const handleOnChange = useCallback( ({ target }: ChangeEvent) => - onChange(value === "" ? options.emptyValue : target.value), - [onChange, options.emptyValue, value] + onChange(target.value === "" ? options.emptyValue : target.value), + [onChange, options.emptyValue] ); const handleOnBlur = useCallback( ({ target }: FocusEvent) => onBlur(id, target.value), @@ -209,6 +210,7 @@ export default function BaseInputTemplate< value={inputValue} autoFocus={autofocus} placeholder={ + placeholder || getBaseInputPlaceholder( value, readonly ?? false, @@ -238,9 +240,8 @@ export default function BaseInputTemplate< /> {/* {rightAddon && {rightAddon}} */} - {isStringType && ( + {!readonly && isStringType && ( { From bcaf3df9c8ff655668605f67014d286df1263a4e Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:25:26 +0700 Subject: [PATCH 427/531] fix: turn off validate --- src/lib/components/json-schema/form/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/components/json-schema/form/index.tsx b/src/lib/components/json-schema/form/index.tsx index c26078301..ee807d350 100644 --- a/src/lib/components/json-schema/form/index.tsx +++ b/src/lib/components/json-schema/form/index.tsx @@ -114,6 +114,7 @@ export const JsonSchemaForm: FC = ({ }} validator={v8Validator} liveValidate={!schema.readOnly} + noValidate showErrorList={false} onChange={({ formData: values, errors }) => { // log.info(values) From c725c066b96d30e1f7dfa56dedf30acfab60f9c2 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:28:25 +0700 Subject: [PATCH 428/531] fix: comment log --- src/lib/components/json-schema/form/index.tsx | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/lib/components/json-schema/form/index.tsx b/src/lib/components/json-schema/form/index.tsx index ee807d350..ac61fae41 100644 --- a/src/lib/components/json-schema/form/index.tsx +++ b/src/lib/components/json-schema/form/index.tsx @@ -13,7 +13,7 @@ import type { RJSFSchema, RJSFValidationError } from "@rjsf/utils"; import { customizeValidator } from "@rjsf/validator-ajv8"; import { isUndefined } from "lodash"; import type { FC } from "react"; -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import type { JsonDataType } from "lib/types"; @@ -64,19 +64,6 @@ export const JsonSchemaForm: FC = ({ }) => { const [formData, setFormData] = useState(initialFormData); - const onSubmit = (values: Record) => { - console.log("onSubmit", values); - propsOnSubmit?.(values); - }; - - const onChange = useCallback( - (data: JsonDataType, errors: RJSFValidationError[]) => { - setFormData(data); - propsOnChange?.(data, errors); - }, - [formData, propsOnChange] - ); - useEffect(() => { setFormData(initialFormData); @@ -117,14 +104,14 @@ export const JsonSchemaForm: FC = ({ noValidate showErrorList={false} onChange={({ formData: values, errors }) => { - // log.info(values) - onChange?.(values, errors); + setFormData(values); + propsOnChange?.(values, errors); }} onSubmit={({ formData: values }) => { - // log.info(values) - onSubmit(values); + // console.log("onSubmit", values); + propsOnSubmit?.(values); }} - onError={() => console.error("errors")} + // onError={() => console.error("errors")} experimental_defaultFormStateBehavior={{ // Assign value to formData when only default is set emptyObjectFields: "skipEmptyDefaults", From c372dd80e74c1d314b3ee576932492dc2613a81d Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:48:01 +0700 Subject: [PATCH 429/531] fix: eslint --- .../components/json-schema/form/templates/BaseInputTemplate.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/components/json-schema/form/templates/BaseInputTemplate.tsx b/src/lib/components/json-schema/form/templates/BaseInputTemplate.tsx index 4393de420..58d848c6e 100644 --- a/src/lib/components/json-schema/form/templates/BaseInputTemplate.tsx +++ b/src/lib/components/json-schema/form/templates/BaseInputTemplate.tsx @@ -1,6 +1,4 @@ /* eslint-disable complexity */ -/* eslint-disable sonarjs/cognitive-complexity */ -/* eslint-disable react/destructuring-assignment */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Box, From 655fdd43f2a5328215bb1a1fb38e2763a8938947 Mon Sep 17 00:00:00 2001 From: Poafs1 Date: Tue, 2 Apr 2024 15:56:57 +0700 Subject: [PATCH 430/531] feat(components): update website button if href none will show tooltip --- .../validator-top/WebsiteButton.tsx | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/lib/pages/validator-details/components/validator-top/WebsiteButton.tsx b/src/lib/pages/validator-details/components/validator-top/WebsiteButton.tsx index 93d50bfc7..259f0ba8a 100644 --- a/src/lib/pages/validator-details/components/validator-top/WebsiteButton.tsx +++ b/src/lib/pages/validator-details/components/validator-top/WebsiteButton.tsx @@ -2,23 +2,33 @@ import { Button, Link } from "@chakra-ui/react"; import type { ButtonProps } from "@chakra-ui/react"; import { CustomIcon } from "lib/components/icon"; +import { Tooltip } from "lib/components/Tooltip"; interface WebsiteButtonProps extends ButtonProps { href: string; } +const RenderWebsiteButton = ({ href, ...props }: WebsiteButtonProps) => ( + +); + export const WebsiteButton = ({ href, ...props }: WebsiteButtonProps) => - href && ( + href ? ( - + + ) : ( + + + ); From 4364d7c4ccb36127f7b118f294bfd3f40b58ee26 Mon Sep 17 00:00:00 2001 From: Jennie Alles Date: Tue, 2 Apr 2024 16:11:46 +0700 Subject: [PATCH 431/531] feat(components): add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fff2f0e52..1793103cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,6 +94,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#863](https://github.com/alleslabs/celatone-frontend/pull/863) Add link to user document (move) - [#843](https://github.com/alleslabs/celatone-frontend/pull/843) Add link to user document - [#845](https://github.com/alleslabs/celatone-frontend/pull/845) Edit error fetching message on the contract state - [#844](https://github.com/alleslabs/celatone-frontend/pull/844) Modify wording status for rejected proposals From 08bee915602d7e4b0cde23f4a3b80a0805d8a65f Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:44:55 +0700 Subject: [PATCH 432/531] fix: voting countdown text --- CHANGELOG.md | 1 + .../components/proposal-overview/status-summary/Countdown.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c5447fa0..c48321bb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -127,6 +127,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Bug fixes +- [#864](https://github.com/alleslabs/celatone-frontend/pull/864) Fix voting countdown text - [#859](https://github.com/alleslabs/celatone-frontend/pull/859) Fix voting power chart display data - [#858](https://github.com/alleslabs/celatone-frontend/pull/858) Handle neutron and minitia validator links - [#852](https://github.com/alleslabs/celatone-frontend/pull/852) Show quorum only during the voting period since past total voting power is not available diff --git a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx index aea88a389..b6805b650 100644 --- a/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx +++ b/src/lib/pages/proposal-details/components/proposal-overview/status-summary/Countdown.tsx @@ -35,7 +35,7 @@ export const Countdown = ({ endTime, isString }: CountdownProps) => { const days = duration.days(); const timestamp = isString ? ( `${ - days > 0 && `${days.toString()} ${plur("day", days)} ` + days > 0 ? `${days.toString()} ${plur("day", days)} ` : "" }${duration.hours()}:${formatNumber(duration.minutes())}:${formatNumber(duration.seconds())}` ) : ( <> From b5f2bba58df3ded47d4c59388dd1faeb10e05f59 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:58:54 +0700 Subject: [PATCH 433/531] fix: input switch tooltip --- src/lib/components/json-schema/MessageInputSwitch.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/json-schema/MessageInputSwitch.tsx b/src/lib/components/json-schema/MessageInputSwitch.tsx index be9089a8b..dfefc65cb 100644 --- a/src/lib/components/json-schema/MessageInputSwitch.tsx +++ b/src/lib/components/json-schema/MessageInputSwitch.tsx @@ -59,7 +59,7 @@ export const MessageInputSwitch = < * @todos current implementation of sliding box dimensions and position is hardcoded due to issues with ref, improve this later */ return ( - +