From 45a6a930c983bbb361c1b8135cd2eacf3f3f861e Mon Sep 17 00:00:00 2001
From: Matt Hill
Date: Thu, 10 Nov 2022 10:20:52 -0700
Subject: [PATCH] Add guid to partition type (#1932)
* add guid to partitions and implement pipe in shared to return guid for any disk
* fix bug and clean up
---
.../src/app/pages/home/home.module.ts | 6 +-
.../src/app/pages/home/home.page.html | 83 +++++++++++--------
.../src/app/services/api/mock-api.service.ts | 29 ++++++-
.../src/app/app-routing.module.ts | 5 ++
.../app/pages/attach/attach-routing.module.ts | 16 ++++
.../src/app/pages/attach/attach.module.ts | 21 +++++
.../src/app/pages/attach/attach.page.html | 74 +++++++++++++++++
.../src/app/pages/attach/attach.page.scss | 4 +
.../src/app/pages/attach/attach.page.ts | 77 +++++++++++++++++
.../src/app/pages/embassy/embassy.module.ts | 6 +-
.../src/app/pages/embassy/embassy.page.ts | 9 +-
.../src/app/pages/home/home.page.html | 35 ++++++--
.../src/app/pages/home/home.page.ts | 72 ++--------------
.../src/app/pages/transfer/transfer.module.ts | 6 +-
.../src/app/pages/transfer/transfer.page.html | 9 +-
.../src/app/pages/transfer/transfer.page.ts | 12 +--
.../src/app/services/api/mock-api.service.ts | 38 +++++++--
.../shared/src/pipes/guid/guid.module.ts | 8 ++
.../shared/src/pipes/guid/guid.pipe.ts | 11 +++
frontend/projects/shared/src/public-api.ts | 2 +
frontend/projects/shared/src/types/api.ts | 1 +
21 files changed, 393 insertions(+), 131 deletions(-)
create mode 100644 frontend/projects/setup-wizard/src/app/pages/attach/attach-routing.module.ts
create mode 100644 frontend/projects/setup-wizard/src/app/pages/attach/attach.module.ts
create mode 100644 frontend/projects/setup-wizard/src/app/pages/attach/attach.page.html
create mode 100644 frontend/projects/setup-wizard/src/app/pages/attach/attach.page.scss
create mode 100644 frontend/projects/setup-wizard/src/app/pages/attach/attach.page.ts
create mode 100644 frontend/projects/shared/src/pipes/guid/guid.module.ts
create mode 100644 frontend/projects/shared/src/pipes/guid/guid.pipe.ts
diff --git a/frontend/projects/install-wizard/src/app/pages/home/home.module.ts b/frontend/projects/install-wizard/src/app/pages/home/home.module.ts
index 79afa2ac5..e7cd274f6 100644
--- a/frontend/projects/install-wizard/src/app/pages/home/home.module.ts
+++ b/frontend/projects/install-wizard/src/app/pages/home/home.module.ts
@@ -5,7 +5,10 @@ import { IonicModule } from '@ionic/angular'
import { FormsModule } from '@angular/forms'
import { HomePage } from './home.page'
import { SwiperModule } from 'swiper/angular'
-import { UnitConversionPipesModule } from '@start9labs/shared'
+import {
+ UnitConversionPipesModule,
+ GuidPipePipesModule,
+} from '@start9labs/shared'
const routes: Routes = [
{
@@ -22,6 +25,7 @@ const routes: Routes = [
RouterModule.forChild(routes),
SwiperModule,
UnitConversionPipesModule,
+ GuidPipePipesModule,
],
declarations: [HomePage],
})
diff --git a/frontend/projects/install-wizard/src/app/pages/home/home.page.html b/frontend/projects/install-wizard/src/app/pages/home/home.page.html
index 91e454d99..61d82eebc 100644
--- a/frontend/projects/install-wizard/src/app/pages/home/home.page.html
+++ b/frontend/projects/install-wizard/src/app/pages/home/home.page.html
@@ -27,6 +27,7 @@
+
+
+
-
-
-
-
- Re-Install embassyOS
-
- Will preserve existing embassyOS data
-
-
-
-
-
-
- {{ !!selectedDisk?.guid ? 'Factory Reset' : 'Install
- embassyOS' }}
-
- Will delete existing data on disk
-
-
+
+
+
+
+
+
+ Re-Install embassyOS
+
+ Will preserve existing embassyOS data
+
+
+
+
+
+
+
+
+
+ {{ (selectedDisk | guid) ? 'Factory Reset' : 'Install
+ embassyOS' }}
+
+
+ Will delete existing data on disk
+
+
+
diff --git a/frontend/projects/install-wizard/src/app/services/api/mock-api.service.ts b/frontend/projects/install-wizard/src/app/services/api/mock-api.service.ts
index 9f035d2cd..9caf4f88e 100644
--- a/frontend/projects/install-wizard/src/app/services/api/mock-api.service.ts
+++ b/frontend/projects/install-wizard/src/app/services/api/mock-api.service.ts
@@ -24,6 +24,7 @@ export class MockApiService implements ApiService {
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
'wrapped-key': null,
},
+ guid: null,
},
],
capacity: 123456789123,
@@ -40,15 +41,39 @@ export class MockApiService implements ApiService {
capacity: 73264762332,
used: null,
'embassy-os': {
- version: '0.3.1',
+ version: '0.3.3',
full: true,
'password-hash':
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
'wrapped-key': null,
},
+ guid: null,
},
],
- capacity: 123456789123,
+ capacity: 124456789123,
+ guid: null,
+ },
+ {
+ logicalname: 'wxyz',
+ vendor: 'SanDisk',
+ model: 'Specialness',
+ partitions: [
+ {
+ logicalname: 'pbcba',
+ label: null,
+ capacity: 73264762332,
+ used: null,
+ 'embassy-os': {
+ version: '0.3.2',
+ full: true,
+ 'password-hash':
+ '$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
+ 'wrapped-key': null,
+ },
+ guid: 'guid-guid-guid-guid',
+ },
+ ],
+ capacity: 123459789123,
guid: null,
},
]
diff --git a/frontend/projects/setup-wizard/src/app/app-routing.module.ts b/frontend/projects/setup-wizard/src/app/app-routing.module.ts
index 38f320436..ccc184340 100644
--- a/frontend/projects/setup-wizard/src/app/app-routing.module.ts
+++ b/frontend/projects/setup-wizard/src/app/app-routing.module.ts
@@ -8,6 +8,11 @@ const routes: Routes = [
loadChildren: () =>
import('./pages/home/home.module').then(m => m.HomePageModule),
},
+ {
+ path: 'attach',
+ loadChildren: () =>
+ import('./pages/attach/attach.module').then(m => m.AttachPageModule),
+ },
{
path: 'recover',
loadChildren: () =>
diff --git a/frontend/projects/setup-wizard/src/app/pages/attach/attach-routing.module.ts b/frontend/projects/setup-wizard/src/app/pages/attach/attach-routing.module.ts
new file mode 100644
index 000000000..8ba45b29c
--- /dev/null
+++ b/frontend/projects/setup-wizard/src/app/pages/attach/attach-routing.module.ts
@@ -0,0 +1,16 @@
+import { NgModule } from '@angular/core'
+import { RouterModule, Routes } from '@angular/router'
+import { AttachPage } from './attach.page'
+
+const routes: Routes = [
+ {
+ path: '',
+ component: AttachPage,
+ },
+]
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class AttachPageRoutingModule {}
diff --git a/frontend/projects/setup-wizard/src/app/pages/attach/attach.module.ts b/frontend/projects/setup-wizard/src/app/pages/attach/attach.module.ts
new file mode 100644
index 000000000..486884878
--- /dev/null
+++ b/frontend/projects/setup-wizard/src/app/pages/attach/attach.module.ts
@@ -0,0 +1,21 @@
+import { NgModule } from '@angular/core'
+import { CommonModule } from '@angular/common'
+import { IonicModule } from '@ionic/angular'
+import {
+ GuidPipePipesModule,
+ UnitConversionPipesModule,
+} from '@start9labs/shared'
+import { AttachPage } from './attach.page'
+import { AttachPageRoutingModule } from './attach-routing.module'
+
+@NgModule({
+ declarations: [AttachPage],
+ imports: [
+ CommonModule,
+ IonicModule,
+ AttachPageRoutingModule,
+ UnitConversionPipesModule,
+ GuidPipePipesModule,
+ ],
+})
+export class AttachPageModule {}
diff --git a/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.html b/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.html
new file mode 100644
index 000000000..05097f920
--- /dev/null
+++ b/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+

+
+
+
+
+ Use Existing Drive
+ Select the physical drive containing your Embassy
+ data
+
+
+
+
+
+
+
+
+ Available Drives
+
+
+ No valid Embassy data drives found. Please make sure the drive
+ is a valid Embassy data drive (not a backup) and is firmly
+ connected, then refresh the page.
+
+
+
+
+
+
+ {{ drive.logicalname }}
+
+ {{ drive.vendor || 'Unknown Vendor' }} - {{ drive.model ||
+ 'Unknown Model' }}
+
+ Capacity: {{ drive.capacity | convertBytes }}
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
diff --git a/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.scss b/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.scss
new file mode 100644
index 000000000..687b91ecf
--- /dev/null
+++ b/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.scss
@@ -0,0 +1,4 @@
+.target-label {
+ font-weight: bold;
+ padding-bottom: 6px;
+}
diff --git a/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.ts b/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.ts
new file mode 100644
index 000000000..a6fd69a09
--- /dev/null
+++ b/frontend/projects/setup-wizard/src/app/pages/attach/attach.page.ts
@@ -0,0 +1,77 @@
+import { Component } from '@angular/core'
+import {
+ LoadingController,
+ ModalController,
+ NavController,
+} from '@ionic/angular'
+import { ApiService } from 'src/app/services/api/api.service'
+import { DiskInfo, ErrorToastService } from '@start9labs/shared'
+import { StateService } from 'src/app/services/state.service'
+import { PasswordPage } from 'src/app/modals/password/password.page'
+
+@Component({
+ selector: 'app-attach',
+ templateUrl: 'attach.page.html',
+ styleUrls: ['attach.page.scss'],
+})
+export class AttachPage {
+ loading = true
+ drives: DiskInfo[] = []
+
+ constructor(
+ private readonly apiService: ApiService,
+ private readonly navCtrl: NavController,
+ private readonly errToastService: ErrorToastService,
+ private readonly stateService: StateService,
+ private readonly modalCtrl: ModalController,
+ private readonly loadingCtrl: LoadingController,
+ ) {}
+
+ async ngOnInit() {
+ await this.getDrives()
+ }
+
+ async refresh() {
+ this.loading = true
+ await this.getDrives()
+ }
+
+ async getDrives() {
+ try {
+ const drives = await this.apiService.getDrives()
+ this.drives = drives.filter(d => d.partitions.length)
+ } catch (e: any) {
+ this.errToastService.present(e)
+ } finally {
+ this.loading = false
+ }
+ }
+
+ async select(guid: string) {
+ const modal = await this.modalCtrl.create({
+ component: PasswordPage,
+ componentProps: { storageDrive: true },
+ })
+ modal.onDidDismiss().then(res => {
+ if (res.data && res.data.password) {
+ this.attachDrive(guid, res.data.password)
+ }
+ })
+ await modal.present()
+ }
+
+ private async attachDrive(guid: string, password: string) {
+ const loader = await this.loadingCtrl.create({
+ message: 'Attaching Drive',
+ })
+ await loader.present()
+ try {
+ await this.stateService.importDrive(guid, password)
+ await this.navCtrl.navigateForward(`/success`)
+ } catch (e: any) {
+ this.errToastService.present(e)
+ } finally {
+ loader.dismiss()
+ }
+ }
+}
diff --git a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.module.ts b/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.module.ts
index a49e06c9c..7a7594b41 100644
--- a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.module.ts
+++ b/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.module.ts
@@ -2,7 +2,10 @@ import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'
import { IonicModule } from '@ionic/angular'
import { FormsModule } from '@angular/forms'
-import { UnitConversionPipesModule } from '@start9labs/shared'
+import {
+ GuidPipePipesModule,
+ UnitConversionPipesModule,
+} from '@start9labs/shared'
import { EmbassyPage } from './embassy.page'
import { PasswordPageModule } from '../../modals/password/password.module'
import { EmbassyPageRoutingModule } from './embassy-routing.module'
@@ -15,6 +18,7 @@ import { EmbassyPageRoutingModule } from './embassy-routing.module'
EmbassyPageRoutingModule,
PasswordPageModule,
UnitConversionPipesModule,
+ GuidPipePipesModule,
],
declarations: [EmbassyPage],
})
diff --git a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts b/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts
index 4dcc2f13d..029787118 100644
--- a/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts
+++ b/frontend/projects/setup-wizard/src/app/pages/embassy/embassy.page.ts
@@ -10,7 +10,7 @@ import {
BackupRecoverySource,
DiskRecoverySource,
} from 'src/app/services/api/api.service'
-import { DiskInfo, ErrorToastService } from '@start9labs/shared'
+import { DiskInfo, ErrorToastService, GuidPipe } from '@start9labs/shared'
import { StateService } from 'src/app/services/state.service'
import { PasswordPage } from '../../modals/password/password.page'
import { ActivatedRoute } from '@angular/router'
@@ -19,6 +19,7 @@ import { ActivatedRoute } from '@angular/router'
selector: 'app-embassy',
templateUrl: 'embassy.page.html',
styleUrls: ['embassy.page.scss'],
+ providers: [GuidPipe],
})
export class EmbassyPage {
storageDrives: DiskInfo[] = []
@@ -32,6 +33,7 @@ export class EmbassyPage {
private readonly stateService: StateService,
private readonly loadingCtrl: LoadingController,
private readonly errorToastService: ErrorToastService,
+ private readonly guidPipe: GuidPipe,
private route: ActivatedRoute,
) {}
@@ -71,7 +73,10 @@ export class EmbassyPage {
}
async chooseDrive(drive: DiskInfo) {
- if (!!drive.partitions.find(p => p.used) || !!drive.guid) {
+ if (
+ this.guidPipe.transform(drive) ||
+ !!drive.partitions.find(p => p.used)
+ ) {
const alert = await this.alertCtrl.create({
header: 'Warning',
subHeader: 'Drive contains data!',
diff --git a/frontend/projects/setup-wizard/src/app/pages/home/home.page.html b/frontend/projects/setup-wizard/src/app/pages/home/home.page.html
index 5cb8175b1..8037bedc3 100644
--- a/frontend/projects/setup-wizard/src/app/pages/home/home.page.html
+++ b/frontend/projects/setup-wizard/src/app/pages/home/home.page.html
@@ -1,4 +1,4 @@
-
+
@@ -6,7 +6,7 @@
-
+
-
+
+
+
Get started with a brand new Embassy
+
+
+
+
+
Restore From Backup
- Recover an Embassy from an encrypted backup
+ Restore an Embassy from an encrypted backup
-
+
+
+
Use Existing Drive
- Attach and use a valid Embassy data drive
+
+ Use an existing, valid Embassy data drive (not a backup)
+
+
+
Transfer
- Transfer data to a new drive
(e.g. upgrade to a
- larger drive or an Embassy Pro)
+ Transfer data from an existing, valid Embassy data drive
+ (not a backup) to a new drive
(e.g. in order to
+ transfer data to another device)
diff --git a/frontend/projects/setup-wizard/src/app/pages/home/home.page.ts b/frontend/projects/setup-wizard/src/app/pages/home/home.page.ts
index bf25183a6..94712abca 100644
--- a/frontend/projects/setup-wizard/src/app/pages/home/home.page.ts
+++ b/frontend/projects/setup-wizard/src/app/pages/home/home.page.ts
@@ -1,14 +1,6 @@
import { Component } from '@angular/core'
-import {
- AlertController,
- IonicSlides,
- LoadingController,
- ModalController,
- NavController,
-} from '@ionic/angular'
-import { PasswordPage } from 'src/app/modals/password/password.page'
+import { IonicSlides } from '@ionic/angular'
import { ApiService } from 'src/app/services/api/api.service'
-import { StateService } from 'src/app/services/state.service'
import SwiperCore, { Swiper } from 'swiper'
import { ErrorToastService } from '@start9labs/shared'
@@ -21,35 +13,26 @@ SwiperCore.use([IonicSlides])
})
export class HomePage {
swiper?: Swiper
- guid?: string | null
error = false
- loaded = false
+ loading = true
constructor(
private readonly api: ApiService,
- private readonly modalCtrl: ModalController,
- private readonly alertCtrl: AlertController,
- private readonly loadingCtrl: LoadingController,
- private readonly stateService: StateService,
- private readonly navCtrl: NavController,
private readonly errToastService: ErrorToastService,
) {}
- async ngOnInit() {
+ async ionViewDidEnter() {
+ if (this.swiper) {
+ this.swiper.allowTouchMove = false
+ }
+
try {
await this.api.getPubKey()
- const disks = await this.api.getDrives()
- this.guid = disks.find(d => !!d.guid)?.guid
} catch (e: any) {
this.error = true
this.errToastService.present(e)
- }
- }
-
- async ionViewDidEnter() {
- this.loaded = true // needed to accommodate autoHight="true" on swiper. Otherwise Swiper height might be 0 when navigating *to* this page from later page. Happens on refresh.
- if (this.swiper) {
- this.swiper.allowTouchMove = false
+ } finally {
+ this.loading = false
}
}
@@ -64,41 +47,4 @@ export class HomePage {
previous() {
this.swiper?.slidePrev(500)
}
-
- async import() {
- if (this.guid) {
- const modal = await this.modalCtrl.create({
- component: PasswordPage,
- componentProps: { storageDrive: true },
- })
- modal.onDidDismiss().then(res => {
- if (res.data && res.data.password) {
- this.importDrive(res.data.password)
- }
- })
- await modal.present()
- } else {
- const alert = await this.alertCtrl.create({
- header: 'Drive Not Found',
- message:
- 'Please make sure the drive is a valid Embassy data drive (not a backup) and is firmly connected, then refresh the page.',
- })
- await alert.present()
- }
- }
-
- private async importDrive(password: string) {
- const loader = await this.loadingCtrl.create({
- message: 'Importing Drive',
- })
- await loader.present()
- try {
- await this.stateService.importDrive(this.guid!, password)
- await this.navCtrl.navigateForward(`/success`)
- } catch (e: any) {
- this.errToastService.present(e)
- } finally {
- loader.dismiss()
- }
- }
}
diff --git a/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.module.ts b/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.module.ts
index e4169d50a..2dfd57b20 100644
--- a/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.module.ts
+++ b/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.module.ts
@@ -1,7 +1,10 @@
import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'
import { IonicModule } from '@ionic/angular'
-import { UnitConversionPipesModule } from '@start9labs/shared'
+import {
+ GuidPipePipesModule,
+ UnitConversionPipesModule,
+} from '@start9labs/shared'
import { TransferPage } from './transfer.page'
import { TransferPageRoutingModule } from './transfer-routing.module'
@@ -12,6 +15,7 @@ import { TransferPageRoutingModule } from './transfer-routing.module'
IonicModule,
TransferPageRoutingModule,
UnitConversionPipesModule,
+ GuidPipePipesModule,
],
})
export class TransferPageModule {}
diff --git a/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.page.html b/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.page.html
index 3b533857e..e24fecc18 100644
--- a/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.page.html
+++ b/frontend/projects/setup-wizard/src/app/pages/transfer/transfer.page.html
@@ -10,7 +10,7 @@
Transfer
Select the physical drive containing your previous Embassy
+ >Select the physical drive containing your Embassy
data
@@ -28,7 +28,12 @@
Available Drives
-
+
d.partitions.length && d.guid)
+ const drives = await this.apiService.getDrives()
+ this.drives = drives.filter(d => d.partitions.length)
} catch (e: any) {
this.errToastService.present(e)
} finally {
@@ -41,11 +41,7 @@ export class TransferPage {
}
}
- async select(target: DiskInfo) {
- const { logicalname, guid } = target
-
- if (!logicalname) return
-
+ async select(guid: string) {
const alert = await this.alertCtrl.create({
header: 'Warning',
message:
@@ -60,7 +56,7 @@ export class TransferPage {
handler: () => {
this.stateService.recoverySource = {
type: 'migrate',
- guid: guid!,
+ guid,
}
this.navCtrl.navigateForward(`/embassy`, {
queryParams: { action: 'transfer' },
diff --git a/frontend/projects/setup-wizard/src/app/services/api/mock-api.service.ts b/frontend/projects/setup-wizard/src/app/services/api/mock-api.service.ts
index 475aa79c0..7f016ca87 100644
--- a/frontend/projects/setup-wizard/src/app/services/api/mock-api.service.ts
+++ b/frontend/projects/setup-wizard/src/app/services/api/mock-api.service.ts
@@ -24,9 +24,8 @@ export class MockApiService extends ApiService {
async getPubKey() {
await pauseFor(1000)
- const keystore = jose.JWK.createKeyStore()
-
// randomly generated
+ // const keystore = jose.JWK.createKeyStore()
// this.pubkey = await keystore.generate('EC', 'P-256')
// generated from backend
@@ -58,6 +57,7 @@ export class MockApiService extends ApiService {
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
'wrapped-key': null,
},
+ guid: null,
},
],
capacity: 123456789123,
@@ -65,8 +65,8 @@ export class MockApiService extends ApiService {
},
{
logicalname: 'dcba',
- vendor: 'Samsung',
- model: 'T5',
+ vendor: 'Crucial',
+ model: 'MX500',
partitions: [
{
logicalname: 'pbcba',
@@ -74,16 +74,40 @@ export class MockApiService extends ApiService {
capacity: 73264762332,
used: null,
'embassy-os': {
- version: '0.3.1',
+ version: '0.3.3',
full: true,
'password-hash':
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
'wrapped-key': null,
},
+ guid: null,
},
],
- capacity: 123456789123,
- guid: 'uuid-uuid-uuid-uuid',
+ capacity: 124456789123,
+ guid: null,
+ },
+ {
+ logicalname: 'wxyz',
+ vendor: 'SanDisk',
+ model: 'Specialness',
+ partitions: [
+ {
+ logicalname: 'pbcba',
+ label: null,
+ capacity: 73264762332,
+ used: null,
+ 'embassy-os': {
+ version: '0.3.2',
+ full: true,
+ 'password-hash':
+ '$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
+ 'wrapped-key': null,
+ },
+ guid: 'guid-guid-guid-guid',
+ },
+ ],
+ capacity: 123459789123,
+ guid: null,
},
]
}
diff --git a/frontend/projects/shared/src/pipes/guid/guid.module.ts b/frontend/projects/shared/src/pipes/guid/guid.module.ts
new file mode 100644
index 000000000..bd4e22f5f
--- /dev/null
+++ b/frontend/projects/shared/src/pipes/guid/guid.module.ts
@@ -0,0 +1,8 @@
+import { NgModule } from '@angular/core'
+import { GuidPipe } from './guid.pipe'
+
+@NgModule({
+ declarations: [GuidPipe],
+ exports: [GuidPipe],
+})
+export class GuidPipePipesModule {}
diff --git a/frontend/projects/shared/src/pipes/guid/guid.pipe.ts b/frontend/projects/shared/src/pipes/guid/guid.pipe.ts
new file mode 100644
index 000000000..a095bd929
--- /dev/null
+++ b/frontend/projects/shared/src/pipes/guid/guid.pipe.ts
@@ -0,0 +1,11 @@
+import { Pipe, PipeTransform } from '@angular/core'
+import { DiskInfo } from '../../types/api'
+
+@Pipe({
+ name: 'guid',
+})
+export class GuidPipe implements PipeTransform {
+ transform(disk: DiskInfo): string | null {
+ return disk.guid || disk.partitions.find(p => p.guid)?.guid || null
+ }
+}
diff --git a/frontend/projects/shared/src/public-api.ts b/frontend/projects/shared/src/public-api.ts
index 0745f5561..a957014ee 100644
--- a/frontend/projects/shared/src/public-api.ts
+++ b/frontend/projects/shared/src/public-api.ts
@@ -24,6 +24,8 @@ export * from './directives/safe-links/safe-links.module'
export * from './pipes/emver/emver.module'
export * from './pipes/emver/emver.pipe'
+export * from './pipes/guid/guid.module'
+export * from './pipes/guid/guid.pipe'
export * from './pipes/markdown/markdown.module'
export * from './pipes/markdown/markdown.pipe'
export * from './pipes/shared/shared.module'
diff --git a/frontend/projects/shared/src/types/api.ts b/frontend/projects/shared/src/types/api.ts
index 21a869c4c..4726c05cd 100644
--- a/frontend/projects/shared/src/types/api.ts
+++ b/frontend/projects/shared/src/types/api.ts
@@ -32,6 +32,7 @@ export interface PartitionInfo {
capacity: number
used: number | null
'embassy-os': EmbassyOSDiskInfo | null
+ guid: string | null
}
export type EmbassyOSDiskInfo = {