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: delete satellites and orbiters #312

Merged
merged 6 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 0 deletions src/declarations/mission_control/mission_control.did.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ export interface _SERVICE {
create_orbiter: ActorMethod<[[] | [string]], Orbiter>;
create_satellite: ActorMethod<[string], Satellite>;
del_mission_control_controllers: ActorMethod<[Array<Principal>], undefined>;
del_orbiter: ActorMethod<[Principal, bigint], undefined>;
del_orbiters_controllers: ActorMethod<[Array<Principal>, Array<Principal>], undefined>;
del_satellite: ActorMethod<[Principal, bigint], undefined>;
del_satellites_controllers: ActorMethod<[Array<Principal>, Array<Principal>], undefined>;
get_user: ActorMethod<[], Principal>;
list_mission_control_controllers: ActorMethod<[], Array<[Principal, Controller]>>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ export const idlFactory = ({ IDL }) => {
create_orbiter: IDL.Func([IDL.Opt(IDL.Text)], [Orbiter], []),
create_satellite: IDL.Func([IDL.Text], [Satellite], []),
del_mission_control_controllers: IDL.Func([IDL.Vec(IDL.Principal)], [], []),
del_orbiter: IDL.Func([IDL.Principal, IDL.Nat], [], []),
del_orbiters_controllers: IDL.Func([IDL.Vec(IDL.Principal), IDL.Vec(IDL.Principal)], [], []),
del_satellite: IDL.Func([IDL.Principal, IDL.Nat], [], []),
del_satellites_controllers: IDL.Func([IDL.Vec(IDL.Principal), IDL.Vec(IDL.Principal)], [], []),
get_user: IDL.Func([], [IDL.Principal], ['query']),
list_mission_control_controllers: IDL.Func(
Expand Down
5 changes: 5 additions & 0 deletions src/declarations/orbiter/orbiter.did.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export interface DelSatelliteConfig {
export interface DeleteControllersArgs {
controllers: Array<Principal>;
}
export interface DepositCyclesArgs {
cycles_to_retain: bigint;
destination_id: Principal;
}
export interface GetAnalytics {
to: [] | [bigint];
from: [] | [bigint];
Expand Down Expand Up @@ -91,6 +95,7 @@ export interface TrackEvent {
export interface _SERVICE {
del_controllers: ActorMethod<[DeleteControllersArgs], Array<[Principal, Controller]>>;
del_satellite_config: ActorMethod<[Principal, DelSatelliteConfig], undefined>;
deposit_cycles: ActorMethod<[DepositCyclesArgs], undefined>;
get_page_views: ActorMethod<[GetAnalytics], Array<[AnalyticKey, PageView]>>;
get_track_events: ActorMethod<[GetAnalytics], Array<[AnalyticKey, TrackEvent]>>;
list_controllers: ActorMethod<[], Array<[Principal, Controller]>>;
Expand Down
5 changes: 5 additions & 0 deletions src/declarations/orbiter/orbiter.factory.did.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export const idlFactory = ({ IDL }) => {
expires_at: IDL.Opt(IDL.Nat64)
});
const DelSatelliteConfig = IDL.Record({ updated_at: IDL.Opt(IDL.Nat64) });
const DepositCyclesArgs = IDL.Record({
cycles_to_retain: IDL.Nat,
destination_id: IDL.Principal
});
const GetAnalytics = IDL.Record({
to: IDL.Opt(IDL.Nat64),
from: IDL.Opt(IDL.Nat64),
Expand Down Expand Up @@ -98,6 +102,7 @@ export const idlFactory = ({ IDL }) => {
[]
),
del_satellite_config: IDL.Func([IDL.Principal, DelSatelliteConfig], [], []),
deposit_cycles: IDL.Func([DepositCyclesArgs], [], []),
get_page_views: IDL.Func(
[GetAnalytics],
[IDL.Vec(IDL.Tuple(AnalyticKey, PageView))],
Expand Down
5 changes: 5 additions & 0 deletions src/declarations/satellite/satellite.did.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export interface DelDoc {
export interface DeleteControllersArgs {
controllers: Array<Principal>;
}
export interface DepositCyclesArgs {
cycles_to_retain: bigint;
destination_id: Principal;
}
export interface Doc {
updated_at: bigint;
owner: Principal;
Expand Down Expand Up @@ -194,6 +198,7 @@ export interface _SERVICE {
del_custom_domain: ActorMethod<[string], undefined>;
del_doc: ActorMethod<[string, string, DelDoc], undefined>;
del_rule: ActorMethod<[RulesType, string, DelDoc], undefined>;
deposit_cycles: ActorMethod<[DepositCyclesArgs], undefined>;
get_config: ActorMethod<[], Config>;
get_doc: ActorMethod<[string, string], [] | [Doc]>;
http_request: ActorMethod<[HttpRequest], HttpResponse>;
Expand Down
5 changes: 5 additions & 0 deletions src/declarations/satellite/satellite.factory.did.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export const idlFactory = ({ IDL }) => {
});
const DelDoc = IDL.Record({ updated_at: IDL.Opt(IDL.Nat64) });
const RulesType = IDL.Variant({ Db: IDL.Null, Storage: IDL.Null });
const DepositCyclesArgs = IDL.Record({
cycles_to_retain: IDL.Nat,
destination_id: IDL.Principal
});
const StorageConfigRedirect = IDL.Record({
status_code: IDL.Nat16,
location: IDL.Text
Expand Down Expand Up @@ -194,6 +198,7 @@ export const idlFactory = ({ IDL }) => {
del_custom_domain: IDL.Func([IDL.Text], [], []),
del_doc: IDL.Func([IDL.Text, IDL.Text, DelDoc], [], []),
del_rule: IDL.Func([RulesType, IDL.Text, DelDoc], [], []),
deposit_cycles: IDL.Func([DepositCyclesArgs], [], []),
get_config: IDL.Func([], [Config], []),
get_doc: IDL.Func([IDL.Text, IDL.Text], [IDL.Opt(Doc)], ['query']),
http_request: IDL.Func([HttpRequest], [HttpResponse], ['query']),
Expand Down
5 changes: 5 additions & 0 deletions src/declarations/satellite/satellite.factory.did.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export const idlFactory = ({ IDL }) => {
});
const DelDoc = IDL.Record({ updated_at: IDL.Opt(IDL.Nat64) });
const RulesType = IDL.Variant({ Db: IDL.Null, Storage: IDL.Null });
const DepositCyclesArgs = IDL.Record({
cycles_to_retain: IDL.Nat,
destination_id: IDL.Principal
});
const StorageConfigRedirect = IDL.Record({
status_code: IDL.Nat16,
location: IDL.Text
Expand Down Expand Up @@ -194,6 +198,7 @@ export const idlFactory = ({ IDL }) => {
del_custom_domain: IDL.Func([IDL.Text], [], []),
del_doc: IDL.Func([IDL.Text, IDL.Text, DelDoc], [], []),
del_rule: IDL.Func([RulesType, IDL.Text, DelDoc], [], []),
deposit_cycles: IDL.Func([DepositCyclesArgs], [], []),
get_config: IDL.Func([], [Config], []),
get_doc: IDL.Func([IDL.Text, IDL.Text], [IDL.Opt(Doc)], ['query']),
http_request: IDL.Func([HttpRequest], [HttpResponse], ['query']),
Expand Down
26 changes: 26 additions & 0 deletions src/frontend/src/lib/api/mission-control.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,29 @@ export const deleteOrbitersController = async ({
const actor = await getMissionControlActor(missionControlId);
await actor.del_orbiters_controllers(orbiterIds, [controller]);
};

export const deleteSatellite = async ({
missionControlId,
satelliteId,
cycles_to_retain
}: {
missionControlId: Principal;
satelliteId: Principal;
cycles_to_retain: bigint;
}) => {
const { del_satellite } = await getMissionControlActor(missionControlId);
await del_satellite(satelliteId, cycles_to_retain);
};

export const deleteOrbiter = async ({
missionControlId,
orbiterId,
cycles_to_retain
}: {
missionControlId: Principal;
orbiterId: Principal;
cycles_to_retain: bigint;
}) => {
const { del_orbiter } = await getMissionControlActor(missionControlId);
await del_orbiter(orbiterId, cycles_to_retain);
};
192 changes: 192 additions & 0 deletions src/frontend/src/lib/components/modals/CanisterDeleteModal.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<script lang="ts">
import { i18n } from '$lib/stores/i18n.store';
import SpinnerModal from '$lib/components/ui/SpinnerModal.svelte';
import Modal from '$lib/components/ui/Modal.svelte';
import { createEventDispatcher } from 'svelte';
import { isBusy, wizardBusy } from '$lib/stores/busy.store';
import Value from '$lib/components/ui/Value.svelte';
import IconWarning from '$lib/components/icons/IconWarning.svelte';
import Input from '$lib/components/ui/Input.svelte';
import { authSignedInStore } from '$lib/stores/auth.store';
import { toasts } from '$lib/stores/toasts.store';
import { isNullish } from '@dfinity/utils';
import { missionControlStore } from '$lib/stores/mission-control.store';
import { loadSatellites } from '$lib/services/satellites.services';
import { goto } from '$app/navigation';
import type { Principal } from '@dfinity/principal';
import { ONE_TRILLION } from '$lib/constants/constants';
import { i18nFormat } from '$lib/utils/i18n.utils';
import { formatTCycles } from '$lib/utils/cycles.utils';

export let segment: 'satellite' | 'orbiter';
export let currentCycles: bigint;
export let deleteFn: (params: {
missionControlId: Principal;
cycles_to_retain: bigint;
}) => Promise<void>;

let steps: 'init' | 'in_progress' | 'error' = 'init';

const dispatch = createEventDispatcher();
const close = () => dispatch('junoClose');

// 1T cycles per default
let tCycles = 1;

let cycles: bigint;
$: (() => {
if (isNaN(tCycles)) {
return;
}

cycles = BigInt(tCycles * ONE_TRILLION);
})();

let depositCycles: bigint;
$: depositCycles = currentCycles - cycles > 0 ? currentCycles - cycles : 0n;

let validConfirm = false;
$: validConfirm = cycles > 0 && cycles <= currentCycles;

const onSubmit = async () => {
if (!$authSignedInStore) {
toasts.error({
text: $i18n.errors.no_identity
});
return;
}

if (isNullish($missionControlStore)) {
toasts.error({
text: $i18n.errors.no_mission_control
});
return;
}

if (cycles > currentCycles) {
toasts.error({
text: $i18n.canisters.invalid_cycles_to_retain
});
return;
}

steps = 'in_progress';

wizardBusy.start();

try {
await deleteFn({
missionControlId: $missionControlStore,
cycles_to_retain: cycles
});

await loadSatellites({
missionControl: $missionControlStore,
reload: true
});

await goto('/', { replaceState: true });

close();

toasts.success($i18n.satellites.stop_success);
} catch (err: unknown) {
steps = 'error';

toasts.error({
text: $i18n.errors.satellite_stop,
detail: err
});
}

wizardBusy.stop();
};
</script>

<Modal on:junoClose>
{#if steps === 'in_progress'}
<SpinnerModal>
<p>{$i18n.canisters.delete_in_progress}</p>
</SpinnerModal>
{:else}
<form on:submit|preventDefault={onSubmit}>
<h2>
{@html i18nFormat($i18n.canisters.delete_title, [
{
placeholder: '{0}',
value: segment.replace('_', ' ')
}
])}
</h2>

<p>
{@html i18nFormat($i18n.canisters.delete_explanation, [
{
placeholder: '{0}',
value: segment.replace('_', ' ')
},
{
placeholder: '{1}',
value: segment.replace('_', ' ')
}
])}
</p>

<p>
{@html i18nFormat($i18n.canisters.delete_customization, [
{
placeholder: '{0}',
value: segment.replace('_', ' ')
},
{
placeholder: '{1}',
value: formatTCycles(currentCycles)
}
])}
</p>

<Value ref="cycles">
<svelte:fragment slot="label">{$i18n.canisters.cycles_to_retain}</svelte:fragment>

<Input
name="cycles"
inputType="icp"
required
bind:value={tCycles}
placeholder={$i18n.canisters.amount}
/>
</Value>

<p>
<small
>{@html i18nFormat($i18n.canisters.cycles_to_transfer, [
{
placeholder: '{0}',
value: formatTCycles(depositCycles)
}
])}</small
>
</p>

<p class="warning">
<IconWarning />
{@html i18nFormat($i18n.canisters.delete_info, [
{
placeholder: '{0}',
value: segment.replace('_', ' ')
}
])}
</p>

<button type="submit" class="submit" disabled={$isBusy || !validConfirm}>
{$i18n.core.delete}
</button>
</form>
{/if}
</Modal>

<style lang="scss">
.warning {
padding: var(--padding) 0 0;
}
</style>
5 changes: 5 additions & 0 deletions src/frontend/src/lib/components/modals/Modals.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import OrbiterCreateModal from '$lib/components/modals/OrbiterCreateModal.svelte';
import OrbiterUpgradeModal from '$lib/components/modals/OrbiterUpgradeModal.svelte';
import OrbiterTopUpModal from '$lib/components/modals/OrbiterTopUpModal.svelte';
import SatelliteDeleteModal from '$lib/components/modals/SatelliteDeleteModal.svelte';

let modal: JunoModal | undefined = undefined;

Expand Down Expand Up @@ -58,3 +59,7 @@
{#if modal?.type === 'upgrade_orbiter' && nonNullish(modal.detail)}
<OrbiterUpgradeModal on:junoClose={close} detail={modal.detail} />
{/if}

{#if modal?.type === 'delete_satellite' && nonNullish(modal.detail)}
<SatelliteDeleteModal on:junoClose={close} detail={modal.detail} />
{/if}
26 changes: 26 additions & 0 deletions src/frontend/src/lib/components/modals/SatelliteDeleteModal.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script lang="ts">
import type { JunoModalDeleteSatelliteDetail, JunoModalDetail } from '$lib/types/modal';
import type { Satellite } from '$declarations/mission_control/mission_control.did';
import { deleteSatellite } from '$lib/api/mission-control.api';
import type { Principal } from '@dfinity/principal';
import CanisterDeleteModal from '$lib/components/modals/CanisterDeleteModal.svelte';

export let detail: JunoModalDetail;

let satellite: Satellite;
let currentCycles: bigint;

$: ({ satellite, cycles: currentCycles } = detail as JunoModalDeleteSatelliteDetail);

let deleteFn: (params: {
missionControlId: Principal;
cycles_to_retain: bigint;
}) => Promise<void>;
$: deleteFn = async (params: { missionControlId: Principal; cycles_to_retain: bigint }) =>
deleteSatellite({
...params,
satelliteId: satellite.satellite_id
});
</script>

<CanisterDeleteModal {deleteFn} {currentCycles} on:junoClose segment="satellite" />
Loading