diff --git a/package.json b/package.json
index fd9552a..2036524 100644
--- a/package.json
+++ b/package.json
@@ -20,8 +20,8 @@
"build:production": "lerna run --scope dashboard build:production",
"build:staging": "lerna run --scope dashboard build:staging",
"build:local": "lerna run --scope dashboard build:local",
- "dev:dashboard-dev": "lerna run --scope dashboard dev:development",
- "dev:dashboard-prod": "lerna run --scope dashboard dev:production",
+ "dev:dashboard-dev": "lerna run --stream --scope dashboard dev:development",
+ "dev:dashboard-prod": "lerna run --stream --scope dashboard dev:production",
"test:dashboard-unit": "lerna run --scope dashboard test:unit",
"cap:init": "git submodule update --init --recursive",
"cap:update": "git submodule update --remote --merge",
diff --git a/packages/dashboard/src/components/Link/index.tsx b/packages/dashboard/src/components/Link/index.tsx
index 1987660..ff0773f 100644
--- a/packages/dashboard/src/components/Link/index.tsx
+++ b/packages/dashboard/src/components/Link/index.tsx
@@ -94,6 +94,24 @@ export const AccountLink = ({
);
+
+export const NamedAccountLink = ({
+ account,
+ name,
+ trim,
+}: {
+ name: string,
+ account: string,
+ trim?: boolean,
+}) => (
+
+ {trim ? trimAccount(name) : name}
+
+);
+
export const NamedLink = ({
url,
name,
diff --git a/packages/dashboard/src/components/Tables/AccountsTable/index.tsx b/packages/dashboard/src/components/Tables/AccountsTable/index.tsx
index 221dd6f..f2437f3 100644
--- a/packages/dashboard/src/components/Tables/AccountsTable/index.tsx
+++ b/packages/dashboard/src/components/Tables/AccountsTable/index.tsx
@@ -2,7 +2,7 @@ import React, { useState, useMemo, useEffect } from 'react';
import { styled } from '@stitched';
import DataTable, { FormatterTypes, TableId } from '@components/Tables/DataTable';
import Title from '@components/Title';
-import { AccountLink, NamedLink } from '@components/Link';
+import { AccountLink, NamedAccountLink } from '@components/Link';
import { getDabMetadata, CanisterMetadata } from '@utils/dab';
import IdentityDab from '@components/IdentityDab';
@@ -31,8 +31,8 @@ const Container = styled('div', {
});
export interface AccountData {
- canister: string,
- name: string,
+ contractId: string,
+ rootCanisterId: string,
}
interface Column {
@@ -41,18 +41,18 @@ interface Column {
}
export const DEFAULT_COLUMN_ORDER: (keyof AccountData)[] = [
- 'name',
- 'canister',
+ 'rootCanisterId',
+ 'contractId',
];
const columns: Column[] = [
{
Header: 'Name',
- accessor: 'name',
+ accessor: 'rootCanisterId',
},
{
- Header: 'Cap Root',
- accessor: 'canister',
+ Header: 'Token contract',
+ accessor: 'contractId',
},
];
@@ -65,6 +65,9 @@ const AccountDab = ({
// Dab metadata handler
useEffect(() => {
+ // TODO: Should this move to the store?
+ // at the moment is called as a "nice-to-have",
+ // not as main business logic...
const getDabMetadataHandler = async () => {
const metadata = await getDabMetadata({
canisterId,
@@ -83,7 +86,7 @@ const AccountDab = ({
return identityInDab
?
- :
+ :
};
const AccountsTable = ({
@@ -98,10 +101,16 @@ const AccountsTable = ({
}) => {
const formatters = useMemo(() => ({
body: {
- canister: (cellValue: string) => ,
- name: (cellValue: string) => ,
+ contractId: (cellValue: string) => {
+ const found = data.find((x) => x.contractId === cellValue);
+
+ if (!found?.rootCanisterId) return '';
+
+ return ;
+ },
+ rootCanisterId: (cellValue: string) => ,
},
- } as FormatterTypes), []);
+ } as FormatterTypes), [data]);
return (
((set) => ({
return;
}
- const pageData = parseUserRootBucketsResponse(response);
+ // Get the Root, Token Contract pair
+ // via promise all for concurrency
+ // TODO: Change to actual implementation once CAP PR's ready
+ const { tokenContractsPairedRoots } = await import('@utils/mocks/tokenContractsCapRoots');
+
+ const pageData = parseUserRootBucketsResponse({
+ ...response,
+ tokenContractsPairedRoots,
+ });
set((state: AccountStore) => ({
accounts: response,
diff --git a/packages/dashboard/src/utils/account.test.ts b/packages/dashboard/src/utils/account.test.ts
index 3d8d3f1..b7ab298 100644
--- a/packages/dashboard/src/utils/account.test.ts
+++ b/packages/dashboard/src/utils/account.test.ts
@@ -144,12 +144,18 @@ describe('Account', () => {
});
it('should parse the data', () => {
- const parsed = parseUserRootBucketsResponse(response);
+ const parsed = parseUserRootBucketsResponse({
+ ...response,
+ tokenContractsPairedRoots: {},
+ });
expect(parsed).toBeTruthy();
});
it('should parse the data to the expected object type', () => {
- const parsed = parseUserRootBucketsResponse(response);
+ const parsed = parseUserRootBucketsResponse({
+ ...response,
+ tokenContractsPairedRoots: {},
+ });
const expectedData = [{
canister: identity.toText(),
age: undefined,
@@ -172,7 +178,10 @@ describe('Account', () => {
});
it('should return empty list', () => {
- const parsed = parseUserRootBucketsResponse(response);
+ const parsed = parseUserRootBucketsResponse({
+ ...response,
+ tokenContractsPairedRoots: {},
+ });
const expectedData: any[] = [];
expect(parsed).toStrictEqual(expectedData);
});
@@ -192,7 +201,10 @@ describe('Account', () => {
});
it('should return empty list', () => {
- const parsed = parseUserRootBucketsResponse(response);
+ const parsed = parseUserRootBucketsResponse({
+ ...response,
+ tokenContractsPairedRoots: {},
+ });
const expectedData: any[] = [];
expect(parsed).toStrictEqual(expectedData);
});
diff --git a/packages/dashboard/src/utils/account.ts b/packages/dashboard/src/utils/account.ts
index 03db571..ac0a564 100644
--- a/packages/dashboard/src/utils/account.ts
+++ b/packages/dashboard/src/utils/account.ts
@@ -5,6 +5,7 @@ import {
} from '../components/BookmarkPanel';
import { Principal } from "@dfinity/principal";
import { AccountData } from '@components/Tables/AccountsTable';
+// import principal from './principal';
export const hashTrimmer = (hash: string) => {
const size = 6;
@@ -52,20 +53,47 @@ export const createBookmarkExpandHandler = ({
return bookmarkExpandHandler;
};
+type TokenContractsPairedRoots = Record;
+
export const parseUserRootBucketsResponse = ({
contracts,
+ tokenContractsPairedRoots,
}: {
contracts?: Principal[],
+ tokenContractsPairedRoots: TokenContractsPairedRoots,
}): AccountData[] | [] => {
if (!contracts || !Array.isArray(contracts) || !contracts.length) return [];
return contracts
- .map((principal: Principal) => ({
- canister: principal.toText(),
- // TODO: there's a call to Dab that requires
- // the canister id, so this should be handle a bit differently
- // but for now pass the canister id and the call to dab
- // is made in the scope of the datatable generation
- name: principal.toText(),
- }));
+ .filter(
+ (principal: Principal) => getTokenContractCanisterIdByRoot(
+ tokenContractsPairedRoots,
+ principal.toText(),
+ )
+ )
+ .map((principal: Principal) => {
+ const rootCanisterId = principal.toText();
+ const contractId = getTokenContractCanisterIdByRoot(
+ tokenContractsPairedRoots,
+ rootCanisterId,
+ ) as string;
+
+ return {
+ contractId,
+ rootCanisterId,
+ }
+ });
}
+
+const getTokenContractCanisterIdByRoot = (
+ tokenContractsPairedRoots: TokenContractsPairedRoots,
+ rootCanisterId: string,
+) => {
+ if (!tokenContractsPairedRoots[rootCanisterId]) {
+ console.warn(`Oops! Token contract not found for root ${rootCanisterId}, omitted.` );
+
+ return false;
+ }
+
+ return tokenContractsPairedRoots[rootCanisterId];
+}
\ No newline at end of file
diff --git a/packages/dashboard/src/utils/mocks/accountsMockData.ts b/packages/dashboard/src/utils/mocks/accountsMockData.ts
index 5553f5c..d6b3e78 100644
--- a/packages/dashboard/src/utils/mocks/accountsMockData.ts
+++ b/packages/dashboard/src/utils/mocks/accountsMockData.ts
@@ -4,23 +4,24 @@ import { AccountData } from '@components/Tables/AccountsTable';
export const columns = [
{
Header: 'Name',
- accessor: 'name',
+ accessor: 'rootCanisterId',
},
{
Header: 'Canister',
- accessor: 'canister',
+ accessor: 'contractId',
},
];
const NUM_TO_GENERATE = 10;
export const generateData = (count: number = NUM_TO_GENERATE) => {
-
+ // TODO: contract id was introduced
+ // this needs to be refactored at some point
const data: AccountData[] = [...new Array(count)].map(() => {
const principal = generateRandomPrincipal();
const accountData = {
- canister: principal.toText(),
- name: 'CanisterX'
+ contractId: principal.toText(),
+ rootCanisterId: 'CanisterX'
};
return accountData;
diff --git a/packages/dashboard/src/utils/mocks/tokenContractsCapRoots.ts b/packages/dashboard/src/utils/mocks/tokenContractsCapRoots.ts
new file mode 100644
index 0000000..8d6b527
--- /dev/null
+++ b/packages/dashboard/src/utils/mocks/tokenContractsCapRoots.ts
@@ -0,0 +1,43 @@
+// Key is Root, value is token contract
+// TODO: rename as rootsPairedTokenContract?
+export const tokenContractsPairedRoots = {
+ 'cvfe7-zqaaa-aaaah-qceqa-cai': 'qcg3w-tyaaa-aaaah-qakea-cai',
+ 'hj662-syaaa-aaaah-qcepq-cai': 'njgly-uaaaa-aaaah-qb6pa-cai',
+ '2oigl-gaaaa-aaaah-qcgja-cai': 'e3izy-jiaaa-aaaah-qacbq-cai',
+ '2jja7-lyaaa-aaaah-qcgjq-cai': 'nbg4r-saaaa-aaaah-qap7a-cai',
+ '24ors-kqaaa-aaaah-qcgka-cai': 'bxdf4-baaaa-aaaah-qaruq-cai',
+ '23pxg-hiaaa-aaaah-qcgkq-cai': 'uzhxd-ziaaa-aaaah-qanaq-cai',
+ '2sm42-raaaa-aaaah-qcgla-cai': 'tde7l-3qaaa-aaaah-qansa-cai',
+ '2vn2o-4yaaa-aaaah-qcglq-cai': 'gevsk-tqaaa-aaaah-qaoca-cai',
+ '3yd6a-tqaaa-aaaah-qcgma-cai': 'owuqd-dyaaa-aaaah-qapxq-cai',
+ '37cyu-6iaaa-aaaah-qcgmq-cai': '3db6u-aiaaa-aaaah-qbjbq-cai',
+ '3wbti-iaaaa-aaaah-qcgna-cai': 'd3ttm-qaaaa-aaaai-qam4a-cai',
+ '3rav4-fyaaa-aaaah-qcgnq-cai': '73xld-saaaa-aaaah-qbjya-cai',
+ '3eher-eqaaa-aaaah-qcgoa-cai': 'xkbqi-2qaaa-aaaah-qbpqq-cai',
+ '3dgcf-jiaaa-aaaah-qcgoq-cai': '6olkk-7iaaa-aaaah-qboaa-cai',
+ '3kfjz-7aaaa-aaaah-qcgpa-cai': 'kss7i-hqaaa-aaaah-qbvmq-cai',
+ '3nepn-syaaa-aaaah-qcgpq-cai': 'k4qsa-4aaaa-aaaah-qbvnq-cai',
+ '6r7vi-zqaaa-aaaah-qcgqa-cai': 'hdxhu-qqaaa-aaaai-aasnq-cai',
+ '6w6t4-uiaaa-aaaah-qcgqq-cai': 'wxi2q-oiaaa-aaaaj-qab2q-cai',
+ '675ya-caaaa-aaaah-qcgra-cai': 'sr4qi-vaaaa-aaaah-qcaaq-cai',
+ '6y46u-pyaaa-aaaah-qcgrq-cai': 'cihkf-qyaaa-aaaah-qb7jq-cai',
+ '6n3pz-oqaaa-aaaah-qcgsa-cai': 'q6hjz-kyaaa-aaaah-qcama-cai',
+ '6k2jn-diaaa-aaaah-qcgsq-cai': 'ahl3d-xqaaa-aaaaj-qacca-cai',
+ '6dzcr-vaaaa-aaaah-qcgta-cai': 'er7d4-6iaaa-aaaaj-qac2q-cai',
+ '6eyef-yyaaa-aaaah-qcgtq-cai': 'lhq4n-3yaaa-aaaai-qaniq-cai',
+ '7jwal-xqaaa-aaaah-qcgua-cai': 'nfvlz-jaaaa-aaaah-qcciq-cai',
+ '7oxg7-2iaaa-aaaah-qcguq-cai': 'oeee4-qaaaa-aaaak-qaaeq-cai',
+ '7hund-maaaa-aaaah-qcgva-cai': 'pnpu4-3aaaa-aaaah-qcceq-cai',
+ '7avlx-byaaa-aaaah-qcgvq-cai': 'bid2t-gyaaa-aaaah-qcdea-cai',
+ '7vs22-aqaaa-aaaah-qcgwa-cai': 'btggw-4aaaa-aaaah-qcdgq-cai',
+ '7st4o-niaaa-aaaah-qcgwq-cai': 'dv6u3-vqaaa-aaaah-qcdlq-cai',
+ '73qxs-3aaaa-aaaah-qcgxa-cai': 'crt3j-mqaaa-aaaah-qcdnq-cai',
+ '74rrg-wyaaa-aaaah-qcgxq-cai': 'cnxby-3qaaa-aaaah-qcdpq-cai',
+ '5bm7o-fqaaa-aaaah-qcgya-cai': 'ckwhm-wiaaa-aaaah-qcdpa-cai',
+ '5gnz2-iiaaa-aaaah-qcgyq-cai': 'cdvmq-aaaaa-aaaah-qcdoq-cai',
+ '5posg-6aaaa-aaaah-qcgza-cai': 'b5el6-hqaaa-aaaah-qcdhq-cai',
+ '5ipus-tyaaa-aaaah-qcgzq-cai': 'gyuaf-kqaaa-aaaah-qceka-cai',
+ '55if7-sqaaa-aaaah-qcg2a-cai': 'dknxi-2iaaa-aaaah-qceuq-cai',
+ '52jdl-7iaaa-aaaah-qcg2q-cai': 'bzsui-sqaaa-aaaah-qce2a-cai',
+ '5tkix-jaaaa-aaaah-qcg3a-cai': 'ep54t-xiaaa-aaaah-qcdza-cai'
+}