add new route "/vault-import" in the popup
This commit is contained in:
@@ -15,6 +15,7 @@ import { HomeComponent as EditIdentityHomeComponent } from './components/edit-id
|
||||
import { KeysComponent as EditIdentityKeysComponent } from './components/edit-identity/keys/keys.component';
|
||||
import { PermissionsComponent as EditIdentityPermissionsComponent } from './components/edit-identity/permissions/permissions.component';
|
||||
import { RelaysComponent as EditIdentityRelaysComponent } from './components/edit-identity/relays/relays.component';
|
||||
import { VaultImportComponent } from './components/vault-import/vault-import.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
@@ -39,6 +40,10 @@ export const routes: Routes = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'vault-import',
|
||||
component: VaultImportComponent,
|
||||
},
|
||||
{
|
||||
path: 'home',
|
||||
component: HomeComponent,
|
||||
|
||||
@@ -23,7 +23,15 @@ export class ChromeMetaHandler extends GootiMetaHandler {
|
||||
await chrome.storage.local.set(data);
|
||||
}
|
||||
|
||||
async clearData(): Promise<void> {
|
||||
await chrome.storage.local.remove(this.metaProperties);
|
||||
async clearData(keep: string[]): Promise<void> {
|
||||
const toBeRemovedProperties: string[] = [];
|
||||
|
||||
for (const property of this.metaProperties) {
|
||||
if (!keep.includes(property)) {
|
||||
toBeRemovedProperties.push(property);
|
||||
}
|
||||
}
|
||||
|
||||
await chrome.storage.local.remove(toBeRemovedProperties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,7 @@
|
||||
Export Vault
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
(click)="
|
||||
confirm.show(
|
||||
'Do you really want to import a vault? All existing data will be overwritten.',
|
||||
onImportVault.bind(fileInput)
|
||||
)
|
||||
"
|
||||
>
|
||||
<button class="btn btn-primary" (click)="navigate('/vault-import')">
|
||||
Import Vault
|
||||
</button>
|
||||
|
||||
@@ -26,12 +18,12 @@
|
||||
class="btn btn-danger"
|
||||
(click)="
|
||||
confirm.show(
|
||||
'Do you really want to delete your vault with all identities?',
|
||||
onDeleteVault.bind(this)
|
||||
'Do you really want to reset your extension? Every data will be lost.',
|
||||
onResetExtension.bind(this)
|
||||
)
|
||||
"
|
||||
>
|
||||
Delete Vault
|
||||
Reset Extension
|
||||
</button>
|
||||
|
||||
<lib-confirm #confirm> </lib-confirm>
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
BrowserSyncFlow,
|
||||
ConfirmComponent,
|
||||
DateHelper,
|
||||
NavComponent,
|
||||
StartupService,
|
||||
StorageService,
|
||||
} from '@common';
|
||||
@@ -15,7 +16,7 @@ import { getNewStorageServiceConfig } from '../../../common/data/get-new-storage
|
||||
templateUrl: './settings.component.html',
|
||||
styleUrl: './settings.component.scss',
|
||||
})
|
||||
export class SettingsComponent implements OnInit {
|
||||
export class SettingsComponent extends NavComponent implements OnInit {
|
||||
syncFlow: string | undefined;
|
||||
|
||||
readonly #storage = inject(StorageService);
|
||||
@@ -41,9 +42,9 @@ export class SettingsComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
async onDeleteVault() {
|
||||
async onResetExtension() {
|
||||
try {
|
||||
await this.#storage.deleteVault();
|
||||
await this.#storage.resetExtension();
|
||||
this.#startup.startOver(getNewStorageServiceConfig());
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="sam-flex-column center">
|
||||
<div class="sam-flex-column gap" style="align-items: center">
|
||||
<div class="logo-frame">
|
||||
<img src="gooti.svg" height="120" width="120" alt=""/>
|
||||
<img src="gooti.svg" height="120" width="120" alt="" />
|
||||
</div>
|
||||
|
||||
<button
|
||||
@@ -25,18 +25,10 @@
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
(click)="fileInput.click()"
|
||||
(click)="router.navigateByUrl('/vault-import')"
|
||||
>
|
||||
<span>Import a vault</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input
|
||||
#fileInput
|
||||
class="file-input"
|
||||
type="file"
|
||||
(change)="onImportFileChange($event)"
|
||||
accept=".json"
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { BrowserSyncData, StartupService, StorageService } from '@common';
|
||||
import { getNewStorageServiceConfig } from '../../../common/data/get-new-storage-service-config';
|
||||
import { NavComponent } from '@common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
@@ -9,28 +8,6 @@ import { getNewStorageServiceConfig } from '../../../common/data/get-new-storage
|
||||
templateUrl: './home.component.html',
|
||||
styleUrl: './home.component.scss',
|
||||
})
|
||||
export class HomeComponent {
|
||||
export class HomeComponent extends NavComponent {
|
||||
readonly router = inject(Router);
|
||||
readonly #storage = inject(StorageService);
|
||||
readonly #startup = inject(StartupService);
|
||||
|
||||
async onImportFileChange(event: Event) {
|
||||
try {
|
||||
const element = event.currentTarget as HTMLInputElement;
|
||||
const file = element.files !== null ? element.files[0] : undefined;
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
const text = await file.text();
|
||||
const vault = JSON.parse(text) as BrowserSyncData;
|
||||
console.log(vault);
|
||||
|
||||
await this.#storage.importVault(vault);
|
||||
this.#startup.startOver(getNewStorageServiceConfig());
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<div class="custom-header">
|
||||
<lib-icon-button
|
||||
class="button"
|
||||
icon="chevron-left"
|
||||
(click)="navigateBack()"
|
||||
></lib-icon-button>
|
||||
|
||||
<span class="text">Import Vault </span>
|
||||
</div>
|
||||
|
||||
<div class="sam-pl sam-pr sam-flex-column gap">
|
||||
<span class="sam-text-muted">
|
||||
You can select any snapshot that you have previously uploaded on the
|
||||
<a href="options.html" target="_blank">options page</a>.
|
||||
</span>
|
||||
|
||||
<select class="form-select sam-text-sm" [(ngModel)]="selectedSnapshot">
|
||||
@for(snapshot of snapshots; track snapshot) {
|
||||
<option [ngValue]="snapshot">
|
||||
<span>{{ snapshot.fileName }}</span>
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
|
||||
<span class="sam-text-muted" style="font-size: 12px">
|
||||
Please note that your data will be imported regarding your current SYNC
|
||||
setting: <b>{{ syncText }}</b>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="sam-flex-grow"></div>
|
||||
|
||||
<button
|
||||
[disabled]="!selectedSnapshot"
|
||||
class="import-button btn btn-primary"
|
||||
(click)="onClickImport()"
|
||||
>
|
||||
Import
|
||||
</button>
|
||||
@@ -0,0 +1,46 @@
|
||||
:host {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
|
||||
.custom-header {
|
||||
padding-top: var(--size);
|
||||
padding-bottom: var(--size);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto;
|
||||
align-items: center;
|
||||
background: var(--background);
|
||||
|
||||
.button {
|
||||
grid-column-start: 1;
|
||||
grid-column-end: 2;
|
||||
grid-row-start: 1;
|
||||
grid-row-end: 2;
|
||||
justify-self: start;
|
||||
margin-left: 16px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.text {
|
||||
grid-column-start: 1;
|
||||
grid-column-end: 2;
|
||||
grid-row-start: 1;
|
||||
grid-row-end: 2;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
justify-self: center;
|
||||
height: 32px;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.import-button {
|
||||
margin: var(--size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { VaultImportComponent } from './vault-import.component';
|
||||
|
||||
describe('VaultImportComponent', () => {
|
||||
let component: VaultImportComponent;
|
||||
let fixture: ComponentFixture<VaultImportComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [VaultImportComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(VaultImportComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Component, inject, OnInit } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import {
|
||||
BrowserSyncFlow,
|
||||
GootiMetaData_VaultSnapshot,
|
||||
IconButtonComponent,
|
||||
NavComponent,
|
||||
StartupService,
|
||||
StorageService,
|
||||
} from '@common';
|
||||
import browser from 'webextension-polyfill';
|
||||
import { getNewStorageServiceConfig } from '../../common/data/get-new-storage-service-config';
|
||||
|
||||
@Component({
|
||||
selector: 'app-vault-import',
|
||||
imports: [IconButtonComponent, FormsModule],
|
||||
templateUrl: './vault-import.component.html',
|
||||
styleUrl: './vault-import.component.scss',
|
||||
})
|
||||
export class VaultImportComponent extends NavComponent implements OnInit {
|
||||
snapshots: GootiMetaData_VaultSnapshot[] = [];
|
||||
selectedSnapshot: GootiMetaData_VaultSnapshot | undefined;
|
||||
syncText: string | undefined;
|
||||
|
||||
readonly #storage = inject(StorageService);
|
||||
readonly #startup = inject(StartupService);
|
||||
|
||||
async openOptionsPage() {
|
||||
await browser.runtime.openOptionsPage();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.#loadData();
|
||||
}
|
||||
|
||||
async onClickImport() {
|
||||
if (!this.selectedSnapshot) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.#storage.deleteVault(true);
|
||||
await this.#storage.importVault(this.selectedSnapshot.data);
|
||||
this.#storage.isInitialized = false;
|
||||
this.#startup.startOver(getNewStorageServiceConfig());
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
async #loadData() {
|
||||
this.snapshots = (
|
||||
this.#storage.getGootiMetaHandler().gootiMetaData?.vaultSnapshots ?? []
|
||||
).sortBy((x) => x.fileName, 'desc');
|
||||
|
||||
const syncFlow =
|
||||
this.#storage.getGootiMetaHandler().gootiMetaData?.syncFlow;
|
||||
|
||||
switch (syncFlow) {
|
||||
case BrowserSyncFlow.BROWSER_SYNC:
|
||||
this.syncText = 'GOOGLE CHROME';
|
||||
break;
|
||||
|
||||
default:
|
||||
case BrowserSyncFlow.NO_SYNC:
|
||||
this.syncText = 'OFF';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="content-login-vault">
|
||||
<div class="sam-flex-column gap" style="align-items: center">
|
||||
<div class="logo-frame">
|
||||
<img src="gooti.svg" height="120" width="120" alt=""/>
|
||||
<img src="gooti.svg" height="120" width="120" alt="" />
|
||||
</div>
|
||||
|
||||
<div class="sam-mt-2 input-group">
|
||||
@@ -45,14 +45,14 @@
|
||||
class="sam-mt"
|
||||
(click)="
|
||||
confirm.show(
|
||||
'Do you really want to delete your vault? All existing data will be lost.',
|
||||
onClickDeleteVault.bind(this)
|
||||
'Do you really want to reset the extension? All data will be lost.',
|
||||
onClickResetExtension.bind(this)
|
||||
)
|
||||
"
|
||||
type="button"
|
||||
class="btn btn-link"
|
||||
>
|
||||
Delete Vault
|
||||
Reset Extension
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -43,9 +43,9 @@ export class VaultLoginComponent {
|
||||
}
|
||||
}
|
||||
|
||||
async onClickDeleteVault() {
|
||||
async onClickResetExtension() {
|
||||
try {
|
||||
await this.#storage.deleteVault();
|
||||
await this.#storage.resetExtension();
|
||||
this.#startup.startOver(getNewStorageServiceConfig());
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import { inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
export class NavComponent {
|
||||
readonly #router = inject(Router);
|
||||
|
||||
navigateBack() {
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
navigate(path: string) {
|
||||
this.#router.navigate([path]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,5 +39,5 @@ export abstract class GootiMetaHandler {
|
||||
await this.saveFullData(this.#gootiMetaData);
|
||||
}
|
||||
|
||||
abstract clearData(): Promise<void>;
|
||||
abstract clearData(keep: string[]): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -120,7 +120,6 @@ export const deleteVault = async function (
|
||||
|
||||
await this.getBrowserSyncHandler().clearData();
|
||||
await this.getBrowserSessionHandler().clearData();
|
||||
await this.getGootiMetaHandler().clearData();
|
||||
|
||||
if (!doNotSetIsInitializedToFalse) {
|
||||
this.isInitialized = false;
|
||||
|
||||
@@ -115,6 +115,14 @@ export class StorageService {
|
||||
await deleteVault.call(this, doNotSetIsInitializedToFalse);
|
||||
}
|
||||
|
||||
async resetExtension() {
|
||||
this.assureIsInitialized();
|
||||
await this.getBrowserSyncHandler().clearData();
|
||||
await this.getBrowserSessionHandler().clearData();
|
||||
await this.getGootiMetaHandler().clearData([]);
|
||||
this.isInitialized = false;
|
||||
}
|
||||
|
||||
async unlockVault(password: string): Promise<void> {
|
||||
await unlockVault.call(this, password);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user