2
0
mirror of https://github.com/frappe/books.git synced 2024-12-22 19:09:01 +00:00

incr: update plugin page with delete and update

This commit is contained in:
18alantom 2023-07-25 13:40:49 +05:30
parent 31b1eed124
commit 94ee5cda35
4 changed files with 159 additions and 16 deletions

View File

@ -5,6 +5,7 @@ export class Plugin extends Doc {
name?: string; name?: string;
version?: string; version?: string;
info?: string; info?: string;
data?: string;
/* /*
override get canDelete(): boolean { override get canDelete(): boolean {

View File

@ -230,12 +230,18 @@ export default defineComponent({
const { onboardingComplete } = await fyo.doc.get('GetStarted'); const { onboardingComplete } = await fyo.doc.get('GetStarted');
const { hideGetStarted } = await fyo.doc.get('SystemSettings'); const { hideGetStarted } = await fyo.doc.get('SystemSettings');
let route = '/get-started'; let fallback, route;
fallback = route = '/get-started';
if (hideGetStarted || onboardingComplete) { if (hideGetStarted || onboardingComplete) {
route = localStorage.getItem('lastRoute') || '/'; route = localStorage.getItem('lastRoute') || '/';
fallback = '/';
} }
try {
await routeTo(route); await routeTo(route);
} catch {
await routeTo(fallback);
}
}, },
async showDbSelector(): Promise<void> { async showDbSelector(): Promise<void> {
localStorage.clear(); localStorage.clear();

View File

@ -1,36 +1,75 @@
<template> <template>
<div> <div>
<PageHeader :title="doc && doc.inserted ? doc.name : ''"> <PageHeader :title="title">
<Button @click="selectPluginFile">{{ t`Select Plugin` }}</Button> <Button v-if="!doc?.info" @click="selectPluginFile">{{
t`Select Plugin`
}}</Button>
<Button <Button
v-if="doc?.canSave && doc.data" v-if="doc?.canSave && doc.data && !exists"
type="primary" type="primary"
@click="doc.sync()" @click="installPlugin()"
> >
{{ t`Save` }} {{ t`Install` }}
</Button> </Button>
<Button
v-if="doc?.canSave && doc.data && exists"
type="primary"
@click="updatePlugin()"
>
{{ t`Update` }}
</Button>
<Button v-if="doc?.canDelete" @click="deletePlugin()">{{
t`Delete`
}}</Button>
</PageHeader> </PageHeader>
<div class="p-4 text-sm"> <div v-if="info" class="p-4 text-sm">
<pre>{{ JSON.stringify(JSON.parse(doc?.info || '{}'), null, 2) }}</pre> <pre>{{ JSON.stringify(info, null, 2) }}</pre>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ModelNameEnum } from 'models/types'; import { Doc } from 'fyo/model/doc';
import PageHeader from 'src/components/PageHeader.vue';
import Button from 'src/components/Button.vue';
import { defineComponent } from 'vue';
import { Plugin } from 'fyo/models/Plugin'; import { Plugin } from 'fyo/models/Plugin';
import { ModelNameEnum } from 'models/types';
import Button from 'src/components/Button.vue';
import PageHeader from 'src/components/PageHeader.vue';
import { showDialog, showToast } from 'src/utils/interactive';
import { commonDocSync, deleteDocWithPrompt } from 'src/utils/ui';
import { PluginInfo } from 'utils/types';
import { defineComponent } from 'vue';
/**
* TODO:
* - [ ] Display plugin README.md
* - [ ] Display plugin info properly
*/
export default defineComponent({ export default defineComponent({
components: { PageHeader, Button }, components: { PageHeader, Button },
props: { name: { type: String, required: true } }, props: { name: { type: String, required: true } },
data() { data() {
return { doc: null as null | Plugin }; return {
info: null as null | PluginInfo,
doc: null as null | Plugin,
exists: false as boolean,
};
},
computed: {
title(): string {
if (this.info) {
return this.info.name;
}
return '';
},
}, },
async mounted() { async mounted() {
if (this.name) { if (this.name) {
try {
this.doc = await this.fyo.doc.get(ModelNameEnum.Plugin, this.name); this.doc = await this.fyo.doc.get(ModelNameEnum.Plugin, this.name);
} catch {
this.doc = this.fyo.doc.new(ModelNameEnum.Plugin);
}
} else { } else {
this.doc = this.fyo.doc.new(ModelNameEnum.Plugin); this.doc = this.fyo.doc.new(ModelNameEnum.Plugin);
} }
@ -38,8 +77,18 @@ export default defineComponent({
// @ts-ignore // @ts-ignore
window.p = this; window.p = this;
} }
this.setInfo();
}, },
methods: { methods: {
setInfo(info?: string) {
info ??= this.doc?.info;
if (!info) {
return;
}
this.info = JSON.parse(info) as PluginInfo;
},
async selectPluginFile() { async selectPluginFile() {
const { filePath } = await ipc.selectFile({ const { filePath } = await ipc.selectFile({
title: this.t`Select Plugin File`, title: this.t`Select Plugin File`,
@ -53,8 +102,95 @@ export default defineComponent({
} }
const data = await ipc.getPluginData(filePath); const data = await ipc.getPluginData(filePath);
this.setInfo(data.info);
this.exists = await this.fyo.db.exists(
ModelNameEnum.Plugin,
this.info?.name ?? ''
);
await this.doc?.set(data); await this.doc?.set(data);
}, },
async installPlugin() {
if (!this.doc) {
return;
}
const success = await commonDocSync(this.doc as Doc, true);
if (success) {
this.showReloadToast();
}
},
async updatePlugin() {
const { name, info, data } = this.doc ?? {};
if (!name || !info || !data) {
return;
}
const oldDoc = (await this.fyo.doc.get(
ModelNameEnum.Plugin,
name
)) as Plugin;
const newInfo = JSON.parse(info) as PluginInfo;
const oldInfo = JSON.parse(oldDoc.info ?? '{}') as PluginInfo;
let message = this
.t`Plugin ${name} exists, update data with selected file?`;
if (
oldInfo.version !== newInfo.version &&
oldInfo.name === newInfo.name
) {
message = this
.t`Update plugin data from version ${oldInfo.version} to ${newInfo.version}?`;
}
const success = await showDialog({
title: this.t`Update ${name}`,
message,
buttons: [
{
label: this.t`Yes`,
async action() {
await oldDoc.set({ info, data });
await oldDoc.sync();
return true;
},
},
{
label: this.t`No`,
action() {
return false;
},
},
],
});
if (success) {
this.doc = oldDoc;
this.showReloadToast();
}
},
async deletePlugin() {
if (!this.doc) {
return;
}
const success = await deleteDocWithPrompt(this.doc as Doc);
if (success) {
const route = `/list/Plugin/${this.t`Plugins`}`;
await this.$router.replace(route);
this.showReloadToast();
}
},
showReloadToast() {
showToast({
message: this.t`Changes will be visible on reload`,
action: () => ipc.reloadWindow(),
actionText: this.t`Reload Frappe Books?`,
});
},
}, },
}); });
</script> </script>

View File

@ -19,7 +19,7 @@ export default () => {
} }
return defineConfig({ return defineConfig({
server: { host, port, strictPort: true }, server: { host, port, strictPort: true, watch: { ignored: ['**/dbs/**'] } },
root: path.resolve(__dirname, './src'), root: path.resolve(__dirname, './src'),
plugins: [vue()], plugins: [vue()],
resolve: { resolve: {