Implemented support for child entities in entity modals.

This commit is contained in:
Fabio Manganiello 2023-03-21 16:02:02 +01:00
parent b1cb7ef847
commit e9abb5cb9a
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
3 changed files with 95 additions and 34 deletions

View file

@ -31,6 +31,7 @@
:parent="value" :parent="value"
:loading="loading" :loading="loading"
:level="level + 1" :level="level + 1"
@show-modal="$emit('show-modal', $event)"
@input="$emit('input', entity)" /> @input="$emit('input', entity)" />
</div> </div>
</div> </div>
@ -45,7 +46,7 @@ import { bus } from "@/bus";
export default { export default {
name: "Entity", name: "Entity",
mixins: [EntityMixin], mixins: [EntityMixin],
emits: ['input', 'loading', 'update'], emits: ['input', 'loading', 'update', 'show-modal'],
data() { data() {
return { return {
@ -88,12 +89,19 @@ export default {
}, },
onClick(event) { onClick(event) {
event.stopPropagation()
if ( if (
event.target.classList.contains('label') || event.target.classList.contains('label') ||
event.target.classList.contains('head') event.target.classList.contains('head')
) { ) {
event.stopPropagation() // When clicking on the name or icon of the entity, stop the event
// propagation and toggle the collapsed state instead.
this.toggleCollapsed() this.toggleCollapsed()
} else {
// Otherwise, propagate the event upwards as a request to show the
// entity details modal.
this.$emit('show-modal', this.value.id)
} }
}, },

View file

@ -20,6 +20,7 @@
:visible="modalVisible" :visible="modalVisible"
:config-values="configValuesByParentId(modalEntityId)" :config-values="configValuesByParentId(modalEntityId)"
@close="onEntityModal" @close="onEntityModal"
@entity-update="modalEntityId = $event"
v-if="modalEntityId && entities[modalEntityId]" v-if="modalEntityId && entities[modalEntityId]"
/> />
@ -48,11 +49,13 @@
</div> </div>
<div class="body"> <div class="body">
<div class="entity-frame" @click="onEntityModal(entity.id)" <div class="entity-frame"
v-for="entity in group.entities" :key="entity.id"> v-for="entity in group.entities"
:key="entity.id">
<Entity <Entity
:value="entity" :value="entity"
:children="childrenByParentId(entity.id)" :children="childrenByParentId(entity.id)"
@show-modal="onEntityModal($event)"
@input="onEntityInput(entity)" @input="onEntityInput(entity)"
:error="!!errorEntities[entity.id]" :error="!!errorEntities[entity.id]"
:loading="!!loadingEntities[entity.id]" :loading="!!loadingEntities[entity.id]"

View file

@ -90,6 +90,16 @@
</div> </div>
</div> </div>
<div class="table-row" v-if="entity.parent_id">
<div class="title">Parent</div>
<div class="value">
<a href="#"
@click="$emit('entity-update', entity.parent_id)"
v-text="entity.parent_id"
/>
</div>
</div>
<div class="table-row" v-if="entity.created_at"> <div class="table-row" v-if="entity.created_at">
<div class="title">Created at</div> <div class="title">Created at</div>
<div class="value" v-text="formatDateTime(entity.created_at)" /> <div class="value" v-text="formatDateTime(entity.created_at)" />
@ -100,32 +110,49 @@
<div class="value" v-text="formatDateTime(entity.updated_at)" /> <div class="value" v-text="formatDateTime(entity.updated_at)" />
</div> </div>
<div v-for="value, attr in entity" :key="attr"> <div class="table-row delete-entity-container"
<div class="table-row" v-if="value != null && specialFields.indexOf(attr) < 0"> @click="$refs.deleteConfirmDiag.show()">
<div class="title" v-text="prettify(attr)" />
<div class="value" v-text="'' + value" />
</div>
</div>
<div v-for="value, attr in (entity.data || {})" :key="attr">
<div class="table-row" v-if="value != null">
<div class="title" v-text="prettify(attr)" />
<div class="value" v-text="'' + value" />
</div>
</div>
<div class="table-row delete-entity-container">
<div class="title">Delete Entity</div> <div class="title">Delete Entity</div>
<div class="value"> <div class="value">
<button @click="$refs.deleteConfirmDiag.show()"> <button @click.stop="$refs.deleteConfirmDiag.show()">
<i class="fas fa-trash" /> <i class="fas fa-trash" />
</button> </button>
</div> </div>
</div> </div>
<div class="extra-info-container">
<div class="title section-title" @click="extraInfoCollapsed = !extraInfoCollapsed">
<div class="col-11">
<i class="fas fa-circle-info" /> &nbsp;
Extra Info
</div>
<div class="col-1 pull-right">
<i class="fas"
:class="{'fa-chevron-down': extraInfoCollapsed, 'fa-chevron-up': !extraInfoCollapsed}" />
</div>
</div>
<div class="extra-info" v-if="!extraInfoCollapsed">
<div v-for="value, attr in entity" :key="attr">
<div class="table-row" v-if="value != null && specialFields.indexOf(attr) < 0">
<div class="title" v-text="prettify(attr)" />
<div class="value" v-text="stringify(value)" />
</div>
</div>
<div v-for="value, attr in (entity.data || {})" :key="attr">
<div class="table-row" v-if="value != null">
<div class="title" v-text="prettify(attr)" />
<div class="value" v-text="stringify(value)" />
</div>
</div>
</div>
</div>
<div class="config-container" <div class="config-container"
v-if="computedConfig.length"> v-if="computedConfig.length">
<div class="title" <div class="title section-title"
@click="configCollapsed = !configCollapsed"> @click="configCollapsed = !configCollapsed">
<div class="col-11"> <div class="col-11">
<i class="fas fa-screwdriver-wrench" /> &nbsp; <i class="fas fa-screwdriver-wrench" /> &nbsp;
@ -172,13 +199,14 @@ const specialFields = [
'name', 'name',
'plugin', 'plugin',
'updated_at', 'updated_at',
'parent_id',
] ]
export default { export default {
name: "EntityModal", name: "EntityModal",
components: {Entity, Modal, EditButton, NameEditor, Icon, ConfirmDialog}, components: {Entity, Modal, EditButton, NameEditor, Icon, ConfirmDialog},
mixins: [Utils], mixins: [Utils],
emits: ['input', 'loading'], emits: ['input', 'loading', 'entity-update'],
props: { props: {
entity: { entity: {
type: Object, type: Object,
@ -210,6 +238,7 @@ export default {
editName: false, editName: false,
editIcon: false, editIcon: false,
configCollapsed: true, configCollapsed: true,
extraInfoCollapsed: true,
specialFields: specialFields, specialFields: specialFields,
} }
}, },
@ -280,6 +309,14 @@ export default {
this.editIcon = false this.editIcon = false
} }
}, },
stringify(value) {
if (value == null)
return ''
if (Array.isArray(value) || typeof value === 'object')
return JSON.stringify(value)
return '' + value
},
}, },
} }
</script> </script>
@ -329,26 +366,39 @@ export default {
.delete-entity-container { .delete-entity-container {
color: $error-fg; color: $error-fg;
cursor: pointer;
button { button {
color: $error-fg; color: $error-fg;
} }
} }
.config-container { @mixin section-title {
display: flex;
cursor: pointer;
padding: 1em;
text-transform: uppercase;
letter-spacing: 0.033em;
border-top: $default-border;
box-shadow: $border-shadow-bottom;
&:hover {
background: $hover-bg;
}
}
.config-container,
.extra-info-container
{
margin: 0; margin: 0;
.title { .section-title {
display: flex; @include section-title;
padding: 1em; }
text-transform: uppercase; }
letter-spacing: 0.033em;
border-top: $default-border;
box-shadow: $border-shadow-bottom;
cursor: pointer;
&:hover { .config-container {
background: $hover-bg; .title {
} @include section-title;
} }
} }