Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the Desktop Backup Import #1701

Merged
merged 4 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/assets/scss/element/element-reset.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import '~@/assets/scss/variable.scss';

/* Divider */
.el-divider {
background-color: var(--color-border-default);
Expand Down Expand Up @@ -180,6 +182,15 @@
.el-dialog {
background: var(--color-bg-normal);
border-radius: 8px;
.el-dialog__header {
padding: 0 20px;
line-height: 56px;
border-bottom: 1px solid var(--color-border-default);
.el-dialog__title {
color: var(--color-text-title);
font-size: $font-size--subtitle;
}
}
}

/* Input */
Expand Down Expand Up @@ -341,3 +352,17 @@
color: var(--color-text-tips);
}
}

/* Progress */
.el-progress {
.el-progress-bar__outer {
background-color: var(--color-bg-code);
border-radius: 4px;
.el-progress-bar__inner {
border-radius: 4px;
}
}
.el-progress__text {
color: var(--color-text-default);
}
}
106 changes: 75 additions & 31 deletions src/components/ImportData.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,12 @@
<el-col :span="22">
<el-form-item :label="$t('connections.importFile')">
<el-tooltip placement="top" :effect="theme !== 'light' ? 'light' : 'dark'" :open-delay="500">
<div slot="content" v-html="$t('connections.importConnectionsTip')">
{{ $t('connections.importConnectionsTip') }}
</div>
<div slot="content" v-html="$t('connections.importConnectionsTip')"></div>
<a href="javascript:;" class="icon-tip">
<i class="el-icon-question"></i>
</a>
</el-tooltip>
<el-input size="small" v-model="record.filePath"></el-input>
<el-input size="small" v-model="record.filePath" @change="handleFilePathChange"></el-input>
</el-form-item>
</el-col>
<el-col :span="2">
Expand All @@ -64,6 +62,15 @@
</el-collapse-transition>
</el-row>
</el-form>
<el-dialog
width="50%"
:title="$t('settings.importProgress')"
:close-on-click-modal="false"
:visible.sync="progressVisible"
append-to-body
>
<el-progress :percentage="getProgressNumber(this.importMsgsProgress)" color="#34c388"></el-progress>
</el-dialog>
</my-dialog>
</template>

Expand Down Expand Up @@ -110,8 +117,10 @@ export default class ImportData extends Vue {

@Prop({ default: false }) public visible!: boolean

private importMsgsProgress = 0
private showDialog: boolean = this.visible
private confirmLoading: boolean = false
private progressVisible = false
private record: ImportForm = {
importFormat: 'JSON',
filePath: '',
Expand All @@ -124,10 +133,21 @@ export default class ImportData extends Vue {
this.showDialog = val
}

private handleFilePathChange(val: string) {
if (!val) {
return
}
this.readFilePath(val, this.getExtensionName())
}

private getExtensionName() {
const lowerFormat = this.record.importFormat.toLowerCase()
return lowerFormat === 'excel' ? 'xlsx' : lowerFormat
}

private getFileData() {
let loading: ElLoadingComponent | undefined = undefined
const lowerFormat = this.record.importFormat.toLowerCase()
const extensionName = lowerFormat === 'excel' ? 'xlsx' : lowerFormat
const extensionName = this.getExtensionName()
remote.dialog
.showOpenDialog({
properties: ['openFile'],
Expand All @@ -141,11 +161,7 @@ export default class ImportData extends Vue {
spinner: 'el-icon-loading',
})
const filePath = filePaths[0]
if (extensionName === 'xlsx') {
this.getExcelContentByXlsx(filePath)
} else {
this.getFileContentByFs(filePath)
}
this.readFilePath(filePath, extensionName)
}
})
.catch(() => {})
Expand Down Expand Up @@ -174,7 +190,8 @@ export default class ImportData extends Vue {
properties = JSON.parse(properties)
will = JSON.parse(will)
} catch (err) {
this.$message.error(err.toString())
const error = err as unknown as Error
this.$message.error(error.toString())
caughtError = true
}
return Object.assign(connection, { messages, subscriptions, properties, will })
Expand All @@ -185,6 +202,14 @@ export default class ImportData extends Vue {
}
}

private readFilePath(filePath: string, extensionName: string) {
if (extensionName === 'xlsx') {
this.getExcelContentByXlsx(filePath)
} else {
this.getFileContentByFs(filePath)
}
}

private getFileContentByFs(filePath: string) {
fs.readFile(filePath, 'utf-8', (err, content) => {
if (err) {
Expand All @@ -195,7 +220,8 @@ export default class ImportData extends Vue {
const fileContent = this.getDiffFormatData(content)
this.assignValueToRecord(filePath, fileContent)
} catch (err) {
this.$message.error(err.toString())
const error = err as unknown as Error
this.$message.error(error.toString())
}
})
}
Expand Down Expand Up @@ -277,7 +303,8 @@ export default class ImportData extends Vue {
const keyName = Object.keys(parentElement._parent)[keyNameIndex]
parentElement._parent[keyName] = nativeType(keyName, value)
} catch (err) {
this.$message.error(err.toString())
const error = err as unknown as Error
this.$message.error(error.toString())
}
}
const convertRightStringAndArray = (data: string) => {
Expand All @@ -301,7 +328,8 @@ export default class ImportData extends Vue {
if (!Array.isArray(subscriptions)) connection.subscriptions = [subscriptions]
})
} catch (err) {
this.$message.error(err.toString())
const error = err as unknown as Error
this.$message.error(error.toString())
}
return fileContent
}
Expand Down Expand Up @@ -356,33 +384,44 @@ export default class ImportData extends Vue {
})
fileContent.push({ messages, subscriptions, properties, will, ...otherProps })
} catch (err) {
this.$message.error(err.toString())
const error = err as unknown as Error
this.$message.error(error.toString())
}
})
return fileContent
}

