Add plugin platform with modular backend and frontend registry.

Split graph/import/meta into Django apps, add API v1 with OpenAPI and pytest, and introduce plugin registry with the tags reference plugin on both FE and BE.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-25 09:35:51 +03:00
co-authored by Cursor
parent b694a596b8
commit cafc7335ad
77 changed files with 1801 additions and 490 deletions
+12 -2
View File
@@ -45,6 +45,13 @@
<label>Заметки</label>
<textarea v-model="form.notes" class="form-control" placeholder="Дополнительная информация..." rows="3"></textarea>
</div>
<component
:is="Ext"
v-for="(Ext, index) in contactFormExtensions"
:key="index"
:contact-id="initial?.id"
v-model="pluginTags"
/>
<div class="contact-form-footer">
<button
v-if="showDelete"
@@ -63,9 +70,10 @@
</template>
<script setup>
import { reactive, watch, computed, onMounted } from 'vue'
import { reactive, ref, watch, computed, onMounted } from 'vue'
import { useNetworkMapsStore } from '../stores/networkMaps'
import { listMembershipsByContact } from '../application/usecases/networkMaps'
import { getContactFormExtensions } from '../core/pluginRegistry'
const props = defineProps({
initial: { type: Object, default: () => ({}) },
@@ -75,6 +83,8 @@ const props = defineProps({
const emit = defineEmits(['submit', 'cancel', 'delete'])
const mapsStore = useNetworkMapsStore()
const contactFormExtensions = getContactFormExtensions()
const pluginTags = ref([])
const showDelete = computed(() => {
if (props.deletable) return true
@@ -140,7 +150,7 @@ onMounted(async () => {
function onSubmit() {
const { mapIds, ...contactData } = form
emit('submit', contactData, mapIds)
emit('submit', contactData, mapIds, { tags: [...pluginTags.value] })
}
</script>