|
@ -1,16 +1,9 @@ |
|
|
/** |
|
|
/** * Data Export Section Component * * Provides UI and functionality for |
|
|
* Data Export Section Component |
|
|
exporting user data and backing up identifier seeds. * Includes buttons for seed |
|
|
* |
|
|
backup and database export, with platform-specific download instructions. * * |
|
|
* Provides UI and functionality for exporting user data and backing up identifier seeds. |
|
|
@component * @displayName DataExportSection * @example * ```vue * |
|
|
* Includes buttons for seed backup and database export, with platform-specific download instructions. |
|
|
<DataExportSection :active-did="currentDid" /> |
|
|
* |
|
|
* ``` */ |
|
|
* @component |
|
|
|
|
|
* @displayName DataExportSection |
|
|
|
|
|
* @example |
|
|
|
|
|
* ```vue |
|
|
|
|
|
* <DataExportSection :active-did="currentDid" /> |
|
|
|
|
|
* ``` |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
<template> |
|
|
<template> |
|
|
<div |
|
|
<div |
|
@ -36,28 +29,24 @@ |
|
|
(excluding Identifier Data) |
|
|
(excluding Identifier Data) |
|
|
</button> |
|
|
</button> |
|
|
<a |
|
|
<a |
|
|
|
|
|
v-if="platformService?.needsSecondaryDownloadLink()" |
|
|
ref="downloadLink" |
|
|
ref="downloadLink" |
|
|
:class="computedDownloadLinkClassNames()" |
|
|
:class="computedDownloadLinkClassNames()" |
|
|
class="block w-full text-center text-md bg-gradient-to-b from-green-500 to-green-800 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-6" |
|
|
class="block w-full text-center text-md bg-gradient-to-b from-green-500 to-green-800 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-6" |
|
|
> |
|
|
> |
|
|
If no download happened yet, click again here to download now. |
|
|
If no download happened yet, click again here to download now. |
|
|
</a> |
|
|
</a> |
|
|
<div class="mt-4" v-if="showPlatformInstructions"> |
|
|
<div |
|
|
<p> |
|
|
v-if="platformService?.getExportInstructions().length > 0" |
|
|
After the download, you can save the file in your preferred storage |
|
|
class="mt-4" |
|
|
location. |
|
|
> |
|
|
|
|
|
<p |
|
|
|
|
|
v-for="instruction in platformService?.getExportInstructions()" |
|
|
|
|
|
:key="instruction" |
|
|
|
|
|
class="list-disc list-outside ml-4" |
|
|
|
|
|
> |
|
|
|
|
|
{{ instruction }} |
|
|
</p> |
|
|
</p> |
|
|
<ul> |
|
|
|
|
|
<li v-if="platformService.isCapacitor() && isIOS" class="list-disc list-outside ml-4"> |
|
|
|
|
|
On iOS: Choose "More..." and select a place in iCloud, or go "Back" |
|
|
|
|
|
and save to another location. |
|
|
|
|
|
</li> |
|
|
|
|
|
<li v-if="platformService.isCapacitor() && !isIOS" class="list-disc list-outside ml-4"> |
|
|
|
|
|
On Android: Choose "Open" and then share |
|
|
|
|
|
<font-awesome icon="share-nodes" class="fa-fw" /> |
|
|
|
|
|
to your prefered place. |
|
|
|
|
|
</li> |
|
|
|
|
|
</ul> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</template> |
|
|
</template> |
|
@ -100,60 +89,72 @@ export default class DataExportSection extends Vue { |
|
|
/** |
|
|
/** |
|
|
* Platform service instance for platform-specific operations |
|
|
* Platform service instance for platform-specific operations |
|
|
*/ |
|
|
*/ |
|
|
private platformService: PlatformService = PlatformServiceFactory.getInstance(); |
|
|
private platformService?: PlatformService; |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Whether the current platform is iOS |
|
|
|
|
|
*/ |
|
|
|
|
|
private get isIOS(): boolean { |
|
|
|
|
|
return /iPad|iPhone|iPod/.test(navigator.userAgent); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* Whether to show platform-specific instructions |
|
|
|
|
|
*/ |
|
|
|
|
|
private get showPlatformInstructions(): boolean { |
|
|
|
|
|
return this.platformService.isCapacitor(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Lifecycle hook to clean up resources |
|
|
* Lifecycle hook to clean up resources |
|
|
* Revokes object URL when component is unmounted (web platform only) |
|
|
* Revokes object URL when component is unmounted (web platform only) |
|
|
*/ |
|
|
*/ |
|
|
beforeUnmount() { |
|
|
beforeUnmount() { |
|
|
if (this.downloadUrl && this.platformService.isWeb()) { |
|
|
if (this.downloadUrl && this.platformService?.needsDownloadCleanup()) { |
|
|
URL.revokeObjectURL(this.downloadUrl); |
|
|
URL.revokeObjectURL(this.downloadUrl); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async mounted() { |
|
|
|
|
|
this.platformService = await PlatformServiceFactory.getInstance(); |
|
|
|
|
|
logger.log( |
|
|
|
|
|
"DataExportSection mounted on platform:", |
|
|
|
|
|
process.env.VITE_PLATFORM, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Exports the database to a JSON file |
|
|
* Exports the database to a JSON file |
|
|
* Uses platform-specific methods for saving the exported data |
|
|
* Uses platform-specific methods for saving the exported data |
|
|
* Shows success/error notifications to user |
|
|
* Shows success/error notifications to user |
|
|
* |
|
|
* |
|
|
* @throws {Error} If export fails |
|
|
* @throws {Error} If export fails |
|
|
* @emits {Notification} Success or error notification |
|
|
* @emits {Notification} Success or error notification |
|
|
*/ |
|
|
*/ |
|
|
public async exportDatabase() { |
|
|
public async exportDatabase() { |
|
|
try { |
|
|
try { |
|
|
|
|
|
if (!this.platformService) { |
|
|
|
|
|
this.platformService = await PlatformServiceFactory.getInstance(); |
|
|
|
|
|
} |
|
|
|
|
|
logger.log( |
|
|
|
|
|
"Starting database export on platform:", |
|
|
|
|
|
process.env.VITE_PLATFORM, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
const blob = await db.export({ prettyJson: true }); |
|
|
const blob = await db.export({ prettyJson: true }); |
|
|
const fileName = `${db.name}-backup.json`; |
|
|
const fileName = `${db.name}-backup.json`; |
|
|
|
|
|
logger.log("Database export details:", { |
|
|
|
|
|
fileName, |
|
|
|
|
|
blobSize: `${blob.size} bytes`, |
|
|
|
|
|
platform: process.env.VITE_PLATFORM, |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
await this.platformService.exportDatabase(blob, fileName); |
|
|
await this.platformService.exportDatabase(blob, fileName); |
|
|
|
|
|
logger.log("Database export completed successfully:", { |
|
|
|
|
|
fileName, |
|
|
|
|
|
platform: process.env.VITE_PLATFORM, |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
this.$notify( |
|
|
this.$notify( |
|
|
{ |
|
|
{ |
|
|
group: "alert", |
|
|
group: "alert", |
|
|
type: "success", |
|
|
type: "success", |
|
|
title: "Export Successful", |
|
|
title: "Export Successful", |
|
|
text: this.platformService.isWeb() |
|
|
text: this.platformService.getExportSuccessMessage(), |
|
|
? "See your downloads directory for the backup. It is in the Dexie format." |
|
|
|
|
|
: "The backup has been saved to your device.", |
|
|
|
|
|
}, |
|
|
}, |
|
|
-1, |
|
|
-1, |
|
|
); |
|
|
); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
logger.error("Export Error:", error); |
|
|
logger.error("Database export failed:", { |
|
|
|
|
|
error, |
|
|
|
|
|
platform: process.env.VITE_PLATFORM, |
|
|
|
|
|
}); |
|
|
this.$notify( |
|
|
this.$notify( |
|
|
{ |
|
|
{ |
|
|
group: "alert", |
|
|
group: "alert", |
|
@ -172,7 +173,8 @@ export default class DataExportSection extends Vue { |
|
|
*/ |
|
|
*/ |
|
|
public computedStartDownloadLinkClassNames() { |
|
|
public computedStartDownloadLinkClassNames() { |
|
|
return { |
|
|
return { |
|
|
hidden: this.downloadUrl && this.platformService.isWeb(), |
|
|
hidden: |
|
|
|
|
|
this.downloadUrl && this.platformService?.needsSecondaryDownloadLink(), |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -182,7 +184,9 @@ export default class DataExportSection extends Vue { |
|
|
*/ |
|
|
*/ |
|
|
public computedDownloadLinkClassNames() { |
|
|
public computedDownloadLinkClassNames() { |
|
|
return { |
|
|
return { |
|
|
hidden: !this.downloadUrl || !this.platformService.isWeb(), |
|
|
hidden: |
|
|
|
|
|
!this.downloadUrl || |
|
|
|
|
|
!this.platformService?.needsSecondaryDownloadLink(), |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|