diff --git a/libs/ledger/jest.config.ts b/libs/ledger/jest.config.ts
index deafd8379..3c3e0b5cd 100644
--- a/libs/ledger/jest.config.ts
+++ b/libs/ledger/jest.config.ts
@@ -12,4 +12,5 @@ export default {
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/libs/ledger',
+ setupFilesAfterEnv: ['./src/setup-tests.ts'],
};
diff --git a/libs/ledger/src/lib/ledger-entries-data-provider.ts b/libs/ledger/src/lib/ledger-entries-data-provider.ts
index 0f8a31f69..893214335 100644
--- a/libs/ledger/src/lib/ledger-entries-data-provider.ts
+++ b/libs/ledger/src/lib/ledger-entries-data-provider.ts
@@ -30,7 +30,10 @@ export type LedgerEntry = LedgerEntryFragment & {
};
export type AggregatedLedgerEntriesEdge = Schema.AggregatedLedgerEntriesEdge;
-export type AggregatedLedgerEntriesNode = AggregatedLedgerEntriesEdge & {
+export type AggregatedLedgerEntriesNode = Omit<
+ AggregatedLedgerEntriesEdge,
+ 'node'
+> & {
node: LedgerEntry;
};
diff --git a/libs/ledger/src/lib/ledger-entries.mock.ts b/libs/ledger/src/lib/ledger-entries.mock.ts
index 8e31a31e9..1033a8c0c 100644
--- a/libs/ledger/src/lib/ledger-entries.mock.ts
+++ b/libs/ledger/src/lib/ledger-entries.mock.ts
@@ -32,7 +32,7 @@ export const ledgerEntriesQuery = (
return merge(defaultResult, override);
};
-const ledgerEntries: LedgerEntryFragment[] = [
+export const ledgerEntries: LedgerEntryFragment[] = [
{
vegaTime: '1669224476734364000',
quantity: '0',
@@ -180,7 +180,6 @@ const ledgerEntries: LedgerEntryFragment[] = [
toAccountBalance: '0',
fromAccountBalance: '0',
},
-
{
vegaTime: '2022-11-24T12:41:22.054428Z',
quantity: '1000000000',
diff --git a/libs/ledger/src/lib/ledger-export-link.spec.tsx b/libs/ledger/src/lib/ledger-export-link.spec.tsx
new file mode 100644
index 000000000..8c623ccfa
--- /dev/null
+++ b/libs/ledger/src/lib/ledger-export-link.spec.tsx
@@ -0,0 +1,85 @@
+import { act, render, screen, waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { LedgerExportLink } from './ledger-export-link';
+import * as Types from '@vegaprotocol/types';
+import { ledgerEntries } from './ledger-entries.mock';
+import type { LedgerEntry } from './ledger-entries-data-provider';
+
+const VEGA_URL = 'https://vega-url.co.uk/querystuff';
+const mockEnvironment = jest.fn(() => VEGA_URL);
+jest.mock('@vegaprotocol/environment', () => ({
+ useEnvironment: jest.fn(() => mockEnvironment()),
+}));
+
+const asset = {
+ id: 'assetID',
+ name: 'assetName',
+ symbol: 'assetSymbol',
+ decimals: 1,
+ quantum: '1',
+ status: Types.AssetStatus,
+ source: {
+ __typename: 'ERC20',
+ contractAddress: 'contractAddres',
+ lifetimeLimit: 'lifetimeLimit',
+ withdrawThreshold: 'withdraw',
+ },
+};
+
+describe('LedgerExportLink', () => {
+ const partyId = 'partyId';
+ const entries = ledgerEntries.map((entry) => {
+ return {
+ ...entry,
+ asset: entry.assetId
+ ? {
+ ...asset,
+ id: entry.assetId,
+ name: `name ${entry.assetId}`,
+ symbol: `symbol ${entry.assetId}`,
+ }
+ : null,
+ marketSender: null,
+ marketReceiver: null,
+ } as LedgerEntry;
+ });
+
+ it('should be properly rendered', async () => {
+ render();
+ await waitFor(() => {
+ expect(screen.getByRole('link')).toBeInTheDocument();
+ expect(screen.getByRole('link')).toHaveAttribute(
+ 'href',
+ `https://vega-url.co.uk/api/v2/ledgerentry/export?partyId=${partyId}&assetId=asset-id`
+ );
+ expect(
+ screen.getByRole('button', { name: /^symbol asset-id/ })
+ ).toBeInTheDocument();
+ });
+ });
+ it('should be properly change link url', async () => {
+ render();
+ await waitFor(() => {
+ expect(
+ screen.getByRole('button', { name: /^symbol asset-id/ })
+ ).toBeInTheDocument();
+ });
+ act(() => {
+ userEvent.click(screen.getByRole('button', { name: /^symbol asset-id/ }));
+ });
+ await waitFor(() => {
+ expect(screen.getByRole('menu')).toBeInTheDocument();
+ });
+ act(() => {
+ userEvent.click(
+ screen.getByRole('menuitem', { name: /^symbol asset-id-2/ })
+ );
+ });
+ await waitFor(() => {
+ expect(screen.getByRole('link')).toHaveAttribute(
+ 'href',
+ `https://vega-url.co.uk/api/v2/ledgerentry/export?partyId=${partyId}&assetId=asset-id-2`
+ );
+ });
+ });
+});
diff --git a/libs/ledger/src/lib/ledger-export-link.tsx b/libs/ledger/src/lib/ledger-export-link.tsx
new file mode 100644
index 000000000..9de96bbc9
--- /dev/null
+++ b/libs/ledger/src/lib/ledger-export-link.tsx
@@ -0,0 +1,71 @@
+import type { LedgerEntry } from './ledger-entries-data-provider';
+import { useMemo, useState } from 'react';
+import { useEnvironment } from '@vegaprotocol/environment';
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+ Link,
+ Button,
+} from '@vegaprotocol/ui-toolkit';
+import { t } from '@vegaprotocol/i18n';
+
+const getProtoHost = (vegaurl: string) => {
+ const loc = new URL(vegaurl);
+ return `${loc.protocol}//${loc.host}`;
+};
+
+export const LedgerExportLink = ({
+ partyId,
+ entries,
+}: {
+ partyId: string;
+ entries: LedgerEntry[];
+}) => {
+ const assets = entries.reduce((aggr, item) => {
+ if (item.asset && !(item.asset.id in aggr)) {
+ aggr[item.asset.id] = item.asset.symbol;
+ }
+ return aggr;
+ }, {} as Record);
+ const [assetId, setAssetId] = useState(Object.keys(assets)[0]);
+ const VEGA_URL = useEnvironment((store) => store.VEGA_URL);
+ const protohost = VEGA_URL ? getProtoHost(VEGA_URL) : '';
+
+ const assetDropDown = useMemo(() => {
+ return (
+ {assets[assetId]}}
+ >
+
+ {Object.keys(assets).map((assetKey) => (
+ setAssetId(assetKey)}
+ >
+ {assets[assetKey]}
+
+ ))}
+
+
+ );
+ }, [assetId, assets]);
+
+ if (!protohost) {
+ return null;
+ }
+ return (
+
+
Export all
+ {assetDropDown}
+
+
+
+
+ );
+};
diff --git a/libs/ledger/src/lib/ledger-manager.tsx b/libs/ledger/src/lib/ledger-manager.tsx
index a6771d2e1..a4ca28c2f 100644
--- a/libs/ledger/src/lib/ledger-manager.tsx
+++ b/libs/ledger/src/lib/ledger-manager.tsx
@@ -3,12 +3,13 @@ import type * as Schema from '@vegaprotocol/types';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import type { FilterChangedEvent } from 'ag-grid-community';
import type { AgGridReact } from 'ag-grid-react';
-import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { useCallback, useEffect, useRef, useState } from 'react';
import { subDays, formatRFC3339 } from 'date-fns';
import type { AggregatedLedgerEntriesNode } from './ledger-entries-data-provider';
import { useLedgerEntriesDataProvider } from './ledger-entries-data-provider';
import { LedgerTable } from './ledger-table';
import type * as Types from '@vegaprotocol/types';
+import { LedgerExportLink } from './ledger-export-link';
export interface Filter {
vegaTime?: {
@@ -22,6 +23,7 @@ const defaultFilter = {
value: { start: formatRFC3339(subDays(Date.now(), 7)) },
},
};
+
export const LedgerManager = ({ partyId }: { partyId: string }) => {
const gridRef = useRef(null);
const [filter, setFilter] = useState(defaultFilter);
@@ -55,6 +57,9 @@ export const LedgerManager = ({ partyId }: { partyId: string }) => {
rowData={extractedData}
onFilterChanged={onFilterChanged}
/>
+ {extractedData && (
+
+ )}
(
(props, ref) => {
return (