mirror of
https://github.com/frappe/books.git
synced 2024-11-10 07:40:55 +00:00
feat(ui): add a loading element
This commit is contained in:
parent
e1389184ed
commit
3d175f1730
63
src/components/Loading.vue
Normal file
63
src/components/Loading.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div
|
||||
class="absolute bottom-0 flex justify-end pb-6 pr-6"
|
||||
style="width: calc(100% - 12rem)"
|
||||
v-if="open && !close"
|
||||
>
|
||||
<div
|
||||
class="
|
||||
text-gray-900
|
||||
shadow-lg
|
||||
px-3
|
||||
py-3
|
||||
items-center
|
||||
w-96
|
||||
z-10
|
||||
bg-white
|
||||
rounded-lg
|
||||
"
|
||||
v-if="true"
|
||||
>
|
||||
<p class="text-base text-gray-600 pb-2" v-if="message.length">{{ message }}</p>
|
||||
<div class="w-full flex flex-row items-center">
|
||||
<div class="w-full bg-gray-200 h-3 mr-2 rounded">
|
||||
<div
|
||||
class="h-3 rounded bg-blue-400"
|
||||
:style="{ width: `${percent * 100}%` }"
|
||||
></div>
|
||||
</div>
|
||||
<feather-icon
|
||||
name="x"
|
||||
class="
|
||||
w-4
|
||||
h-4
|
||||
ml-auto
|
||||
text-gray-600
|
||||
cursor-pointer
|
||||
hover:text-gray-800
|
||||
"
|
||||
@click="closeToast"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
open: { type: Boolean, default: false },
|
||||
percent: { type: Number, default: 0.5 },
|
||||
message: { type: String, default: '' },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
close: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
closeToast() {
|
||||
this.close = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -35,6 +35,12 @@ type LabelTemplateFieldMap = {
|
||||
[key: string]: TemplateField;
|
||||
};
|
||||
|
||||
type LoadingStatusCallback = (
|
||||
isMakingEntries: boolean,
|
||||
entriesMade: number,
|
||||
totalEntries: number
|
||||
) => void;
|
||||
|
||||
interface TemplateField {
|
||||
label: string;
|
||||
fieldname: string;
|
||||
@ -354,11 +360,15 @@ export class Importer {
|
||||
return Object.keys(docMap).map((k) => docMap[k]);
|
||||
}
|
||||
|
||||
async importData(): Promise<Status> {
|
||||
async importData(setLoadingStatus: LoadingStatusCallback): Promise<Status> {
|
||||
const status: Status = { success: false, names: [], message: '' };
|
||||
const shouldDeleteName = await isNameAutoSet(this.doctype);
|
||||
const docObjs = this.getDocs();
|
||||
|
||||
for (const docObj of this.getDocs()) {
|
||||
let entriesMade = 0;
|
||||
setLoadingStatus(true, 0, docObjs.length);
|
||||
|
||||
for (const docObj of docObjs) {
|
||||
if (shouldDeleteName) {
|
||||
delete docObj.name;
|
||||
}
|
||||
@ -378,7 +388,10 @@ export class Importer {
|
||||
if (this.shouldSubmit) {
|
||||
await doc.submit();
|
||||
}
|
||||
entriesMade += 1;
|
||||
setLoadingStatus(true, entriesMade, docObjs.length);
|
||||
} catch (err) {
|
||||
setLoadingStatus(false, entriesMade, docObjs.length);
|
||||
const messages = [
|
||||
frappe.t`Could not import ${this.doctype} ${doc.name}.`,
|
||||
];
|
||||
@ -405,6 +418,7 @@ export class Importer {
|
||||
status.names.push(doc.name);
|
||||
}
|
||||
|
||||
setLoadingStatus(false, entriesMade, docObjs.length);
|
||||
status.success = true;
|
||||
return status;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex flex-col overflow-hidden">
|
||||
<div class="flex flex-col overflow-hidden w-full">
|
||||
<PageHeader>
|
||||
<template #title>
|
||||
<h1 class="text-2xl font-bold">
|
||||
@ -212,7 +212,14 @@
|
||||
:key="'matrix-row-' + i"
|
||||
>
|
||||
<button
|
||||
class="w-4 h-4 text-gray-600 hover:text-gray-900 cursor-pointer outline-none"
|
||||
class="
|
||||
w-4
|
||||
h-4
|
||||
text-gray-600
|
||||
hover:text-gray-900
|
||||
cursor-pointer
|
||||
outline-none
|
||||
"
|
||||
@click="
|
||||
() => {
|
||||
importer.dropRow(i);
|
||||
@ -306,12 +313,18 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="!importType"
|
||||
class="flex justify-center h-full items-center mb-16"
|
||||
class="flex justify-center h-full w-full items-center mb-16"
|
||||
>
|
||||
<HowTo link="https://youtu.be/ukHAgcnVxTQ">
|
||||
{{ t`How to Use Data Import?` }}
|
||||
</HowTo>
|
||||
</div>
|
||||
<Loading
|
||||
v-if="openLoading"
|
||||
:open="openLoading"
|
||||
:percent="percentLoading"
|
||||
:message="messageLoading"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@ -326,6 +339,7 @@ import { IPC_ACTIONS } from '@/messages';
|
||||
import { getSavePath, saveData, showMessageDialog } from '@/utils';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import frappe from 'frappe';
|
||||
import Loading from '../components/Loading.vue';
|
||||
export default {
|
||||
components: {
|
||||
PageHeader,
|
||||
@ -334,6 +348,7 @@ export default {
|
||||
DropdownWithActions,
|
||||
FeatherIcon,
|
||||
HowTo,
|
||||
Loading,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -343,6 +358,9 @@ export default {
|
||||
file: null,
|
||||
importer: null,
|
||||
importType: '',
|
||||
openLoading: false,
|
||||
percentLoading: 0,
|
||||
messageLoading: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -446,7 +464,7 @@ export default {
|
||||
if (!this.complete) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.clear();
|
||||
},
|
||||
methods: {
|
||||
@ -533,7 +551,9 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
const { success, names, message } = await this.importer.importData();
|
||||
const { success, names, message } = await this.importer.importData(
|
||||
this.setLoadingStatus
|
||||
);
|
||||
if (!success) {
|
||||
showMessageDialog({
|
||||
message: this.t`Import Failed`,
|
||||
@ -552,6 +572,13 @@ export default {
|
||||
this.importType = importType;
|
||||
this.importer = new Importer(this.labelDoctypeMap[this.importType]);
|
||||
},
|
||||
setLoadingStatus(isMakingEntries, entriesMade, totalEntries) {
|
||||
this.openLoading = isMakingEntries;
|
||||
this.percentLoading = entriesMade / totalEntries;
|
||||
this.messageLoading = isMakingEntries
|
||||
? `${entriesMade} entries made out of ${totalEntries}...`
|
||||
: '';
|
||||
},
|
||||
async selectFile() {
|
||||
const options = {
|
||||
title: this.t`Select File`,
|
||||
|
Loading…
Reference in New Issue
Block a user