diff --git a/.changeset/soft-forks-hope.md b/.changeset/soft-forks-hope.md deleted file mode 100644 index 69d17cc28..000000000 --- a/.changeset/soft-forks-hope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fuels/ui": minor ---- - -Make the @fuels/ui package public and publishable diff --git a/contracts/predicate/package.json b/contracts/predicate/package.json index 2feff0270..d5c791b50 100644 --- a/contracts/predicate/package.json +++ b/contracts/predicate/package.json @@ -1,5 +1,6 @@ { "name": "predicate", + "private": true, "version": "0.0.1", "description": "Predicate app using Sway", "scripts": { diff --git a/docker/erc20-deployer/deployer/package.json b/docker/erc20-deployer/deployer/package.json index 36f671e30..d0c5a649c 100644 --- a/docker/erc20-deployer/deployer/package.json +++ b/docker/erc20-deployer/deployer/package.json @@ -1,5 +1,6 @@ { "name": "erc20-deployer", + "private": true, "scripts": { "start": "ts-node ./src/index.ts" }, diff --git a/helm/fuel-explorer/Chart.yaml b/helm/fuel-explorer/Chart.yaml index 562f4ac43..0187195f4 100644 --- a/helm/fuel-explorer/Chart.yaml +++ b/helm/fuel-explorer/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.11 +version: 0.1.12 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/helm/fuel-explorer/templates/servicemonitor.yaml b/helm/fuel-explorer/templates/servicemonitor.yaml new file mode 100644 index 000000000..62f88095a --- /dev/null +++ b/helm/fuel-explorer/templates/servicemonitor.yaml @@ -0,0 +1,15 @@ +{{- if .Values.app.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "fuel-explorer.fullname" . }} + labels: + release: {{ .Values.app.serviceMonitor.prometheusRelease }} +spec: + selector: + matchLabels: + {{- include "fuel-explorer.labels" . | nindent 4 }} + endpoints: + - path: /metrics + port: http +{{- end }} diff --git a/helm/fuel-explorer/values.yaml b/helm/fuel-explorer/values.yaml index 82263c908..783c0a3e8 100644 --- a/helm/fuel-explorer/values.yaml +++ b/helm/fuel-explorer/values.yaml @@ -83,3 +83,8 @@ nodeSelector: {} tolerations: [] affinity: {} + +app: + serviceMonitor: + enabled: true + prometheusRelease: kube-prometheus diff --git a/packages/app-explorer/src/systems/Core/components/BalanceItem/BalanceItem.tsx b/packages/app-explorer/src/systems/Core/components/BalanceItem/BalanceItem.tsx index 1cf5d17b5..394c8bcd4 100644 --- a/packages/app-explorer/src/systems/Core/components/BalanceItem/BalanceItem.tsx +++ b/packages/app-explorer/src/systems/Core/components/BalanceItem/BalanceItem.tsx @@ -13,7 +13,8 @@ import { AssetItem } from '~/systems/Asset/components/AssetItem/AssetItem'; import type { GQLBalanceItemFragment } from '@fuel-explorer/graphql'; import { Amount } from '../Amount/Amount'; -import type { UtxoItem } from '../Utxos/Utxos'; + +import { UtxoItemType } from '~/systems/Core/components/Utxos/types'; import { Utxos } from '../Utxos/Utxos'; type BalanceItemProps = BaseProps<{ @@ -56,7 +57,9 @@ export function BalanceItem({ item, isLoading, ...props }: BalanceItemProps) { - {hasUTXOs && } + {hasUTXOs && ( + } assetId={assetId} /> + )} ); } diff --git a/packages/app-explorer/src/systems/Core/components/UtxoItem/UtxoItem.tsx b/packages/app-explorer/src/systems/Core/components/UtxoItem/UtxoItem.tsx new file mode 100644 index 000000000..5b9ce823d --- /dev/null +++ b/packages/app-explorer/src/systems/Core/components/UtxoItem/UtxoItem.tsx @@ -0,0 +1,50 @@ +import { Address, Box, useBreakpoints } from '@fuels/ui'; +import { bn, toBytes, toHex } from 'fuels'; +import NextLink from 'next/link'; +import { useMemo } from 'react'; +import { Routes } from '~/routes'; + +import { Amount } from '../Amount/Amount'; +import { TX_ID_SIZE, UTXO_ID_SIZE } from './constants'; +import { styles } from './styles'; +import { UtxoItemProps } from './types'; + +export function UtxoItem({ item, style, assetId, index }: UtxoItemProps) { + const { isMobile } = useBreakpoints(); + + const txId = useMemo(() => { + if (!item.utxoId) return null; + const bytes = toBytes(item.utxoId, UTXO_ID_SIZE).slice(0, TX_ID_SIZE); + return toHex(bytes, TX_ID_SIZE); + }, []); + + if (!txId) return null; + + const trim = isMobile ? 8 : 16; + const { item: itemStyle } = styles({ + color: index % 2 !== 0 ? 'odd' : undefined, + }); + + return ( + +
+ + + ); +} diff --git a/packages/app-explorer/src/systems/Core/components/UtxoItem/constants.ts b/packages/app-explorer/src/systems/Core/components/UtxoItem/constants.ts new file mode 100644 index 000000000..ef20df99d --- /dev/null +++ b/packages/app-explorer/src/systems/Core/components/UtxoItem/constants.ts @@ -0,0 +1,2 @@ +export const UTXO_ID_SIZE = 34; +export const TX_ID_SIZE = 32; diff --git a/packages/app-explorer/src/systems/Core/components/UtxoItem/styles.ts b/packages/app-explorer/src/systems/Core/components/UtxoItem/styles.ts new file mode 100644 index 000000000..929e86f38 --- /dev/null +++ b/packages/app-explorer/src/systems/Core/components/UtxoItem/styles.ts @@ -0,0 +1,19 @@ +import { tv } from 'tailwind-variants'; + +export const styles = tv({ + slots: { + item: [ + 'flex flex-col p-2 px-4 gap-2', + 'tablet:flex-row', + 'last:rounded-b-sm', + 'fuel-[Address]:text-[0.8rem] fuel-[Address]:leading-none', + ], + }, + variants: { + color: { + odd: { + item: 'bg-gray-4', + }, + }, + }, +}); diff --git a/packages/app-explorer/src/systems/Core/components/UtxoItem/types.ts b/packages/app-explorer/src/systems/Core/components/UtxoItem/types.ts new file mode 100644 index 000000000..53b304ceb --- /dev/null +++ b/packages/app-explorer/src/systems/Core/components/UtxoItem/types.ts @@ -0,0 +1,9 @@ +import type { CSSProperties } from 'react'; +import type { UtxoItemType } from '~/systems/Core/components/Utxos/types'; + +export type UtxoItemProps = { + item: UtxoItemType; + assetId?: string; + style?: CSSProperties; + index: number; +}; diff --git a/packages/app-explorer/src/systems/Core/components/Utxos/Utxos.tsx b/packages/app-explorer/src/systems/Core/components/Utxos/Utxos.tsx index 75289978d..4dcd15595 100644 --- a/packages/app-explorer/src/systems/Core/components/Utxos/Utxos.tsx +++ b/packages/app-explorer/src/systems/Core/components/Utxos/Utxos.tsx @@ -1,72 +1,9 @@ -import type { GQLUtxoItem as TUtxoItem } from '@fuel-explorer/graphql'; -import { Address, Box, Collapsible, useBreakpoints } from '@fuels/ui'; -import type { BoxProps } from '@fuels/ui'; +import { Collapsible, useBreakpoints } from '@fuels/ui'; import { IconCoins } from '@tabler/icons-react'; -import { bn, toBytes, toHex } from 'fuels'; -import NextLink from 'next/link'; import { FixedSizeList as List } from 'react-window'; -import { tv } from 'tailwind-variants'; -import { Routes } from '~/routes'; -import { useMemo } from 'react'; -import { Amount } from '../Amount/Amount'; - -export type UtxoItem = Partial>; - -type UtxoItemProps = { - item: UtxoItem; - assetId?: string; - style?: React.CSSProperties; - index: number; -}; - -const UTXO_ID_SIZE = 34; -const TX_ID_SIZE = 32; - -function UtxoItem({ item, style, assetId, index }: UtxoItemProps) { - const { isMobile } = useBreakpoints(); - - const txId = useMemo(() => { - if (!item.utxoId) return null; - const bytes = toBytes(item.utxoId, UTXO_ID_SIZE).slice(0, TX_ID_SIZE); - return toHex(bytes, TX_ID_SIZE); - }, []); - - if (!txId) return null; - - const trim = isMobile ? 8 : 16; - const { item: itemStyle } = styles({ - color: index % 2 !== 0 ? 'odd' : undefined, - }); - - return ( - -
- - - ); -} - -type UtxosProps = BoxProps & { - assetId?: string; - items?: UtxoItem[] | null; -}; +import { UtxoItem } from '~/systems/Core/components/UtxoItem/UtxoItem'; +import { UtxosProps } from './types'; function VirtualList({ items, assetId }: UtxosProps) { const { isMobile } = useBreakpoints(); @@ -110,21 +47,3 @@ export function Utxos({ items, assetId, ...props }: UtxosProps) { ); } - -const styles = tv({ - slots: { - item: [ - 'flex flex-col p-2 px-4 gap-2', - 'tablet:flex-row', - 'last:rounded-b-sm', - 'fuel-[Address]:text-[0.8rem] fuel-[Address]:leading-none', - ], - }, - variants: { - color: { - odd: { - item: 'bg-gray-4', - }, - }, - }, -}); diff --git a/packages/app-explorer/src/systems/Core/components/Utxos/types.ts b/packages/app-explorer/src/systems/Core/components/Utxos/types.ts new file mode 100644 index 000000000..d0c8afe39 --- /dev/null +++ b/packages/app-explorer/src/systems/Core/components/Utxos/types.ts @@ -0,0 +1,8 @@ +import type { GQLUtxoItem as TUtxoItem } from '@fuel-explorer/graphql/sdk'; +import type { BoxProps } from '@fuels/ui'; + +export type UtxoItemType = Partial>; +export type UtxosProps = BoxProps & { + assetId?: string; + items?: UtxoItemType[] | null; +}; diff --git a/packages/app-explorer/src/systems/Transaction/__mocks__/tx.ts b/packages/app-explorer/src/systems/Transaction/__mocks__/tx.ts index 12266031b..6190aca88 100644 --- a/packages/app-explorer/src/systems/Transaction/__mocks__/tx.ts +++ b/packages/app-explorer/src/systems/Transaction/__mocks__/tx.ts @@ -1,4 +1,4 @@ -import { GQLInputCoin, mocks } from '@fuel-explorer/graphql'; +import { mocks } from '@fuel-explorer/graphql'; import { dayjs } from '~/systems/Core/utils/dayjs'; const date = dayjs().subtract(1, 'day'); @@ -9,10 +9,22 @@ const status = mocks.aSuccessStatus({ }), }); -function input(typename: GQLInputCoin['__typename']) { - return mocks.anInputCoin({ __typename: typename }); +function mockedInputCoinFactory() { + return mocks.anInputCoin({ __typename: 'InputCoin' }); } +function mockedInputMessageFactory() { + return mocks.anInputMessage({ __typename: 'InputMessage' }); +} + +function mockedInputContractFactory() { + return mocks.anInputContract({ __typename: 'InputContract' }); +} + +export const MOCKED_COIN = mockedInputCoinFactory(); +export const MOCKED_MESSAGE = mockedInputMessageFactory(); +export const MOCKED_CONTRACT = mockedInputContractFactory(); + const ADDRS = { to: '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', owner: '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', @@ -23,18 +35,26 @@ const ADDRS = { '0x4c6be4ed66b783f55e44a6d36290a73970a616ba33256636cf15ad5cded228d9', }; -export const GROUPED_INPUT_ASSET = mocks.aGroupedInputCoin({ +const GROUPED_INPUT_ASSET = mocks.aGroupedInputCoin({ ...ADDRS, assetId: '0x0000000000000000000000000000000000000000', - inputs: [input('InputCoin'), input('InputCoin'), input('InputCoin')], + inputs: [ + mockedInputCoinFactory(), + mockedInputCoinFactory(), + mockedInputCoinFactory(), + ], }); -export const GROUPED_INPUT_ASSET_UNKNOWN = mocks.aGroupedInputCoin({ +const GROUPED_INPUT_ASSET_UNKNOWN = mocks.aGroupedInputCoin({ ...ADDRS, - inputs: [input('InputCoin'), input('InputCoin'), input('InputCoin')], + inputs: [ + mockedInputCoinFactory(), + mockedInputCoinFactory(), + mockedInputCoinFactory(), + ], }); -export const GROUPED_INPUT_MESSAGE = mocks.aGroupedInputMessage({ +const GROUPED_INPUT_MESSAGE = mocks.aGroupedInputMessage({ ...ADDRS, }); @@ -65,6 +85,12 @@ export const TX_MOCK = mocks.aTransaction({ GROUPED_INPUT_ASSET, GROUPED_INPUT_MESSAGE, ], + // @TODO: Fix maximum call stack size exceeded and remove override below + operations: [ + mocks.anOperation({ + receipts: [mocks.anOperationReceipt({ receipts: [] })] ?? [], + }), + ], groupedOutputs: [], outputs: [OUTPUT_ASSET, OUTPUT_ASSET_UNKNOWN, OUTPUT_CONTRACT_CREATED], }); diff --git a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInput.stories.tsx b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInput.stories.tsx index acb0c279f..986c6fdb1 100644 --- a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInput.stories.tsx +++ b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInput.stories.tsx @@ -2,9 +2,9 @@ import { VStack } from '@fuels/ui'; import type { Meta, StoryObj } from '@storybook/react'; import { - GROUPED_INPUT_ASSET, - GROUPED_INPUT_ASSET_UNKNOWN, - GROUPED_INPUT_MESSAGE, + MOCKED_COIN, + MOCKED_CONTRACT, + MOCKED_MESSAGE, } from '../../__mocks__/tx'; import { TxInput } from './TxInput'; @@ -17,15 +17,30 @@ const meta: Meta = { export default meta; type Story = StoryObj; -export const Asset: Story = { +function Wrapper({ children }: { children: React.ReactNode }) { + return {children}; +} + +export const Coin: Story = { render: () => ( - - - - + + + ), }; export const Message: Story = { - render: () => , + render: () => ( + + + + ), +}; + +export const Contract: Story = { + render: () => ( + + + + ), }; diff --git a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInput.tsx b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInput.tsx index ff6795208..c3575251f 100644 --- a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInput.tsx +++ b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInput.tsx @@ -1,137 +1,23 @@ -import type { - GQLGroupedInput, - GQLGroupedInputCoin, - GQLGroupedInputMessage, - GQLInputCoin, -} from '@fuel-explorer/graphql'; -import type { CardProps } from '@fuels/ui'; -import { - Address, - Box, - Collapsible, - HStack, - Text, - VStack, - createComponent, - useBreakpoints, -} from '@fuels/ui'; -import { bn } from 'fuels'; -import NextLink from 'next/link'; -import { Routes } from '~/routes'; -import { AssetItem } from '~/systems/Asset/components/AssetItem/AssetItem'; -import { Amount } from '~/systems/Core/components/Amount/Amount'; -import type { UtxoItem } from '~/systems/Core/components/Utxos/Utxos'; -import { Utxos } from '~/systems/Core/components/Utxos/Utxos'; - -import { TxIcon } from '../TxIcon/TxIcon'; - -export type TxInputProps = CardProps & { - input: GQLGroupedInput; -}; - -export type TxInputCoinProps = TxInputProps & { - input: GQLGroupedInputCoin; -}; - -export type TxInputMessageProps = TxInputProps & { - input: GQLGroupedInputMessage; -}; - -const TxInputCoin = createComponent({ - id: 'TxInputCoin', - render: (_, { input, ...props }) => { - if (!input.assetId) return null; - - const assetId = input.assetId; - const amount = input.totalAmount; - const inputs = input.inputs as GQLInputCoin[]; - const { isMobile } = useBreakpoints(); - - return ( - - - -
- - {amount && ( - - - - )} - - - - ); - }, -}); - -const TxInputMessage = createComponent( - { - id: 'TxInputMessage', - render: (_, { input, ...props }) => { - const { sender, recipient, data } = input; - - if (!sender || !recipient) return null; - - return ( - - - - - Message - -
-
- - - - - Data - - {data} - - - - ); - }, - }, -); - -export function TxInput({ input, ...props }: TxInputProps) { - if (input.type?.includes('Coin')) { - return ; - } - if (input.type?.includes('Message')) { - return ( - - ); +import { memo } from 'react'; +import { TxInputCoin } from '~/systems/Transaction/component/TxInput/TxInputCoin/TxInputCoin'; +import type { InputCoin } from '~/systems/Transaction/component/TxInput/TxInputCoin/types'; +import { TxInputContract } from '~/systems/Transaction/component/TxInput/TxInputContract/TxInputContract'; +import type { InputContract } from '~/systems/Transaction/component/TxInput/TxInputContract/types'; +import { TxInputMessage } from '~/systems/Transaction/component/TxInput/TxInputMessage/TxInputMessage'; +import type { InputMessage } from '~/systems/Transaction/component/TxInput/TxInputMessage/types'; +import { TxInputProps } from './types'; + +function _TxInput({ input, ...props }: TxInputProps) { + switch (input?.__typename) { + case 'InputCoin': + return ; + case 'InputMessage': + return ; + case 'InputContract': + return ; + default: + return null; } } + +export const TxInput = memo(_TxInput); diff --git a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputCoin/TxInputCoin.tsx b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputCoin/TxInputCoin.tsx new file mode 100644 index 000000000..fcfe7b1a1 --- /dev/null +++ b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputCoin/TxInputCoin.tsx @@ -0,0 +1,95 @@ +import { + Address, + Badge, + Box, + Collapsible, + Flex, + createComponent, + useBreakpoints, +} from '@fuels/ui'; +import { IconCoins } from '@tabler/icons-react'; +import { bn } from 'fuels'; +import NextLink from 'next/link'; + +import { Routes } from '~/routes'; +import { AssetItem } from '~/systems/Asset/components/AssetItem/AssetItem'; +import { Amount } from '~/systems/Core/components/Amount/Amount'; +import { UtxoItem } from '~/systems/Core/components/UtxoItem/UtxoItem'; +import { TxInputCoinProps } from './types'; + +export const TxInputCoin = createComponent< + TxInputCoinProps, + typeof Collapsible +>({ + id: 'TxInputCoin', + render: (_, { input, ...props }) => { + if (!input.assetId) return null; + + const assetId = input.assetId; + const amount = input.amount; + const { isMobile } = useBreakpoints(); + + return ( + + + + + COIN + + + + +
+ + {amount && ( + + + COIN + + + + )} + + + + + + UTXO + + + + + + + ); + }, +}); diff --git a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputCoin/types.ts b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputCoin/types.ts new file mode 100644 index 000000000..56cc56457 --- /dev/null +++ b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputCoin/types.ts @@ -0,0 +1,11 @@ +import type { GQLTransactionItemFragment } from '@fuel-explorer/graphql/sdk'; +import type { TxInputProps } from '~/systems/Transaction/component/TxInput/types'; + +export type InputCoin = Extract< + NonNullable[number], + { __typename: 'InputCoin' } +>; + +export type TxInputCoinProps = TxInputProps & { + input: InputCoin; +}; diff --git a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputContract/TxInputContract.tsx b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputContract/TxInputContract.tsx new file mode 100644 index 000000000..1997691d6 --- /dev/null +++ b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputContract/TxInputContract.tsx @@ -0,0 +1,110 @@ +import { + Address, + Badge, + Collapsible, + Flex, + HStack, + Text, + VStack, + createComponent, + useBreakpoints, +} from '@fuels/ui'; +import NextLink from 'next/link'; + +import { IconCode } from '@tabler/icons-react'; +import { Routes } from '~/routes'; +import { TxIcon } from '~/systems/Transaction/component/TxIcon/TxIcon'; +import { styles } from './styles'; +import type { TxInputContractProps } from './types'; + +export const TxInputContract = createComponent< + TxInputContractProps, + typeof Collapsible +>({ + id: 'TxInputContract', + render: (_, { input, ...props }) => { + const { utxoId, balanceRoot, txPointer, contractId } = input; + const { isMobile } = useBreakpoints(); + const trim = isMobile ? 8 : 16; + const classes = styles(); + + return ( + + + + + CONTRACT + + + + + + Contract + +
+ + + + + + + Data + + + +
+
+
+ + + Tx Pointer: + + + {txPointer} + + + + + + + ); + }, +}); diff --git a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputContract/styles.ts b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputContract/styles.ts new file mode 100644 index 000000000..f4813a8d2 --- /dev/null +++ b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputContract/styles.ts @@ -0,0 +1,14 @@ +import { tv } from 'tailwind-variants'; + +export const styles = tv({ + slots: { + item: [ + 'flex flex-col p-2 px-4 gap-2', + 'tablet:flex-row', + 'last:rounded-b-sm', + 'fuel-[Address]:text-[0.8rem] fuel-[Address]:leading-none', + ], + contractAddress: + 'flex-col items-start gap-1 flex-1 tablet:flex-row tablet:items-center tablet:gap-4', + }, +}); diff --git a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputContract/types.ts b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputContract/types.ts new file mode 100644 index 000000000..aa8ff1f52 --- /dev/null +++ b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputContract/types.ts @@ -0,0 +1,11 @@ +import type { GQLTransactionItemFragment } from '@fuel-explorer/graphql/sdk'; +import type { TxInputProps } from '~/systems/Transaction/component/TxInput/types'; + +export type InputContract = Extract< + NonNullable[number], + { __typename: 'InputContract' } +>; + +export type TxInputContractProps = TxInputProps & { + input: InputContract; +}; diff --git a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputMessage/TxInputMessage.tsx b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputMessage/TxInputMessage.tsx new file mode 100644 index 000000000..2de5c924e --- /dev/null +++ b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputMessage/TxInputMessage.tsx @@ -0,0 +1,83 @@ +import { + Address, + Badge, + Collapsible, + Flex, + HStack, + Text, + VStack, + createComponent, +} from '@fuels/ui'; +import NextLink from 'next/link'; + +import { Routes } from '~/routes'; +import { TxIcon } from '~/systems/Transaction/component/TxIcon/TxIcon'; +import type { TxInputMessageProps } from './types'; + +export const TxInputMessage = createComponent< + TxInputMessageProps, + typeof Collapsible +>({ + id: 'TxInputMessage', + render: (_, { input, ...props }) => { + const { sender, recipient, data } = input; + + if (!sender || !recipient) return null; + + return ( + + + + + MESSAGE + + + + + + Message + + +
+
+ + + MESSAGE + + + + + + + + Data + + {data} + + + + ); + }, +}); diff --git a/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputMessage/types.ts b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputMessage/types.ts new file mode 100644 index 000000000..880ca7b11 --- /dev/null +++ b/packages/app-explorer/src/systems/Transaction/component/TxInput/TxInputMessage/types.ts @@ -0,0 +1,11 @@ +import type { GQLTransactionItemFragment } from '@fuel-explorer/graphql/sdk'; +import type { TxInputProps } from '~/systems/Transaction/component/TxInput/types'; + +export type InputMessage = Extract< + NonNullable[number], + { __typename: 'InputMessage' } +>; + +export type TxInputMessageProps = TxInputProps & { + input: InputMessage; +}; diff --git a/packages/app-explorer/src/systems/Transaction/component/TxInput/types.ts b/packages/app-explorer/src/systems/Transaction/component/TxInput/types.ts new file mode 100644 index 000000000..bc8fa6f0e --- /dev/null +++ b/packages/app-explorer/src/systems/Transaction/component/TxInput/types.ts @@ -0,0 +1,6 @@ +import type { GQLTransactionItemFragment } from '@fuel-explorer/graphql/sdk'; +import type { CardProps } from '@fuels/ui'; + +export type TxInputProps = CardProps & { + input: NonNullable[number] | undefined; +}; diff --git a/packages/app-explorer/src/systems/Transaction/component/TxScreen/TxScreenSimple.tsx b/packages/app-explorer/src/systems/Transaction/component/TxScreen/TxScreenSimple.tsx index 8fc9a5fac..efc0b226a 100644 --- a/packages/app-explorer/src/systems/Transaction/component/TxScreen/TxScreenSimple.tsx +++ b/packages/app-explorer/src/systems/Transaction/component/TxScreen/TxScreenSimple.tsx @@ -1,6 +1,6 @@ 'use client'; -import { GQLGroupedInput } from '@fuel-explorer/graphql'; +import type { GQLTransactionItemFragment } from '@fuel-explorer/graphql'; import { Address, Badge, @@ -200,9 +200,18 @@ function ContentMain({ Inputs - {tx?.groupedInputs?.map((input, i) => ( - // here we use only index as key because this component will not change - + {tx?.inputs?.map((input, i) => ( + // here we use index as key because this component will not change + [number] + | undefined + } + /> ))} } diff --git a/packages/app-explorer/src/systems/Transaction/component/TxScripts/TxOperationHeader.tsx b/packages/app-explorer/src/systems/Transaction/component/TxScripts/TxOperationHeader.tsx index 31c398af9..210bb1ce9 100644 --- a/packages/app-explorer/src/systems/Transaction/component/TxScripts/TxOperationHeader.tsx +++ b/packages/app-explorer/src/systems/Transaction/component/TxScripts/TxOperationHeader.tsx @@ -56,12 +56,15 @@ function _TxOperationHeader({ value={formattedValue} className="text-xs tablet:text-sm font-mono" prefix={field.label} - linkProps={{ - as: NextLink, - href: - field?.hrefFactory?.(formattedValue) ?? - `/contract/${formattedValue}/assets`, - }} + linkProps={ + field.type === ReceiptHeaderOperationDataType.HEX_ADDRESS && + field?.hrefFactory + ? { + as: NextLink, + href: field.hrefFactory(formattedValue), + } + : undefined + } /> ) : ( `/account/${value}/assets`, + fieldFallback: 'to', + hrefFactory: Routes.accountAssets, }, ], [GQLReceiptType.Transfer]: [ - { type: ReceiptHeaderOperationDataType.AMOUNT, field: 'amount' }, + { + label: 'ID:', + type: ReceiptHeaderOperationDataType.HEX_ADDRESS, + field: 'id', + }, { label: 'To:', type: ReceiptHeaderOperationDataType.HEX_ADDRESS, field: 'toAddress', - hrefFactory: (value: string) => `/account/${value}/assets`, + fieldFallback: 'to', + hrefFactory: Routes.accountAssets, }, ], [GQLReceiptType.MessageOut]: [ @@ -67,14 +81,14 @@ export const RECEIPT_FIELDS_MAP: Record< type: ReceiptHeaderOperationDataType.HEX_ADDRESS, field: 'sender', requiredField: 'recipient', - hrefFactory: (value: string) => `/account/${value}/assets`, + hrefFactory: Routes.accountAssets, }, { label: 'From:', type: ReceiptHeaderOperationDataType.HEX_ADDRESS, field: 'recipient', requiredField: 'sender', - hrefFactory: (value: string) => `/account/${value}/assets`, + hrefFactory: Routes.accountAssets, }, ], [GQLReceiptType.Log]: [ @@ -91,6 +105,7 @@ export const RECEIPT_FIELDS_MAP: Record< label: 'Contract ID:', type: ReceiptHeaderOperationDataType.HEX_ADDRESS, field: 'contractId', + hrefFactory: Routes.contractAssets, }, ], [GQLReceiptType.Revert]: [ @@ -99,6 +114,7 @@ export const RECEIPT_FIELDS_MAP: Record< label: 'Contract ID:', type: ReceiptHeaderOperationDataType.HEX_ADDRESS, field: 'contractId', + hrefFactory: Routes.contractAssets, }, ], [GQLReceiptType.ReturnData]: [ diff --git a/packages/app-portal/src/systems/Ecosystem/components/EcosystemHeader/EcosystemHeader.tsx b/packages/app-portal/src/systems/Ecosystem/components/EcosystemHeader/EcosystemHeader.tsx index 597535c7d..8d8d13ba7 100644 --- a/packages/app-portal/src/systems/Ecosystem/components/EcosystemHeader/EcosystemHeader.tsx +++ b/packages/app-portal/src/systems/Ecosystem/components/EcosystemHeader/EcosystemHeader.tsx @@ -1,4 +1,4 @@ -import { Button, Flex, Input, Separator } from '@fuels/ui'; +import { Button, Flex, Input, Separator, Switch, Text } from '@fuels/ui'; import { IconSearch } from '@tabler/icons-react'; import { PageTitle } from 'app-commons'; import { tv } from 'tailwind-variants'; @@ -7,10 +7,14 @@ export function EcosystemHeader({ disabled, search, onSearchChange, + onBuildingHiddenChange, + isBuildingHidden, }: { disabled?: boolean; search?: string; + isBuildingHidden?: boolean; onSearchChange?: (value: string) => void; + onBuildingHiddenChange?: (value: boolean) => void; }) { const classes = styles(); @@ -39,7 +43,16 @@ export function EcosystemHeader({ - + +