From 7d8b6049ad3e0bcaecba6b373612076ba2566ba8 Mon Sep 17 00:00:00 2001 From: Kieran Hall Date: Thu, 28 Nov 2024 10:04:37 +0100 Subject: [PATCH] explorer: Look-up transaction in mempool Resolves #2877 --- explorer/CHANGELOG.md | 2 + .../lib/components/data-card/DataCard.svelte | 1 - .../TransactionDetails.svelte | 5 +- .../src/lib/dusk/components/banner/Banner.css | 46 +++++++++++++++++ .../lib/dusk/components/banner/Banner.svelte | 51 +++++++++++++++++++ .../lib/dusk/components/dusk.components.d.ts | 2 + explorer/src/lib/dusk/components/index.js | 1 + .../src/lib/mock-data/gql-chain-info.d.ts | 1 - explorer/src/lib/services/duskAPI.js | 18 ++++++- explorer/src/lib/services/gql-queries.js | 9 +++- .../transactions/transaction/+page.svelte | 29 +++++++---- explorer/src/style/dusk/colors.css | 9 ++++ explorer/src/style/dusk/language.css | 24 +++++++-- 13 files changed, 175 insertions(+), 23 deletions(-) create mode 100644 explorer/src/lib/dusk/components/banner/Banner.css create mode 100644 explorer/src/lib/dusk/components/banner/Banner.svelte diff --git a/explorer/CHANGELOG.md b/explorer/CHANGELOG.md index ea6c5d33ce..9b796d9d8c 100644 --- a/explorer/CHANGELOG.md +++ b/explorer/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add decode feature for `memo` field [#2527] - Add top node info in StatisticsPanel [#2613] - Add Provisioners page [#2649] +- Check if transaction exists in mempool [#2877] ### Changed @@ -96,6 +97,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#2662]: https://github.com/dusk-network/rusk/issues/2662 [#3038]: https://github.com/dusk-network/rusk/issues/3038 [#3064]: https://github.com/dusk-network/rusk/issues/3064 +[#2877]: https://github.com/dusk-network/rusk/issues/2877 diff --git a/explorer/src/lib/components/data-card/DataCard.svelte b/explorer/src/lib/components/data-card/DataCard.svelte index a2089213e8..cba1fb3bd2 100644 --- a/explorer/src/lib/components/data-card/DataCard.svelte +++ b/explorer/src/lib/components/data-card/DataCard.svelte @@ -26,7 +26,6 @@ export let className = undefined; $: classes = makeClassName(["data-card", className]); - $: hasEmptyData = Array.isArray(data) && data.length === 0; diff --git a/explorer/src/lib/components/transaction-details/TransactionDetails.svelte b/explorer/src/lib/components/transaction-details/TransactionDetails.svelte index b498f3c09b..f1292a78e6 100644 --- a/explorer/src/lib/components/transaction-details/TransactionDetails.svelte +++ b/explorer/src/lib/components/transaction-details/TransactionDetails.svelte @@ -57,8 +57,6 @@ /** @type {boolean} */ let isMemoDecoded = false; - $: classes = makeClassName(["transaction-details", className]); - onMount(() => { const resizeObserver = new ResizeObserver((entries) => { const entry = entries[0]; @@ -70,6 +68,9 @@ return () => resizeObserver.disconnect(); }); + + $: classes = makeClassName(["transaction-details", className]); + // $: isPending = !!pendingData; + import { makeClassName } from "$lib/dusk/string"; + import { Icon } from "$lib/dusk/components"; + import { + mdiAlertCircleOutline, + mdiAlertDecagramOutline, + mdiAlertOutline, + } from "@mdi/js"; + + import "./Banner.css"; + + /** @type {string} */ + export let title; + + /** @type {String | Undefined} */ + export let className = undefined; + + /** @type {BannerVariant} */ + export let variant = "info"; + + function getBannerIconPath() { + switch (variant) { + case "warning": + return mdiAlertOutline; + case "error": + return mdiAlertDecagramOutline; + default: + return mdiAlertCircleOutline; + } + } + + $: classes = makeClassName([ + "dusk-banner", + `dusk-banner--${variant}`, + className, + ]); + + +
+ +
+ {title} + +