private async importData() {
this.confirmLoading = true
const { connectionService } = useServices()
if (!this.record.fileContent.length) {
this.$message.error(this.$tc('connections.uploadFileTip'))
return
}
const importDataResult = await connectionService.import(this.record.fileContent)
this.confirmLoading = false
if (importDataResult === 'ok') {
this.$message.success(this.$tc('common.importSuccess'))
this.resetData()
setTimeout(() => {
location.reload()
}, 1000)
} else {
this.$message.error(importDataResult)
try {
const { connectionService } = useServices()
if (!this.record.fileContent.length) {
this.$message.error(this.$tc('connections.uploadFileTip'))
return
}
this.progressVisible = true
const importDataResult = await connectionService.import(this.record.fileContent, (progress) => {
this.importMsgsProgress = progress
})
if (importDataResult === 'ok') {
this.$message.success(this.$tc('common.importSuccess'))
setTimeout(() => {
this.resetData()
location.reload()
}, 2000)
} else {
this.$message.error(importDataResult)
}
} catch (err) {
const error = err as unknown as Error
this.$message.error(error.toString())
} finally {
this.confirmLoading = false
}
}

private resetData() {
this.progressVisible = false
this.showDialog = false
this.$emit('update:visible', false)
this.record = {
Expand All @@ -391,6 +430,11 @@ export default class ImportData extends Vue {
fileName: '',
fileContent: [],
}
this.importMsgsProgress = 0
}

private getProgressNumber(progress: number | string) {
return Number((typeof progress === 'string' ? Number(progress) * 100 : progress * 100).toFixed(1))
}
}
</script>
Expand Down
9 changes: 0 additions & 9 deletions src/components/MyDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,6 @@ export default class MyDialog extends Vue {
@import '~@/assets/scss/variable.scss';

.my-dialog {
.el-dialog__header {
padding: 0 20px;
line-height: 56px;
border-bottom: 1px solid var(--color-border-default);
.el-dialog__title {
color: var(--color-text-title);
font-size: $font-size--subtitle;
}
}
.el-dialog--center .el-dialog__body {
padding: 32px 24px 0;
}
Expand Down
63 changes: 58 additions & 5 deletions src/database/services/ConnectionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,52 @@ export default class ConnectionService {
)
}

// import single connection
public async importOneConnection(id: string, data: ConnectionModel) {
/**
* Imports a single connection with the specified ID and data.
*
* @param id - The ID of the connection to import.
* @param data - The data of the connection to import.
* @param getImportProgress - Optional callback function to receive import progress updates.
* @returns A Promise that resolves when the import is complete.
*/
public async importOneConnection(
id: string,
data: ConnectionModel,
getImportOneConnProgress?: (progress: number) => void,
) {
const { connectionService, subscriptionService, messageService } = useServices()
let progress = 0
// Update connection, update subscriptions, and update messages are each considered as a step
const totalSteps = 3
// Connection table & Will Message table
await connectionService.update(id, data)
progress += 1 / totalSteps
if (getImportOneConnProgress) {
getImportOneConnProgress(progress)
}
// Subscriptions table
if (Array.isArray(data.subscriptions) && data.subscriptions.length) {
await subscriptionService.updateSubscriptions(id, data.subscriptions)
}
progress += 1 / totalSteps
if (getImportOneConnProgress) {
getImportOneConnProgress(progress)
}
// Messages table
if (Array.isArray(data.messages) && data.messages.length) {
await messageService.pushToConnection(data.messages, id)
await messageService.importMsgsToConnection(data.messages, id, (msgProgress) => {
if (getImportOneConnProgress) {
// Combine message import progress with total progress proportionally
const combinedProgress = progress + msgProgress / totalSteps
getImportOneConnProgress(combinedProgress)
}
})
} else {
// No messages to import, mark progress as 100% for this connection
progress += 1 / totalSteps
if (getImportOneConnProgress) {
getImportOneConnProgress(progress)
}
}
}

Expand All @@ -153,14 +187,33 @@ export default class ConnectionService {
return await this.get(id)
}

public async import(data: ConnectionModel[]): Promise<string> {
/**
* Imports backup connection data into the database.
*
* @param data - An array of ConnectionModel objects to import.
* @param getImportAllProgress - A callback function to track the import progress.
* @returns A Promise that resolves to a string indicating the import status.
*/
public async import(data: ConnectionModel[], getImportAllProgress?: (progress: number) => void): Promise<string> {
try {
let overallProgress = 0
// Each connection is considered as a step
const totalSteps = data.length

for (let i = 0; i < data.length; i++) {
const { id } = data[i]
if (id) {
// FIXME: remove it after support collection importing
data[i].parentId = null
await this.importOneConnection(id, data[i])
await this.importOneConnection(id, data[i], (progress) => {
if (getImportAllProgress) {
// Calculate the progress of a single connection
const connectionProgress = progress / totalSteps
getImportAllProgress(overallProgress + connectionProgress)
}
})
// Increase progress after processing each connection
overallProgress += 1 / totalSteps
}
}
} catch (err) {
Expand Down
Loading