Skip to content

Commit b198236

Browse files
feat(frontend): out-of-sync support for UFOs (#2778)
* feat(frontend): sync ufos with mission control * chore: lint
1 parent 674c671 commit b198236

16 files changed

Lines changed: 277 additions & 44 deletions

File tree

src/frontend/src/lib/components/app/notifications/Notifications.svelte

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
let satelliteCanisterData = $state<CanisterData | undefined>(undefined);
3535
let satelliteWarnings = $state<CanisterWarning | undefined>(undefined);
3636
37+
let ufoCanisterData = $state<CanisterData | undefined>(undefined);
38+
let ufoWarnings = $state<CanisterWarning | undefined>(undefined);
39+
3740
let upgradeWarning = $state(false);
3841
let canisterWarnings = $state(false);
3942
let canisterNotifications = $state(false);
@@ -98,6 +101,8 @@
98101
{orbiterWarnings}
99102
{satelliteCanisterData}
100103
{satelliteWarnings}
104+
{ufoCanisterData}
105+
{ufoWarnings}
101106
bind:alerts={hasAlerts}
102107
bind:upgradeWarning
103108
bind:canisterWarnings
@@ -121,6 +126,8 @@
121126
{outOfSyncWarnings}
122127
{satelliteCanisterData}
123128
{satelliteWarnings}
129+
{ufoCanisterData}
130+
{ufoWarnings}
124131
{upgradeWarning}
125132
/>
126133
{:else if $store.tabId === $store.tabs[1].id}

src/frontend/src/lib/components/app/notifications/NotificationsAlerts.svelte

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
import IconAnalytics from '$lib/components/icons/IconAnalytics.svelte';
66
import IconMissionControl from '$lib/components/icons/IconMissionControl.svelte';
77
import IconSatellite from '$lib/components/icons/IconSatellite.svelte';
8+
import IconUfo from '$lib/components/icons/IconUfo.svelte';
89
import { satellite } from '$lib/derived/satellite.derived';
10+
import { ufo } from '$lib/derived/ufo.derived';
911
import { i18n } from '$lib/stores/app/i18n.store';
1012
import type { CanisterData, CanisterWarning } from '$lib/types/canister';
11-
import { overviewLink } from '$lib/utils/nav.utils';
13+
import { overviewLink, ufoLink } from '$lib/utils/nav.utils';
1214
1315
interface Props {
1416
missionControlCanisterData: CanisterData | undefined;
@@ -17,6 +19,8 @@
1719
orbiterWarnings: CanisterWarning | undefined;
1820
satelliteCanisterData: CanisterData | undefined;
1921
satelliteWarnings: CanisterWarning | undefined;
22+
ufoCanisterData: CanisterData | undefined;
23+
ufoWarnings: CanisterWarning | undefined;
2024
close: () => void;
2125
alerts: boolean;
2226
upgradeWarning: boolean;
@@ -31,6 +35,8 @@
3135
orbiterWarnings,
3236
satelliteCanisterData,
3337
satelliteWarnings,
38+
ufoCanisterData,
39+
ufoWarnings,
3440
close,
3541
alerts,
3642
upgradeWarning,
@@ -69,6 +75,15 @@
6975
segment="satellite"
7076
warnings={satelliteWarnings}
7177
/>
78+
79+
<NotificationsCanisterAlert
80+
{close}
81+
cyclesIcon={IconUfo}
82+
data={ufoCanisterData}
83+
href={ufoLink($ufo?.ufo_id)}
84+
segment="ufo"
85+
warnings={ufoWarnings}
86+
/>
7287
{/if}
7388

7489
{#if outOfSyncWarnings}

src/frontend/src/lib/components/app/notifications/NotificationsAlertsLoader.svelte

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22
import NotificationsCanisterLoader from '$lib/components/app/notifications/NotificationsCanisterLoader.svelte';
33
import { missionControlId } from '$lib/derived/console/account.mission-control.derived';
44
import { orbiter } from '$lib/derived/orbiter.derived';
5-
import { outOfSyncOrbiters, outOfSyncSatellites } from '$lib/derived/out-of-sync.derived';
5+
import {
6+
outOfSyncOrbiters,
7+
outOfSyncUfos,
8+
outOfSyncSatellites
9+
} from '$lib/derived/out-of-sync.derived';
610
import { satellite } from '$lib/derived/satellite.derived';
11+
import { ufo } from '$lib/derived/ufo.derived';
712
import { versionsLoaded, versionsUpgradeWarning } from '$lib/derived/version.derived';
813
import type { CanisterData, CanisterWarning } from '$lib/types/canister';
914
@@ -14,6 +19,8 @@
1419
orbiterWarnings: CanisterWarning | undefined;
1520
satelliteCanisterData: CanisterData | undefined;
1621
satelliteWarnings: CanisterWarning | undefined;
22+
ufoCanisterData: CanisterData | undefined;
23+
ufoWarnings: CanisterWarning | undefined;
1724
alerts: boolean;
1825
upgradeWarning: boolean;
1926
canisterWarnings: boolean;
@@ -27,6 +34,8 @@
2734
orbiterWarnings = $bindable(undefined),
2835
satelliteCanisterData = $bindable(undefined),
2936
satelliteWarnings = $bindable(undefined),
37+
ufoCanisterData = $bindable(undefined),
38+
ufoWarnings = $bindable(undefined),
3039
alerts = $bindable(false),
3140
upgradeWarning = $bindable(false),
3241
canisterWarnings = $bindable(false),
@@ -39,12 +48,15 @@
3948
let hasCanisterWarnings = $derived(
4049
hasWarnings(missionControlWarnings) ||
4150
hasWarnings(orbiterWarnings) ||
42-
hasWarnings(satelliteWarnings)
51+
hasWarnings(satelliteWarnings) ||
52+
hasWarnings(ufoWarnings)
4353
);
4454
4555
let hasUpgradeWarning = $derived($versionsLoaded && $versionsUpgradeWarning);
4656
47-
let hasOutOfSyncWarning = $derived($outOfSyncSatellites === true || $outOfSyncOrbiters === true);
57+
let hasOutOfSyncWarning = $derived(
58+
$outOfSyncSatellites === true || $outOfSyncOrbiters === true || $outOfSyncUfos === true
59+
);
4860
4961
let hasNotifications = $derived(hasCanisterWarnings || hasUpgradeWarning || hasOutOfSyncWarning);
5062
@@ -73,3 +85,9 @@
7385
bind:warnings={satelliteWarnings}
7486
bind:data={satelliteCanisterData}
7587
/>
88+
89+
<NotificationsCanisterLoader
90+
canisterId={$ufo?.ufo_id}
91+
bind:warnings={ufoWarnings}
92+
bind:data={ufoCanisterData}
93+
/>

src/frontend/src/lib/components/app/notifications/NotificationsCanisterAlert.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
data: CanisterData | undefined;
1414
close: () => void;
1515
href: string;
16-
segment: 'satellite' | 'mission_control' | 'orbiter';
16+
segment: 'satellite' | 'mission_control' | 'orbiter' | 'ufo';
1717
}
1818
1919
let { warnings, close, data, href, cyclesIcon, segment }: Props = $props();

src/frontend/src/lib/components/modals/out-of-sync/OutOfSyncSegmentsModal.svelte

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
const onsubmit = async ($event: SubmitEvent) => {
2929
$event.preventDefault();
3030
31-
$event.preventDefault();
32-
3331
onProgress(undefined);
3432
3533
wizardBusy.start();

src/frontend/src/lib/components/modules/out-of-sync/OutOfSyncForm.svelte

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
<script lang="ts">
22
import OutOfSyncSegments from '$lib/components/modules/out-of-sync/OutOfSyncSegments.svelte';
33
import GridEqualNot from '$lib/components/ui/GridEqualNot.svelte';
4-
import { consoleOrbiter, consoleSortedSatellites } from '$lib/derived/console/segments.derived';
4+
import {
5+
consoleOrbiter,
6+
consoleSortedSatellites,
7+
consoleSortedUfos
8+
} from '$lib/derived/console/segments.derived';
59
import { mctrlOrbiter } from '$lib/derived/mission-control/mission-control-orbiters.derived';
610
import { mctrlSortedSatellites } from '$lib/derived/mission-control/mission-control-satellites.derived';
11+
import { mctrlSortedUfos } from '$lib/derived/mission-control/mission-control-ufos.derived';
712
import { i18n } from '$lib/stores/app/i18n.store';
813
914
interface Props {
@@ -19,15 +24,23 @@
1924

2025
<form {onsubmit}>
2126
<div class="columns">
22-
<OutOfSyncSegments orbiter={$consoleOrbiter} satellites={$consoleSortedSatellites}>
27+
<OutOfSyncSegments
28+
orbiter={$consoleOrbiter}
29+
satellites={$consoleSortedSatellites}
30+
ufos={$consoleSortedUfos}
31+
>
2332
{#snippet label()}
2433
{$i18n.out_of_sync.console}
2534
{/snippet}
2635
</OutOfSyncSegments>
2736

2837
<GridEqualNot small />
2938

30-
<OutOfSyncSegments orbiter={$mctrlOrbiter} satellites={$mctrlSortedSatellites}>
39+
<OutOfSyncSegments
40+
orbiter={$mctrlOrbiter}
41+
satellites={$mctrlSortedSatellites}
42+
ufos={$mctrlSortedUfos}
43+
>
3144
{#snippet label()}
3245
{$i18n.mission_control.title}
3346
{/snippet}

src/frontend/src/lib/components/modules/out-of-sync/OutOfSyncSegments.svelte

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,32 @@
66
import { i18n } from '$lib/stores/app/i18n.store';
77
import type { Orbiter } from '$lib/types/orbiter';
88
import type { Satellite } from '$lib/types/satellite';
9+
import type { Ufo } from '$lib/types/ufo';
910
import { metadataUiName } from '$lib/utils/metadata-ui.utils';
1011
import { orbiterName } from '$lib/utils/orbiter.utils';
1112
1213
interface Props {
1314
label: Snippet;
1415
satellites: Satellite[];
16+
ufos: Ufo[];
1517
orbiter: Nullish<Orbiter>;
1618
}
1719
18-
let { label, satellites, orbiter }: Props = $props();
20+
let { label, satellites, ufos, orbiter }: Props = $props();
1921
</script>
2022

2123
{#snippet withSegments()}
2224
<ul class="content">
25+
{#if nonNullish(orbiter)}
26+
{@const orbName = orbiterName(orbiter)}
27+
28+
<li>
29+
<Segment id={orbiter.orbiter_id}>
30+
{isEmptyString(orbName) ? $i18n.analytics.orbiter : orbName}
31+
</Segment>
32+
</li>
33+
{/if}
34+
2335
{#each satellites as satellite (satellite.satellite_id.toText())}
2436
<li>
2537
<Segment id={satellite.satellite_id}>
@@ -28,15 +40,13 @@
2840
</li>
2941
{/each}
3042

31-
{#if nonNullish(orbiter)}
32-
{@const orbName = orbiterName(orbiter)}
33-
43+
{#each ufos as ufo (ufo.ufo_id.toText())}
3444
<li>
35-
<Segment id={orbiter.orbiter_id}>
36-
{isEmptyString(orbName) ? $i18n.analytics.orbiter : orbName}
45+
<Segment id={ufo.ufo_id}>
46+
{metadataUiName(ufo)}
3747
</Segment>
3848
</li>
39-
{/if}
49+
{/each}
4050
</ul>
4151
{/snippet}
4252

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { ufosUncertifiedStore } from '$lib/stores/mission-control/ufos.store';
2+
import { sortUfos } from '$lib/utils/ufo.utils';
23
import { derived } from 'svelte/store';
34

45
export const mctrlUfos = derived(
56
[ufosUncertifiedStore],
67
([$ufosUncertifiedStore]) => $ufosUncertifiedStore?.data
78
);
9+
10+
export const mctrlSortedUfos = derived([mctrlUfos], ([$mctrlUfosStore]) =>
11+
($mctrlUfosStore ?? []).sort(sortUfos)
12+
);

src/frontend/src/lib/derived/out-of-sync.derived.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
import { consoleOrbiters, consoleSatellites } from '$lib/derived/console/segments.derived';
1+
import {
2+
consoleOrbiters,
3+
consoleSatellites,
4+
consoleUfos
5+
} from '$lib/derived/console/segments.derived';
26
import { mctrlOrbiters } from '$lib/derived/mission-control/mission-control-orbiters.derived';
37
import { mctrlSatellites } from '$lib/derived/mission-control/mission-control-satellites.derived';
8+
import { mctrlUfos } from '$lib/derived/mission-control/mission-control-ufos.derived';
49
import { derived } from 'svelte/store';
510

611
export const outOfSyncSatellites = derived(
@@ -61,3 +66,31 @@ export const outOfSyncOrbiters = derived(
6166
return !inSync;
6267
}
6368
);
69+
70+
export const outOfSyncUfos = derived(
71+
[consoleUfos, mctrlUfos],
72+
([$consoleUfos, $mctrlUfos]): boolean | undefined => {
73+
// Not yet fully loaded
74+
if ($consoleUfos === undefined || $mctrlUfos === undefined) {
75+
return undefined;
76+
}
77+
78+
// No mission control
79+
if ($mctrlUfos === null) {
80+
return false;
81+
}
82+
83+
if ($consoleUfos?.length === 0 && $mctrlUfos.length === 0) {
84+
return false;
85+
}
86+
87+
const inSync =
88+
$consoleUfos?.length === $mctrlUfos.length &&
89+
($consoleUfos ?? []).every(
90+
({ ufo_id: segment_id }) =>
91+
$mctrlUfos.find(({ ufo_id }) => ufo_id.toText() === segment_id.toText()) !== undefined
92+
);
93+
94+
return !inSync;
95+
}
96+
);

src/frontend/src/lib/i18n/en.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,7 @@
11001100
"upgrade_available": "New upgrades available. Visit the Upgrade Dock to check them out.",
11011101
"short_freezing_threshold": "Short freezing threshold detected. We recommend a longer grace period to give you more time if cycles run out.",
11021102
"learn_more": "Learn more",
1103-
"out_of_sync": "Your satellites and orbiters are out of sync. Reconcile them now."
1103+
"out_of_sync": "Your modules are out of sync. Reconcile them now."
11041104
},
11051105
"not_found": {
11061106
"title": "Oops! You got lost in space.",
@@ -1124,7 +1124,9 @@
11241124
"syncing_satellites_to_console": "Syncing Satellites to Console...",
11251125
"syncing_satellites_to_mctrl": "Syncing Satellites to Mission Control... ({0})",
11261126
"syncing_orbiters_to_console": "Syncing Orbiters to Console...",
1127-
"syncing_orbiters_to_mctrl": "Syncing Orbiters to Mission Control... ({0})"
1127+
"syncing_orbiters_to_mctrl": "Syncing Orbiters to Mission Control... ({0})",
1128+
"syncing_ufos_to_console": "Syncing UFOs to Console...",
1129+
"syncing_ufos_to_mctrl": "Syncing UFOs to Mission Control... ({0})"
11281130
},
11291131
"automation": {
11301132
"title": "Deployments",

0 commit comments

Comments
 (0)