Skip to content

Commit 363ddf9

Browse files
committed
docs: add "providing frontend API" section to the plugin development guide
https://web.tracklify.com/project/2b7ZVgE5/AdminForth/1304/Vuvq1Ypg/plugins-frontend-api.-improve-
1 parent ed11c92 commit 363ddf9

File tree

1 file changed

+147
-1
lines changed

1 file changed

+147
-1
lines changed

adminforth/documentation/docs/tutorial/09-Advanced/01-plugin-development.md

Lines changed: 147 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,4 +597,150 @@ handler: async (a) => {
597597
const resp = await this.options.adapter.complete(content, ['.'], this.options.expert?.maxTokens || 50);
598598
...
599599
}
600-
```
600+
```
601+
## Providing a frontend API
602+
If a plugin needs to provide an external frontend API so user code or other plugins can interact with it, you can create a .ts file or a global Pinia store (if you want to have some global variables or use plugin modals) and then re-use it in your frontend logic. For example:
603+
604+
1) Create new `./custom/useChatGptApi.ts` and `./custom/customModal` files
605+
```text
606+
af-plugin-chatgpt/
607+
├── custom
608+
│ └── tsconfig.json
609+
| └── completionInput.vue
610+
//diff-add
611+
| └── useChatGptApi.ts
612+
//diff-add
613+
| └── customModal.vue
614+
├── index.ts
615+
├── package.json
616+
├── tsconfig.json
617+
└── types.ts
618+
```
619+
620+
2) Write your custom logic:
621+
622+
```ts title="./custom/useChatGptApi.ts"
623+
import { ref } from 'vue';
624+
import { callAdminForthApi } from '@/utils';
625+
import { defineStore } from 'pinia'
626+
627+
export const useChatGptApi = defineStore('chatGptApi', () => {
628+
const isCustomModalOpened = ref(false);
629+
const customModalData = ref({})
630+
631+
function openCustomModal(modalData) {
632+
customModalData.value = modalData;
633+
isCustomModalOpened.value = true;
634+
}
635+
636+
function closeCustomModal() {
637+
isCustomModalOpened.value = false;
638+
}
639+
640+
async function doComplete(pluginInstanceId, record, columnName, textBeforeCursor) {
641+
const res = await callAdminForthApi({
642+
path: `/plugin/${pluginInstanceId}/doComplete`,
643+
method: 'POST',
644+
body: {
645+
record: { ...record, [columnName]: textBeforeCursor },
646+
},
647+
});
648+
649+
return res.completion;
650+
}
651+
652+
return {
653+
isCustomModalOpened,
654+
customModalData,
655+
openCustomModal,
656+
closeCustomModal,
657+
doComplete
658+
}
659+
```
660+
661+
3) If you want your plugin to have its own modal API, then first of all you'll need to inject this component somewhere so you can open it:
662+
663+
```ts title="./index.ts"
664+
665+
async modifyResourceConfig(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
666+
667+
...
668+
669+
// Global API injection: exposes openCustomModal(...) to open chatGptModal from anywhere
670+
(adminforth.config.customization.globalInjections.header).push({
671+
file: this.componentPath('customModal.vue'),
672+
meta: {
673+
pluginInstanceId: this.pluginInstanceId,
674+
}
675+
});
676+
677+
...
678+
679+
}
680+
681+
```
682+
683+
684+
and:
685+
686+
```html title="customModal.vue"
687+
<template>
688+
<!-- Hidden component that registers a global function to open job info modal -->
689+
<Modal
690+
ref="dialogRef"
691+
removeFromDomOnClose
692+
class="p-4"
693+
:beforeCloseFunction="() => { chatGpt.closeCustomModal(); }"
694+
>
695+
<div>
696+
***Modal content***
697+
{{ chatGpt.customModalData }}
698+
</div
699+
</Modal>
700+
</template>
701+
702+
<script setup lang="ts">
703+
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
704+
import { Modal } from '@/afcl';
705+
import { useChatGptApi } from './useChatGptApi';
706+
707+
const chatGpt = useChatGptApi();
708+
const dialogRef = ref<any>(null);
709+
710+
const props = defineProps<{
711+
meta: {
712+
pluginInstanceId: string;
713+
}
714+
}>();
715+
716+
watch(() => chatGpt.isCustomModalOpened, (newVal) => {
717+
if (newVal) {
718+
dialogRef.value?.open?.();
719+
} else {
720+
dialogRef.value?.close?.();
721+
}
722+
});
723+
</script>
724+
725+
726+
```
727+
728+
4) Re-use this api in your component:
729+
730+
```html
731+
<template>
732+
...
733+
</template>
734+
735+
<script setup>
736+
//diff-add
737+
import { useChatGptApi } from '@/custom/plugins/ChatGptPlugin/useChatGptApi';
738+
...
739+
</script>
740+
```
741+
742+
### How to get the plugin file path from a custom component
743+
744+
`ChatGptPlugin` is the class name that is defined inside `index.ts`.
745+
So if we want to access plugin files from a custom component, we should use the path:
746+
>`@/custom/plugins/*Plugin class name*/*File name*`

0 commit comments

Comments
 (0)