Skip to content

Commit

Permalink
fix: update proposal metadata display [web-desmos] (#1326)
Browse files Browse the repository at this point in the history
## Description

Closes: #XXXX
[BDU-1179](https://forbole.atlassian.net/browse/BDU-1179)

Changes:
- [desmos, osmosis, persistence ] Display metadata content on proposal
details page
- [persistence] Fix params page display

<!-- Add a description of the changes that this PR introduces and the
files that
are the most critical to review. -->

---

### Author Checklist

_All items are required. Please add a note to the item if the item is
not applicable and
please add links to any relevant follow up issues._

I have...

- [x] ran linting via `yarn lint`
- [x] wrote tests where necessary
- [x] included the correct [type
prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json)
in the PR title
- [x] targeted the correct branch
- [x] provided a link to the relevant issue or specification
- [x] reviewed "Files changed" and left comments if necessary
- [x] confirmed all CI checks have passed
- [x] added a changeset via [`yarn && yarn
changeset`](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md)


[BDU-1179]:
https://forbole.atlassian.net/browse/BDU-1179?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
  • Loading branch information
MonikaCat authored Feb 9, 2024
1 parent 9dedd5e commit 6bcf9eb
Show file tree
Hide file tree
Showing 22 changed files with 2,072 additions and 77 deletions.
7 changes: 7 additions & 0 deletions .changeset/slimy-experts-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'web-persistence': minor
'web-osmosis': minor
'web-desmos': minor
---

fix: update proposal metadata display
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useEffect, useState } from 'react';
import Loading from '@/components/loading';

interface MetadataLoaderProps {
metadata: string;
}

// Checks if a string is a valid URL
const isValidUrl = (url: string) => {
const pattern = /^(ftp|http|https|ipfs):\/\/[^ "]+$/;
return pattern.test(url);
};

// Checks if a string is a IPFS URL
const isIPFSUrl = (url: string) => {
const pattern = /^(ipfs):\/\/[^ "]+$/;
return pattern.test(url);
};

// Removes ipfs prefix from metadata
const removeIPFSPrefix = (metadata: string): string => {
if (metadata.startsWith('ipfs://')) {
return metadata.substring('ipfs://'.length);
}
return metadata;
};

const MetadataLoader: React.FC<MetadataLoaderProps> = ({ metadata }) => {
const [metadataContent, setMetadataContent] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(true);

useEffect(() => {
let isMounted = true;

const fetchMetadata = async () => {
try {
if (!isValidUrl(metadata)) {
setMetadataContent(metadata);
return;
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // Abort the fetch after 10 seconds

let response: Response;
if (!isIPFSUrl(metadata)) {
response = await fetch(metadata, { signal: controller.signal });
} else {
const modifiedMetadata = removeIPFSPrefix(metadata);
response = await fetch(`https://ipfs.io/ipfs/${modifiedMetadata}`, {
signal: controller.signal,
});
}
clearTimeout(timeoutId); // Clear the timeout
if (!isMounted) {
setMetadataContent(metadata);
return;
}
if (!response.ok) {
setMetadataContent(metadata);
return;
}
const text = await response.text();
setMetadataContent(text);
} catch (err) {
if (!isMounted) return; // Exit if the component is unmounted
setMetadataContent(metadata);
} finally {
setLoading(false);
}
};

fetchMetadata();

return () => {
isMounted = false; // Set isMounted to false when unmounting
};
}, [metadata]);

if (loading) {
return <Loading />;
}

if (metadataContent) {
return <code>{metadataContent}</code>;
}

return null;
};

export default MetadataLoader;
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Typography from '@mui/material/Typography';
import useAppTranslation from '@/hooks/useAppTranslation';
import numeral from 'numeral';
import * as R from 'ramda';
import { FC, useCallback, useMemo } from 'react';
import { FC, useMemo, useCallback } from 'react';
import { useRecoilValue } from 'recoil';
import Box from '@/components/box';
import Markdown from '@/components/markdown';
Expand All @@ -19,6 +19,7 @@ import type { OverviewType } from '@/screens/proposal_details/types';
import { getProposalType } from '@/screens/proposal_details/utils';
import dayjs, { formatDayJs } from '@/utils/dayjs';
import { formatNumber, formatToken } from '@/utils/format_token';
import MetadataLoader from './components/metadata_loader';
import useStyles from './styles';

const Overview: FC<{ className?: string; overview: OverviewType }> = ({ className, overview }) => {
Expand Down Expand Up @@ -150,7 +151,7 @@ const Overview: FC<{ className?: string; overview: OverviewType }> = ({ classNam
{t('proposer')}
</Typography>
<Name name={proposerMoniker} address={proposerAddress} />
{!!overview.submitTime && (
{overview?.submitTime && (
<>
<Typography variant="body1" className="label">
{t('submitTime')}
Expand All @@ -160,7 +161,7 @@ const Overview: FC<{ className?: string; overview: OverviewType }> = ({ classNam
</Typography>
</>
)}
{!!overview.depositEndTime && (
{overview?.depositEndTime && (
<>
<Typography variant="body1" className="label">
{t('depositEndTime')}
Expand All @@ -170,7 +171,7 @@ const Overview: FC<{ className?: string; overview: OverviewType }> = ({ classNam
</Typography>
</>
)}
{!!overview.votingStartTime && (
{overview?.votingStartTime && (
<>
<Typography variant="body1" className="label">
{t('votingStartTime')}
Expand All @@ -180,7 +181,7 @@ const Overview: FC<{ className?: string; overview: OverviewType }> = ({ classNam
</Typography>
</>
)}
{!!overview.votingEndTime && (
{overview?.votingEndTime && (
<>
<Typography variant="body1" className="label">
{t('votingEndTime')}
Expand All @@ -194,12 +195,12 @@ const Overview: FC<{ className?: string; overview: OverviewType }> = ({ classNam
{t('description')}
</Typography>
<Markdown markdown={overview.description} />
{!!overview.metadata && (
{overview?.metadata && (
<>
<Typography variant="body1" className="label">
{t('metadata')}
</Typography>
<Markdown markdown={overview?.metadata} />
<MetadataLoader metadata={overview.metadata} />
</>
)}
{extra}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useEffect, useState } from 'react';
import Loading from '@/components/loading';

interface MetadataLoaderProps {
metadata: string;
}

// Checks if a string is a valid URL
const isValidUrl = (url: string) => {
const pattern = /^(ftp|http|https|ipfs):\/\/[^ "]+$/;
return pattern.test(url);
};

// Checks if a string is a IPFS URL
const isIPFSUrl = (url: string) => {
const pattern = /^(ipfs):\/\/[^ "]+$/;
return pattern.test(url);
};

// Removes ipfs prefix from metadata
const removeIPFSPrefix = (metadata: string): string => {
if (metadata.startsWith('ipfs://')) {
return metadata.substring('ipfs://'.length);
}
return metadata;
};

const MetadataLoader: React.FC<MetadataLoaderProps> = ({ metadata }) => {
const [metadataContent, setMetadataContent] = useState<string | null>(null);
const [loading, setLoading] = useState<boolean>(true);

useEffect(() => {
let isMounted = true;

const fetchMetadata = async () => {
try {
if (!isValidUrl(metadata)) {
setMetadataContent(metadata);
return;
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // Abort the fetch after 10 seconds

let response: Response;
if (!isIPFSUrl(metadata)) {
response = await fetch(metadata, { signal: controller.signal });
} else {
const modifiedMetadata = removeIPFSPrefix(metadata);
response = await fetch(`https://ipfs.io/ipfs/${modifiedMetadata}`, {
signal: controller.signal,
});
}
clearTimeout(timeoutId); // Clear the timeout
if (!isMounted) {
setMetadataContent(metadata);
return;
}
if (!response.ok) {
setMetadataContent(metadata);
return;
}
const text = await response.text();
setMetadataContent(text);
} catch (err) {
if (!isMounted) return; // Exit if the component is unmounted
setMetadataContent(metadata);
} finally {
setLoading(false);
}
};

fetchMetadata();

return () => {
isMounted = false; // Set isMounted to false when unmounting
};
}, [metadata]);

if (loading) {
return <Loading />;
}

if (metadataContent) {
return <code>{metadataContent}</code>;
}

return null;
};

export default MetadataLoader;
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Typography from '@mui/material/Typography';
import useAppTranslation from '@/hooks/useAppTranslation';
import numeral from 'numeral';
import * as R from 'ramda';
import { FC, useCallback, useMemo } from 'react';
import { FC, useMemo, useCallback } from 'react';
import { useRecoilValue } from 'recoil';
import Box from '@/components/box';
import Markdown from '@/components/markdown';
Expand All @@ -19,6 +19,7 @@ import type { OverviewType } from '@/screens/proposal_details/types';
import { getProposalType } from '@/screens/proposal_details/utils';
import dayjs, { formatDayJs } from '@/utils/dayjs';
import { formatNumber, formatToken } from '@/utils/format_token';
import MetadataLoader from './components/metadata_loader';
import useStyles from './styles';

const Overview: FC<{ className?: string; overview: OverviewType }> = ({ className, overview }) => {
Expand Down Expand Up @@ -132,21 +133,25 @@ const Overview: FC<{ className?: string; overview: OverviewType }> = ({ classNam
/>
<Divider />
<div className={classes.content}>
<Typography variant="body1" className="label">
{t('type')}
</Typography>
<Typography variant="body1">
{types.map((type: string) => (
<Typography variant="body1" className="value" key={type}>
{t(type)}
{types.length > 0 && (
<>
<Typography variant="body1" className="label">
{t('type')}
</Typography>
))}
</Typography>
<Typography variant="body1">
{types.map((type: string) => (
<Typography variant="body1" className="value" key={type}>
{t(type)}
</Typography>
))}
</Typography>
</>
)}
<Typography variant="body1" className="label">
{t('proposer')}
</Typography>
<Name name={proposerMoniker} address={proposerAddress} />
{!!overview.submitTime && (
{overview?.submitTime && (
<>
<Typography variant="body1" className="label">
{t('submitTime')}
Expand All @@ -156,7 +161,7 @@ const Overview: FC<{ className?: string; overview: OverviewType }> = ({ classNam
</Typography>
</>
)}
{!!overview.depositEndTime && (
{overview?.depositEndTime && (
<>
<Typography variant="body1" className="label">
{t('depositEndTime')}
Expand All @@ -166,7 +171,7 @@ const Overview: FC<{ className?: string; overview: OverviewType }> = ({ classNam
</Typography>
</>
)}
{!!overview.votingStartTime && (
{overview?.votingStartTime && (
<>
<Typography variant="body1" className="label">
{t('votingStartTime')}
Expand All @@ -176,7 +181,7 @@ const Overview: FC<{ className?: string; overview: OverviewType }> = ({ classNam
</Typography>
</>
)}
{!!overview.votingEndTime && (
{overview?.votingEndTime && (
<>
<Typography variant="body1" className="label">
{t('votingEndTime')}
Expand All @@ -190,6 +195,14 @@ const Overview: FC<{ className?: string; overview: OverviewType }> = ({ classNam
{t('description')}
</Typography>
<Markdown markdown={overview.description} />
{overview?.metadata && (
<>
<Typography variant="body1" className="label">
{t('metadata')}
</Typography>
<MetadataLoader metadata={overview.metadata} />
</>
)}
{extra}
</div>
</Box>
Expand Down
2 changes: 2 additions & 0 deletions apps/web-osmosis/src/screens/proposal_details/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const formatOverview = (data: ProposalDetailsQuery) => {
title: data?.proposal?.[0]?.title ?? '',
id: data?.proposal?.[0]?.proposalId ?? '',
description: data?.proposal?.[0]?.description ?? '',
metadata: data?.proposal?.[0]?.metadata ?? '',
status: data?.proposal?.[0]?.status ?? '',
submitTime: data?.proposal?.[0]?.submitTime ?? '',
depositEndTime: data?.proposal?.[0]?.depositEndTime ?? '',
Expand Down Expand Up @@ -62,6 +63,7 @@ export const useProposalDetails = () => {
title: '',
id: 0,
description: '',
metadata: '',
status: '',
submitTime: '',
depositEndTime: '',
Expand Down
1 change: 1 addition & 0 deletions apps/web-osmosis/src/screens/proposal_details/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export interface OverviewType {
id: number;
proposer: string;
description: string;
metadata: string;
status: string;
submitTime: string;
depositEndTime: string;
Expand Down
2 changes: 1 addition & 1 deletion apps/web-persistence/codegen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ generates:
./src/graphql/types/general_types.ts:
documents:
- 'src/graphql/general/*'
schema: https://gql-testnet.persistence.forbole.com/v1/graphql
schema: https://gql.persistence.forbole.com/v1/graphql
config:
# omitOperationSuffix: true
skipTypeNameForRoot: true
Expand Down
8 changes: 4 additions & 4 deletions apps/web-persistence/src/graphql/general/params.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ query Params {
distributionParams: distribution_params(limit: 1, order_by: {height: desc}) {
params
}
govParams: gov_params (limit: 1, order_by: {height: desc}) {
depositParams: deposit_params
tallyParams: tally_params
votingParams: voting_params
govParams: gov_params(limit: 1, order_by: {height: desc}) {
one_row_id
params
height
}
}
Loading

0 comments on commit 6bcf9eb

Please sign in to comment.