Skip to content

Commit

Permalink
refactor(website): useQueryIpfsData (#1236)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicosampler authored Aug 3, 2024
1 parent 9c9e68e commit 83843fd
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 113 deletions.
111 changes: 69 additions & 42 deletions packages/website/src/features/Ipfs/Download.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import React, { useEffect, useState } from 'react';
import React, { ChangeEvent, useEffect, useState } from 'react';
import {
Checkbox,
Container,
Expand All @@ -17,42 +17,64 @@ import {
Button,
} from '@chakra-ui/react';
import { useRouter } from 'next/router';
import { useQueryIpfsData } from '@/hooks/ipfs';
import { useQueryIpfsDataRaw } from '@/hooks/ipfs';
import { CodePreview } from '@/components/CodePreview';
import { useStore } from '@/helpers/store';
import { DownloadIcon } from '@chakra-ui/icons';
import NextLink from 'next/link';
import {
arrayBufferToUtf8,
decodeData,
decompressData,
Encodings,
EncodingsKeys,
} from '@/helpers/misc';

function parseJson(data: ArrayBuffer | undefined, decompress?: boolean) {
if (!data || decompress === undefined) return false;
let _data;
if (decompress) {
try {
_data = decompressData(data) as string;
} catch (error) {
_data = JSON.stringify({
error: 'Failed trying to decompress data.',
try: 'Disabling compression.',
});
}
} else {
_data = arrayBufferToUtf8(data);
}

function isJsonParsable(string: string): boolean {
try {
JSON.parse(string);
return true;
return JSON.parse(_data);
} catch (e) {
return false;
return null;
}
}

export default function Download() {
const [cid, setCid] = useState('');
const [decompress, setDecompress] = useState(false);
const [decompress, setDecompress] = useState<boolean | undefined>();
const router = useRouter();
const pathname = router.pathname;
const searchParams = router.query;
const ipfsApiUrl = useStore((s) => s.settings.ipfsApiUrl);
const [encoding, setEncoding] = useState('utf8');
const [encoding, setEncoding] = useState<EncodingsKeys>('utf8');

useEffect(() => {
const queryCid = searchParams.cid;
const queryCompressed = searchParams.compressed;

if (queryCid && typeof queryCid === 'string') {
setCid(queryCid);
}
}, [searchParams]);

if (queryCompressed && queryCompressed === 'true') {
setDecompress(true);
useEffect(() => {
if (Object.keys(router.query).length && decompress === undefined) {
setDecompress(router.query.compressed !== 'false');
}
}, [searchParams]);
}, [router]);

const handleInputChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const current = new URLSearchParams(
Expand All @@ -76,38 +98,41 @@ export default function Download() {
const handleEncodingChange = (e: {
target: { value: React.SetStateAction<string> };
}) => {
setEncoding(e.target.value);
setEncoding(e.target.value as EncodingsKeys);
};

const decodeData = (data: ArrayBuffer, encoding: string) => {
try {
if (encoding === 'base64') {
return btoa(
String.fromCharCode.apply(null, Array.from(new Uint8Array(data)))
);
} else if (encoding === 'hex') {
return Array.from(new Uint8Array(data))
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
} else if (encoding === 'utf8') {
return new TextDecoder('utf-8').decode(new Uint8Array(data));
}
return data;
} catch (err) {
return data;
}
const handleSwitchDecompress = async (e: ChangeEvent<HTMLInputElement>) => {
setDecompress(e.target.checked);

const newQuery = {
...router.query,
compressed: e.target.checked.toString(),
};
await router.replace(
{
pathname: router.pathname,
query: newQuery,
},
undefined,
{ shallow: true }
);
};

const { data: ipfsData } = useQueryIpfsData(cid, true, !decompress);

const decodedData =
ipfsData instanceof ArrayBuffer
? decodeData(ipfsData, encoding)
: JSON.stringify(ipfsData, null, 2);

const isJson = isJsonParsable(String(decodedData));
const { data: ipfsData } = useQueryIpfsDataRaw(cid, true);
const parsedJsonData = parseJson(ipfsData, decompress);
const isJson = parsedJsonData !== null;
const decodedData = isJson
? JSON.stringify(parsedJsonData, null, 2)
: decompress
? JSON.stringify({
error: 'Compression is not enabled for non JSON files.',
try: 'Disabling compression.',
})
: decodeData(ipfsData as ArrayBuffer, encoding);

const handleDownload = () => {
if (!decodedData) return;

const blob = new Blob([decodedData], { type: 'application/octet-stream' });

const url = URL.createObjectURL(blob);
Expand Down Expand Up @@ -171,7 +196,7 @@ export default function Download() {
<Checkbox
mb={2}
isChecked={decompress}
onChange={(e) => setDecompress(e.target.checked)}
onChange={handleSwitchDecompress}
>
Decompress using zlib
</Checkbox>
Expand All @@ -184,9 +209,11 @@ export default function Download() {
onChange={handleEncodingChange}
mb={2}
>
<option value="utf8">UTF-8</option>
<option value="base64">Base64</option>
<option value="hex">Hexadecimal</option>
{Object.entries(Encodings).map(([key, value]) => (
<option key={key} value={key}>
{value}
</option>
))}
</Select>
</FormControl>
<Box mb={4} minHeight="420px">
Expand Down
12 changes: 6 additions & 6 deletions packages/website/src/features/Packages/CannonfileExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { DeploymentInfo } from '@usecannon/builder/src/types';
import { InfoIcon } from '@chakra-ui/icons';
import ChainDefinitionSteps from './ChainDefinitionSteps';
import { isEmpty } from 'lodash';
import { useQueryIpfsData } from '@/hooks/ipfs';
import { useQueryIpfsDataParsed } from '@/hooks/ipfs';
import { CannonfileGraph } from './CannonfileGraph';
import { StepModalProvider } from '@/providers/stepModalProvider';
import { stringify } from '@iarna/toml';
Expand All @@ -56,11 +56,11 @@ function omitEmptyObjects(config: { [x: string]: any }) {
export const CannonfileExplorer: FC<{
pkg: any;
}> = ({ pkg }) => {
const deploymentData = useQueryIpfsData(pkg?.deployUrl, !!pkg?.deployUrl);

const deploymentInfo = deploymentData.data
? (deploymentData.data as DeploymentInfo)
: undefined;
const deploymentData = useQueryIpfsDataParsed<DeploymentInfo>(
pkg?.deployUrl,
!!pkg?.deployUrl
);
const deploymentInfo = deploymentData.data;

const {
isOpen: isPackageJsonModalOpen,
Expand Down
48 changes: 28 additions & 20 deletions packages/website/src/features/Packages/CodeExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ import {
import 'prismjs';
import 'prismjs/components/prism-toml';
import { CodePreview } from '@/components/CodePreview';
import { useQueryIpfsData } from '@/hooks/ipfs';
import { useQueryIpfsDataParsed } from '@/hooks/ipfs';
import { DownloadIcon, InfoOutlineIcon } from '@chakra-ui/icons';
import { CustomSpinner } from '@/components/CustomSpinner';
import { isEmpty } from 'lodash';
import { DeploymentInfo } from '@usecannon/builder';

const handleDownload = (content: JSON, filename: string) => {
const handleDownload = (content: Record<string, unknown>, filename: string) => {
const blob = new Blob([JSON.stringify(content, null, 2)], {
type: 'application/json',
});
Expand Down Expand Up @@ -104,17 +105,23 @@ export const CodeExplorer: FC<{
name,
key: -1,
});
const { data: metadata } = useQueryIpfsData(pkg?.metaUrl, !!pkg?.metaUrl);
const { data: metadata } = useQueryIpfsDataParsed<{
cannonfile: string;
}>(pkg?.metaUrl, !!pkg?.metaUrl);

const deploymentData = useQueryIpfsData(pkg?.deployUrl, !!pkg?.deployUrl);
const deploymentData = useQueryIpfsDataParsed<DeploymentInfo>(
pkg?.deployUrl,
!!pkg?.deployUrl
);

// Provisioned packages could be inside the "provision" (old) or "clone" (current) key
// So we check both in order to keep backwards compatibility
const provisionedPackagesKeys =
deploymentData?.data?.def?.provision || deploymentData?.data?.def?.clone
? Object.keys(
deploymentData?.data?.def?.provision ||
deploymentData?.data?.def?.clone
deploymentData?.data?.def?.clone ||
{}
)
: [];
const provisionArtifacts = provisionedPackagesKeys.map((k: string) => {
Expand Down Expand Up @@ -144,31 +151,32 @@ export const CodeExplorer: FC<{
const {
data: provisionedPackageData,
isLoading: isLoadingProvisionedPackageData,
} = useQueryIpfsData(
provisionArtifacts[selectedPackage.key]?.artifacts?.imports[
} = useQueryIpfsDataParsed<{ miscUrl: string }>(
provisionArtifacts[selectedPackage.key]?.artifacts?.imports?.[
selectedPackage.name
]?.url,
!!provisionArtifacts[selectedPackage.key]?.artifacts?.imports[
!!provisionArtifacts[selectedPackage.key]?.artifacts?.imports?.[
selectedPackage.name
]?.url
);

const provisionedMiscUrl = provisionedPackageData?.miscUrl;

const { data: provisionedMiscData, isLoading: isLoadingProvisionedMiscData } =
useQueryIpfsData(provisionedMiscUrl, !!provisionedMiscUrl);
useQueryIpfsDataParsed<{ artifacts: Record<string, unknown> }>(
provisionedMiscUrl,
!!provisionedMiscUrl
);

let miscUrl: string | undefined;
if (deploymentData?.data) {
miscUrl =
typeof deploymentData?.data === 'string'
? JSON.parse(deploymentData?.data)?.miscUrl
: JSON.parse(JSON.stringify((deploymentData as any)?.data))?.miscUrl;
miscUrl = deploymentData?.data?.miscUrl;
}

const { data: miscData, isLoading: isLoadingMiscData } = useQueryIpfsData(
miscUrl,
!!miscUrl
);
const { data: miscData, isLoading: isLoadingMiscData } =
useQueryIpfsDataParsed<{ artifacts: Record<string, unknown> }>(
miscUrl,
!!miscUrl
);

const isSelectedPackage = ({ key, name }: { key: number; name: string }) =>
selectedPackage.key === key && selectedPackage.name === name;
Expand Down Expand Up @@ -408,7 +416,7 @@ export const CodeExplorer: FC<{
maxHeight={['140px', '140px', 'calc(100vh - 236px)']}
>
<Box px={3} pb={2}>
{artifacts.map(([artifactKey, artifactValue]: [any, any]) => {
{artifacts?.map(([artifactKey, artifactValue]: [any, any]) => {
return (
<Box key={artifactKey} mt={4}>
<Flex
Expand Down Expand Up @@ -504,7 +512,7 @@ export const CodeExplorer: FC<{
);
})}

{metadata?.cannonfile && (
{metadata?.cannonfile !== undefined && (
<>
<Box mt={4}>
<Flex
Expand Down
16 changes: 8 additions & 8 deletions packages/website/src/features/Packages/DeploymentExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { DeploymentInfo } from '@usecannon/builder/src/types';
import { InfoIcon, DownloadIcon } from '@chakra-ui/icons';
import { ChainBuilderContext } from '@usecannon/builder';
import { isEmpty } from 'lodash';
import { useQueryIpfsData } from '@/hooks/ipfs';
import { useQueryIpfsDataParsed } from '@/hooks/ipfs';
import { CommandPreview } from '@/components/CommandPreview';
import { ContractsTable } from './ContractsTable';
import { InvokesTable } from './InvokesTable';
Expand All @@ -27,11 +27,11 @@ import { EventsTable } from './EventsTable';
export const DeploymentExplorer: FC<{
pkg: any;
}> = ({ pkg }) => {
const deploymentData = useQueryIpfsData(pkg?.deployUrl, !!pkg?.deployUrl);

const deploymentInfo = deploymentData.data
? (deploymentData.data as DeploymentInfo)
: undefined;
const deploymentData = useQueryIpfsDataParsed<DeploymentInfo>(
pkg?.deployUrl,
!!pkg?.deployUrl
);
const deploymentInfo = deploymentData.data;

const settings: { [key: string]: any } = {};
if (deploymentInfo?.def?.setting) {
Expand Down Expand Up @@ -200,8 +200,8 @@ export const DeploymentExplorer: FC<{
</Box>
<CommandPreview
command={`cannon ${pkg.name}${
pkg?.tag !== 'latest' ? `:${pkgDef.version}` : ''
}${pkg.preset !== 'main' ? `@${pkgDef.preset}` : ''}`}
pkg?.tag !== 'latest' ? `:${pkgDef?.version}` : ''
}${pkg.preset !== 'main' ? `@${pkgDef?.preset}` : ''}`}
/>
</Container>
)}
Expand Down
7 changes: 4 additions & 3 deletions packages/website/src/features/Packages/Interact.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CustomSpinner } from '@/components/CustomSpinner';
import { Abi } from '@/features/Packages/Abi';
import chains from '@/helpers/chains';
import { useQueryIpfsData } from '@/hooks/ipfs';
import { useQueryIpfsDataParsed } from '@/hooks/ipfs';
import { getOutput } from '@/lib/builder';
import {
Box,
Expand All @@ -16,6 +16,7 @@ import {
import {
ChainArtifacts,
ContractData,
DeploymentInfo,
PackageReference,
} from '@usecannon/builder';
import { FC, useContext, useEffect, useState } from 'react';
Expand Down Expand Up @@ -45,13 +46,13 @@ export const Interact: FC<{
const [cannonOutputs, setCannonOutputs] = useState<ChainArtifacts>({});
const [contract, setContract] = useState<ContractData | undefined>();

const deploymentData = useQueryIpfsData(
const deploymentData = useQueryIpfsDataParsed<DeploymentInfo>(
packagesQuery?.data?.data.deployUrl,
!!packagesQuery?.data?.data.deployUrl
);

useEffect(() => {
if (deploymentData.isPending) {
if (deploymentData.isPending || !deploymentData.data) {
return;
}

Expand Down
Loading

0 comments on commit 83843fd

Please sign in to comment.