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(station): monitor external canisters #416

Merged
merged 32 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
31c7a97
feat(station): monitor external canisters
jedna Nov 6, 2024
f500ef2
feat(station): monitor external canisters
jedna Nov 7, 2024
340d67f
improve canfund init
jedna Nov 11, 2024
ea0d9c7
merge request specifier for monitoring with funding
jedna Nov 11, 2024
7345f3a
feat(external-canister): consolidate funding logic
jedna Nov 18, 2024
d424698
Merge branch 'refs/heads/main' into pen-331-canfund-external-canisters
jedna Nov 20, 2024
0ea1e87
refactor: monitoring setup
jedna Nov 20, 2024
afc10ce
cs
jedna Nov 20, 2024
8ddf80c
Merge branch 'refs/heads/main' into pen-331-canfund-external-canisters
jedna Nov 20, 2024
46531c2
chore: bump canfund
jedna Nov 20, 2024
1b3797b
Merge branch 'refs/heads/main' into pen-331-canfund-external-canisters
jedna Nov 21, 2024
6564ed4
Merge branch 'refs/heads/main' into pen-331-canfund-external-canisters
jedna Nov 21, 2024
3ab27b8
minor updates
jedna Nov 22, 2024
1fda675
feat(wallet): UI for external canister monitoring setup (#419)
jedna Nov 22, 2024
5a562af
Merge branch 'main' into pen-331-canfund-external-canisters
jedna Nov 22, 2024
ceb28af
cs
jedna Nov 22, 2024
ea99536
fix tests
jedna Nov 22, 2024
b0b88ef
update canbench results
jedna Nov 25, 2024
fa7b2c1
Merge branch 'main' into pen-331-canfund-external-canisters
jedna Nov 25, 2024
84ec5af
Merge branch 'main' into pen-331-canfund-external-canisters
jedna Nov 27, 2024
66db38f
merge main
jedna Nov 27, 2024
6d0fb79
cs
jedna Nov 27, 2024
586c5b2
feat(wallet): Cycle Obtain configuration for external canister (#445)
jedna Dec 2, 2024
05a5490
restart monitoring after upgrade
jedna Dec 2, 2024
d278388
Merge branch 'main' into pen-331-canfund-external-canisters
jedna Dec 2, 2024
1a46ec9
Update apps/wallet/src/components/external-canisters/monitor/Canister…
jedna Dec 3, 2024
f24afa6
use const for icp ledger canister id
jedna Dec 3, 2024
9492f2f
Merge branch 'refs/heads/main' into pen-331-canfund-external-canisters
jedna Dec 3, 2024
16f4840
cs
jedna Dec 3, 2024
ade0031
fix merge conflicts
jedna Dec 3, 2024
1164861
Merge branch 'main' into pen-331-canfund-external-canisters
jedna Dec 3, 2024
fc57770
forbid minting for external canisters on BE
jedna Dec 3, 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
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ byteorder = "1.5"
canbench-rs = "0.1.1"
candid = "0.10.3"
candid_parser = "0.1.3"
canfund = "0.2.0"
canfund = "0.4.0"
cap-std = "3.4.1"
ciborium = "0.2.2"
clap = { version = "4.5.7", features = ["derive"] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ const { submit, edited, additionalFieldErrors, fieldsWithErrors, submitting, val
model,
submit: async (updatedModel: CanisterCallModel): Promise<void> => {
try {
const methodName = assertAndReturn(updatedModel.methodName, 'Method name is required');
const canisterId = assertAndReturn(updatedModel.canisterId, 'Canister ID is required');
const methodName = assertAndReturn(updatedModel.methodName, 'Method name');
const canisterId = assertAndReturn(updatedModel.canisterId, 'Canister ID');
const validationMethod =
updatedModel.validationTarget &&
variantIs(updatedModel.validationTarget, 'ValidationMethod')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Principal } from '@dfinity/principal';
import { describe, expect, it, vi } from 'vitest';
import { StationService } from '~/services/station.service';
import { mount } from '~/test.utils';
import { flushPromises } from '@vue/test-utils';
import { services } from '~/plugins/services.plugin';
import CanisterMonitorDialog from '~/components/external-canisters/CanisterMonitorDialog.vue';

vi.mock('~/services/station.service', () => {
const mock: Partial<StationService> = {
withStationId: vi.fn().mockReturnThis(),
monitorExternalCanister: vi.fn().mockImplementation(() => Promise.reject()),
};

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

describe('CanisterMonitorDialog', () => {
it('renders default card open is true', () => {
const wrapper = mount(CanisterMonitorDialog, {
props: {
open: true,
canisterId: Principal.fromText('r7inp-6aaaa-aaaaa-aaabq-cai'),
attach: true, // disables teleport in VDialog
},
});

const dialog = wrapper.findComponent({ name: 'VDialog' });
expect(dialog.exists()).toBe(true);

const container = dialog.find('[data-test-id="canister-monitor-card"]');

expect(container).not.toBeNull();

wrapper.unmount();
});

it('triggers submit when on click of save button', async () => {
const monitorMethod = vi
.spyOn(services().station, 'monitorExternalCanister')
.mockImplementation(() => Promise.reject());

const wrapper = mount(CanisterMonitorDialog, {
props: {
open: true,
canisterId: Principal.fromText('r7inp-6aaaa-aaaaa-aaabq-cai'),
attach: true, // disables teleport in VDialog
},
});

const strategyInput = wrapper.findComponent({ name: 'VSelect' });
await strategyInput.setValue('Always');

await flushPromises();

const nextBtn = wrapper.find('[data-test-id="monitor-dialog-stepper-next"]');
await nextBtn.trigger('click');

const obtainInput = wrapper.findComponent({ name: 'VSelect' });
await obtainInput.setValue('StationDefault');

const saveBtn = wrapper.find('[data-test-id="monitor-dialog-submit"]');
await saveBtn.trigger('click');

await flushPromises();

expect(monitorMethod).toHaveBeenCalledOnce();

wrapper.unmount();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<template>
<VDialog
v-bind="$attrs"
v-model="open"
:persistent="!canClose"
transition="dialog-bottom-transition"
scrollable
:max-width="props.dialogMaxWidth"
>
<VCard data-test-id="canister-monitor-card">
<VToolbar color="background">
<VToolbarTitle>
{{ dialogTitle }}
</VToolbarTitle>
<VBtn :disabled="!canClose" :icon="mdiClose" @click="open = false" />
</VToolbar>
<VDivider />
<CanisterMonitorForm
v-model="monitorModel"
:display="{ canisterId: !monitorModel.canisterId }"
@submitting="canClose = !$event"
@submitted="open = false"
>
</CanisterMonitorForm>
</VCard>
</VDialog>
</template>
<script lang="ts" setup>
import { Principal } from '@dfinity/principal';
import { mdiClose } from '@mdi/js';
import { Ref, computed, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { VBtn, VCard, VDialog, VDivider, VToolbar, VToolbarTitle } from 'vuetify/components';
import { CanisterMonitorModel } from './external-canisters.types';
import CanisterMonitorForm from '~/components/external-canisters/monitor/CanisterMonitorForm.vue';

const props = withDefaults(
defineProps<{
open?: boolean;
canisterId?: Principal;
dialogMaxWidth?: number;
title?: string;
}>(),
{
open: false,
canisterId: undefined,
dialogMaxWidth: 800,
title: undefined,
},
);

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

const i18n = useI18n();
const canClose = ref(true);
const dialogTitle = computed(() => props.title || i18n.t('external_canisters.monitor.title'));

const buildModel = (): CanisterMonitorModel => ({
canisterId: props.canisterId,
fundingStrategy: undefined,
cycleObtainStrategy: undefined,
});

const open = computed({
get: () => props.open,
set: value => emit('update:open', value),
});

const monitorModel = ref(buildModel()) as Ref<CanisterMonitorModel>;
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import {
Allow,
CanisterInstallMode,
CanisterMethod,
CycleObtainStrategyInput,
ExternalCanisterChangeRequestPolicyRuleInput,
LogVisibility,
MonitorExternalCanisterStrategyInput,
ValidationMethodResourceTarget,
} from '~/generated/station/station.did';

Expand Down Expand Up @@ -74,6 +76,12 @@ export interface CanisterCallReviewContext {
candidIdl?: string;
}

export interface CanisterMonitorModel {
canisterId?: Principal;
fundingStrategy?: MonitorExternalCanisterStrategyInput;
cycleObtainStrategy?: CycleObtainStrategyInput;
}

export interface CanisterSnapshot {
snapshotId: string;
totalSize: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Principal } from '@dfinity/principal';
import { describe, expect, it } from 'vitest';
import { mount } from '~/test.utils.ts';
import CanisterMonitorForm from '~/components/external-canisters/monitor/CanisterMonitorForm.vue';

describe('CanisterMonitorForm', () => {
it('hides the canisterId when display is set to false', () => {
const form = mount(CanisterMonitorForm, {
props: {
modelValue: { canisterId: Principal.anonymous(), fundingStrategy: undefined },
display: { canisterId: false },
},
});
const canisterIdInput = form.find('[name="canisterId"]');

expect(canisterIdInput.exists()).toBe(false);
});
});
Loading
Loading