No banner content provided.

+
+
+
diff --git a/explorer/src/lib/dusk/components/dusk.components.d.ts b/explorer/src/lib/dusk/components/dusk.components.d.ts index 8fb8958889..57c0ceb351 100644 --- a/explorer/src/lib/dusk/components/dusk.components.d.ts +++ b/explorer/src/lib/dusk/components/dusk.components.d.ts @@ -1,5 +1,7 @@ type BadgeVariant = "neutral" | "success" | "warning" | "error" | "alt"; +type BannerVariant = "info" | "warning" | "error"; + type ButtonSize = "normal" | "small"; type ButtonVariant = "primary" | "secondary" | "tertiary"; diff --git a/explorer/src/lib/dusk/components/index.js b/explorer/src/lib/dusk/components/index.js index d3066574f1..2a0ff22a84 100644 --- a/explorer/src/lib/dusk/components/index.js +++ b/explorer/src/lib/dusk/components/index.js @@ -1,5 +1,6 @@ export { default as Anchor } from "./anchor/Anchor.svelte"; export { default as AnchorButton } from "./anchor-button/AnchorButton.svelte"; +export { default as Banner } from "./banner/Banner.svelte"; export { default as Badge } from "./badge/Badge.svelte"; export { default as Button } from "./button/Button.svelte"; export { default as Card } from "./card/Card.svelte"; diff --git a/explorer/src/lib/mock-data/gql-chain-info.d.ts b/explorer/src/lib/mock-data/gql-chain-info.d.ts index 14cf2f6eb2..44ccf46480 100644 --- a/explorer/src/lib/mock-data/gql-chain-info.d.ts +++ b/explorer/src/lib/mock-data/gql-chain-info.d.ts @@ -48,7 +48,6 @@ type GQLTransaction = { gasLimit: number; gasPrice: number; id: string; - isDeploy: boolean; memo: string; txType: string; }; diff --git a/explorer/src/lib/services/duskAPI.js b/explorer/src/lib/services/duskAPI.js index 2f340fe89c..f98e357274 100644 --- a/explorer/src/lib/services/duskAPI.js +++ b/explorer/src/lib/services/duskAPI.js @@ -230,12 +230,26 @@ const duskAPI = { /** * @param {string} id - * @returns {Promise} + * @returns {Promise} */ getTransaction(id) { return gqlGet(gqlQueries.getTransactionQueryInfo(id)) .then(getKey("tx")) - .then(transformTransaction); + .then((tx) => { + if (tx === null) { + return gqlGet(gqlQueries.getMempoolTx(id)) + .then(getKey("mempoolTx")) + .then((mempoolTx) => { + if (mempoolTx) { + return "This transaction is currently in the mempool and has not yet been confirmed. The transaction details will be displayed after confirmation."; + } else { + throw new Error("Transaction not found"); + } + }); + } else { + return transformTransaction(tx); + } + }); }, /** diff --git a/explorer/src/lib/services/gql-queries.js b/explorer/src/lib/services/gql-queries.js index 07d6f15317..f2fc6b3bb5 100644 --- a/explorer/src/lib/services/gql-queries.js +++ b/explorer/src/lib/services/gql-queries.js @@ -15,7 +15,6 @@ fragment TransactionInfo on SpentTransaction { gasLimit, gasPrice, id, - isDeploy, memo txType } @@ -86,6 +85,12 @@ export const getLatestChainQueryInfo = (amount) => ({ variables: { amount }, }); +/** @param {string} id */ +export const getMempoolTx = (id) => ({ + query: "query($id: String!) { mempoolTx(hash: $id) { json } }", + variables: { id }, +}); + /** @param {string} id */ export const getTransactionQueryInfo = (id) => ({ query: ` @@ -106,7 +111,7 @@ export const getTransactionsQueryInfo = (amount) => ({ /** @param {string} id */ export const getTransactionDetailsQueryInfo = (id) => ({ - query: "query($id: String!) { tx(hash: $id) { tx {json} } }", + query: "query($id: String!) { tx(hash: $id) { tx { json } } }", variables: { id }, }); diff --git a/explorer/src/routes/transactions/transaction/+page.svelte b/explorer/src/routes/transactions/transaction/+page.svelte index 300408e53f..8c207b9ab5 100644 --- a/explorer/src/routes/transactions/transaction/+page.svelte +++ b/explorer/src/routes/transactions/transaction/+page.svelte @@ -2,16 +2,17 @@ import { onMount } from "svelte"; import { navigating, page } from "$app/stores"; import { TransactionDetails } from "$lib/components/"; + import { Banner } from "$lib/dusk/components/"; import { duskAPI } from "$lib/services"; import { marketDataStore } from "$lib/stores"; import { createDataStore } from "$lib/dusk/svelte-stores"; + const id = $page.url.searchParams.get("id"); const dataStore = createDataStore(duskAPI.getTransaction); const payloadStore = createDataStore(duskAPI.getTransactionDetails); - const getTransaction = () => { - dataStore.getData($page.url.searchParams.get("id")); - payloadStore.getData($page.url.searchParams.get("id")); + dataStore.getData(id); + payloadStore.getData(id); }; onMount(getTransaction); @@ -28,12 +29,18 @@
- + {#if typeof data === "string"} + + {data} + + {:else} + + {/if}
diff --git a/explorer/src/style/dusk/colors.css b/explorer/src/style/dusk/colors.css index 9359f710fe..0bd5a03ee2 100644 --- a/explorer/src/style/dusk/colors.css +++ b/explorer/src/style/dusk/colors.css @@ -27,4 +27,13 @@ --warning: #ffcf23; --error: #ed254e; --info: #71b1ff; + + --success-500: #16db93; + --success-700: #0f9363; + --warning-500: #ffcf23; + --warning-700: #d1a300; + --error-500: #ed254e; + --error-700: #8e112c; + --info-500: #71b1ff; + --info-700: #0863d1; } diff --git a/explorer/src/style/dusk/language.css b/explorer/src/style/dusk/language.css index 5aab2e6bb3..d7a8edd410 100644 --- a/explorer/src/style/dusk/language.css +++ b/explorer/src/style/dusk/language.css @@ -10,10 +10,14 @@ --secondary-color-variant-light: var(--cornflower-light); --surface-color: var(--magnolia); --danger-color: var(--error); - --error-color: var(--error); - --info-color: var(--info); - --success-color: var(--success); - --warning-color: var(--warning); + --error-color: var(--error-500); + --error-color-variant-dark: var(--error-700); + --info-color: var(--info-500); + --info-color-variant-dark: var(--info-700); + --success-color: var(--success-500); + --success-color-variant-dark: var(--success-700); + --warning-color: var(--warning-500); + --warning-color-variant-dark: var(--warning-700); --on-background-color: var(--smokey-black); --on-primary-color: var(--light-grey); @@ -100,6 +104,12 @@ /* Dividers */ --divider-color-primary: var(--taupe-grey); + + /* Banner */ + + --banner-info-color: var(--info-color-variant-dark); + --banner-warning-color: var(--warning-color-variant-dark); + --banner-error-color: var(--error-color-variant-dark); } :root.dark { @@ -134,4 +144,10 @@ --checkbox-control-border-color: var(--light-grey); --checkbox-control-checked-bg-color: var(--light-grey); + + /* Banner */ + + --banner-info-color: var(--info-color); + --banner-warning-color: var(--warning-color); + --banner-error-color: var(--error-color); }