Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wallet): update frontend with new asset account data models #388

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a88e302
add icrc1 token to orbit scripts
olaszakos Oct 15, 2024
36d6808
icrc1 support for accounts
olaszakos Oct 15, 2024
9d9501e
make and list transfers
olaszakos Oct 16, 2024
b549bc1
add/remove asssets from the UI
olaszakos Oct 17, 2024
6fd4023
add `from_asset: Asset` to TransferOperation; fix tests
olaszakos Oct 18, 2024
e3cf2c4
fix lints; persist canbench;
olaszakos Oct 18, 2024
fffed49
fix account page requests and duplicated name
olaszakos Oct 21, 2024
837e94d
asset in use shouldnt get removed
olaszakos Oct 21, 2024
4f79f82
make index canister id optional; re-add icp metadata form fields
olaszakos Oct 21, 2024
5d52805
unified address display
olaszakos Oct 22, 2024
757fe17
update request operation views
olaszakos Oct 22, 2024
61b84b7
update locales
olaszakos Oct 22, 2024
ea1d88a
fix existnig tests
olaszakos Oct 22, 2024
b4dc470
format and fix lints
olaszakos Oct 22, 2024
5cf7730
add some frontend tests
olaszakos Oct 22, 2024
c0062c5
hide ICP related metadata keys in editor
olaszakos Oct 24, 2024
7620ecd
Update core/station/api/spec.did
olaszakos Oct 24, 2024
79e60e4
Update apps/wallet/src/pages/AccountAssetPage.vue
olaszakos Oct 24, 2024
7a0dd50
Update apps/wallet/src/components/accounts/BatchTransfersActionBtn.vue
olaszakos Oct 24, 2024
bc5b7b7
Update apps/wallet/src/components/ShortenedAddress.vue
olaszakos Oct 24, 2024
a0aa37d
fix typo in `hexStringToUint8Array`
olaszakos Oct 24, 2024
c4ca6a8
run dfx generate
olaszakos Oct 24, 2024
fb27f4b
run pnpm format
olaszakos Oct 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,6 @@ jobs:
validate-node:
name: 'validate-node:required'
runs-on: ubuntu-latest
# disable until the frontend is ready
if: false
steps:
- name: 'Checkout'
uses: actions/checkout@v4
Expand Down
11 changes: 6 additions & 5 deletions apps/wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@
"format": "concurrently -n prettier,eslint -c auto \"prettier --ignore-path ../../.prettierignore --write .\" \"eslint --ext .js,.vue,.ts,.cjs --fix .\""
},
"dependencies": {
"@dfinity/agent": "1.4.0",
"@dfinity/auth-client": "1.4.0",
"@dfinity/candid": "1.4.0",
"@dfinity/identity": "1.4.0",
"@dfinity/principal": "1.4.0",
"@dfinity/agent": "2.1.2",
"@dfinity/auth-client": "2.1.2",
"@dfinity/candid": "2.1.2",
"@dfinity/identity": "2.1.2",
"@dfinity/principal": "2.1.2",
"@dfinity/ledger-icrc": "2.6.1",
"@mdi/font": "7.4.47",
"@mdi/js": "7.4.47",
"buffer": "6.0.3",
Expand Down
20 changes: 20 additions & 0 deletions apps/wallet/src/components/ShortenedAddress.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<template>
<TextOverflow
v-if="format === AddressFormat.ICRC1"
:text="address"
:overflow-position="shortenIcrc1Address"
></TextOverflow>

<TextOverflow v-else :text="address" :max-length="32"></TextOverflow>
</template>

<script setup lang="ts">
import { AddressFormat } from '~/types/chain.types';
import TextOverflow from './TextOverflow.vue';
import { shortenIcrc1Address } from '~/utils/asset.utils';

defineProps<{
address: string;
format: AddressFormat | string | undefined;
}>();
</script>
22 changes: 13 additions & 9 deletions apps/wallet/src/components/TextOverflow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const props = withDefaults(
text: string;
maxLength?: number;
overflowText?: string;
overflowPosition?: 'start' | 'middle' | 'end';
overflowPosition?: 'start' | 'middle' | 'end' | ((input: string) => string);
}>(),
{
maxLength: 18,
Expand All @@ -40,15 +40,19 @@ const truncatedText = computed(() => {
}`;
}

const overflowLengthStart = Math.ceil(props.overflowText.length / 2);
const overflowLengthEnd = Math.floor(props.overflowText.length / 2);
const start = Math.ceil((props.maxLength - 1) / 2) - overflowLengthStart;
const end = Math.floor((props.maxLength - 1) / 2) - overflowLengthEnd;
if (props.overflowPosition === 'middle') {
const overflowLengthStart = Math.ceil(props.overflowText.length / 2);
const overflowLengthEnd = Math.floor(props.overflowText.length / 2);
const start = Math.ceil((props.maxLength - 1) / 2) - overflowLengthStart;
const end = Math.floor((props.maxLength - 1) / 2) - overflowLengthEnd;

return `${props.text.slice(0, start)}${props.overflowText}${props.text.slice(
props.text.length - end,
props.text.length,
)}`;
return `${props.text.slice(0, start)}${props.overflowText}${props.text.slice(
props.text.length - end,
props.text.length,
)}`;
}

return props.overflowPosition(props.text);
});

const handleCopy = (event: ClipboardEvent): void => {
Expand Down
21 changes: 21 additions & 0 deletions apps/wallet/src/components/accounts/AccountAssetsCell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
{{ assetNames.join(', ') }}
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { useStationStore } from '~/stores/station.store';

const props = defineProps<{
assetIds: string[];
}>();

const station = useStationStore();

const assetNames = computed(() => {
return props.assetIds.map(
id =>
station.configuration.details.supported_assets.find(token => token.id === id)?.symbol || id,
);
});
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,8 @@ const saveChangesToExistingAccount = async (accountId: UUID): Promise<Request> =

const createNewAccount = async (): Promise<Request> => {
const changes: Partial<AddAccountOperationInput> = {};
changes.assets = assertAndReturn(wizard.value.configuration.assets, 'assets');
changes.name = assertAndReturn(wizard.value.configuration.name, 'name');
changes.blockchain = assertAndReturn(wizard.value.configuration.blockchain, 'blockchain');
changes.standard = assertAndReturn(wizard.value.configuration.standard, 'standard');
changes.configs_request_policy = wizard.value.request_policy.configurationRule
? [wizard.value.request_policy.configurationRule]
: [];
Expand Down
65 changes: 65 additions & 0 deletions apps/wallet/src/components/accounts/AddAccountAssetBtn.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<template>
<VBtn
v-bind="$attrs"
:size="props.size.value"
:variant="props.variant.value"
:icon="props.icon.value && !props.text.value"
:color="props.color.value"
@click="open = true"
>
<VIcon v-if="props.icon.value" :icon="props.icon.value" />
<slot name="default">
<span v-if="props.text">{{ props.text.value }}</span>
</slot>
<VIcon v-if="props.appendIcon.value" :icon="props.appendIcon.value" />
</VBtn>

<AddAccountAssetDialog
:account="props.account.value"
:open="open"
:readonly="props.readonly.value"
@update:open="
openEvent => {
open = openEvent;

emit('opened', openEvent);
}
"
/>
</template>
<script lang="ts" setup>
import { ref, toRefs } from 'vue';
import { VBtn } from 'vuetify/components';
import { Account } from '~/generated/station/station.did';
import AddAccountAssetDialog from './AddAccountAssetDialog.vue';

const input = withDefaults(
defineProps<{
account: Account;
icon?: string;
text?: string;
size?: 'x-small' | 'small' | 'default' | 'medium' | 'large' | 'x-large';
variant?: 'flat' | 'text' | 'outlined' | 'elevated';
color?: string;
readonly?: boolean;
appendIcon?: string;
}>(),
{
icon: undefined,
text: undefined,
size: 'default',
variant: 'elevated',
color: 'primary',
readonly: false,
appendIcon: undefined,
},
);

const open = ref(false);

const emit = defineEmits<{
(event: 'opened', payload: boolean): void;
}>();

const props = toRefs(input);
</script>
116 changes: 116 additions & 0 deletions apps/wallet/src/components/accounts/AddAccountAssetDialog.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { describe, expect, it, vi } from 'vitest';
import { Account, Asset } from '~/generated/station/station.did';
import { mount } from '~/test.utils';
import AddAccountAssetDialog from './AddAccountAssetDialog.vue';
import { BlockchainStandard } from '~/types/chain.types';
import { useStationStore } from '~/stores/station.store';
import TokenAutocomplete from '../inputs/TokenAutocomplete.vue';
import { flushPromises } from '@vue/test-utils';
import { StationService } from '~/services/station.service';
import { services } from '~/plugins/services.plugin';

vi.mock('~/services/station.service', () => {
const mock: Partial<StationService> = {
editAccount: vi.fn().mockImplementation(() => Promise.resolve({} as Account)),
};

return {
StationService: vi.fn(() => mock),
};
});

const mockAssets: Asset[] = [
{
id: '1',
blockchain: 'icp',
decimals: 8,
metadata: [],
name: 'Test',
symbol: 'TEST',
standards: [BlockchainStandard.Native],
},

{
id: '2',
blockchain: 'icp',
decimals: 8,
metadata: [],
name: 'Test2',
symbol: 'TEST2',
standards: [BlockchainStandard.ICRC1],
},
];

const mockAccount: Account = {
id: '1',
assets: [
{
asset_id: mockAssets[0].id,
balance: [],
},
],
addresses: [],
configs_request_policy: [],
metadata: [],
last_modification_timestamp: '2021-09-01T00:00:00Z',
name: 'Test',
transfer_request_policy: [],
};

describe('AddAccountAssetDialog', () => {
it('renders correctly', () => {
const wrapper = mount(AddAccountAssetDialog, {
props: {
account: mockAccount,

open: true,
attach: true,
},
});

expect(wrapper.exists()).toBe(true);
});

it('edits the account when submitted', async () => {
const wrapper = mount(AddAccountAssetDialog, {
props: {
account: { ...mockAccount },
open: true,
attach: true,
},
});

const station = useStationStore();
station.configuration.details.supported_assets = mockAssets;

const submitBtn = wrapper.find('button[data-test-id="add-asset-dialog-save-button"]');

const tokenField = wrapper.findComponent(TokenAutocomplete);

tokenField.vm.$emit('update:modelValue', [mockAssets[1].id]);

await wrapper.vm.$nextTick();
await flushPromises();

await submitBtn.trigger('click');

await wrapper.vm.$nextTick();
await flushPromises();

// check if editAccount was called with the correct asset
expect(services().station.editAccount).toHaveBeenCalledWith(
expect.objectContaining({
change_assets: [
{
Change: {
add_assets: [mockAssets[1].id],
remove_assets: [],
},
},
],
}),
);

vi.clearAllMocks();
});
});
Loading
Loading