Add multiple network maps, graph UX improvements, and full backup import.
Support per-map contact membership with scoped graph views, relation editing on edges, layout caching, and automatic detection of full JSON backups so contacts and relations import together. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div v-if="open" class="modal-overlay" @click.self="$emit('close')">
|
||||
<div class="modal">
|
||||
<div class="modal-header">
|
||||
<h3>{{ isEdit ? 'Редактировать карту' : 'Новая карта сети' }}</h3>
|
||||
<button class="btn btn-secondary btn-sm" type="button" @click="$emit('close')">✕</button>
|
||||
</div>
|
||||
<form @submit.prevent="onSubmit">
|
||||
<div class="form-group">
|
||||
<label>Название *</label>
|
||||
<input v-model="form.name" class="form-control" required placeholder="Например: Коллектив А" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Описание</label>
|
||||
<textarea
|
||||
v-model="form.description"
|
||||
class="form-control"
|
||||
rows="3"
|
||||
placeholder="Цель карты, контекст..."
|
||||
/>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
v-if="isEdit && deletable"
|
||||
type="button"
|
||||
class="btn btn-danger"
|
||||
@click="$emit('delete')"
|
||||
>
|
||||
Удалить
|
||||
</button>
|
||||
<div class="modal-footer-actions">
|
||||
<button type="button" class="btn btn-secondary" @click="$emit('close')">Отмена</button>
|
||||
<button type="submit" class="btn btn-primary">Сохранить</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, watch, computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
open: { type: Boolean, default: false },
|
||||
initial: { type: Object, default: () => ({}) },
|
||||
deletable: { type: Boolean, default: false },
|
||||
})
|
||||
const emit = defineEmits(['close', 'submit', 'delete'])
|
||||
|
||||
const isEdit = computed(() => Boolean(props.initial?.id))
|
||||
|
||||
const form = reactive({
|
||||
name: '',
|
||||
description: '',
|
||||
})
|
||||
|
||||
watch(
|
||||
() => [props.open, props.initial],
|
||||
() => {
|
||||
if (!props.open) return
|
||||
form.name = props.initial?.name || ''
|
||||
form.description = props.initial?.description || ''
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
|
||||
function onSubmit() {
|
||||
emit('submit', { name: form.name.trim(), description: form.description.trim() })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.modal-footer-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-left: auto;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user