Skip to content

Commit

Permalink
feat: delete satellites and orbiters (#312)
Browse files Browse the repository at this point in the history
  • Loading branch information
peterpeterparker committed Nov 17, 2023
1 parent d03bd14 commit c9f2871
Show file tree
Hide file tree
Showing 35 changed files with 574 additions and 30 deletions.
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

0 comments on commit c9f2871

Please sign in to comment.