allow one-to-one user relationship
This commit is contained in:
parent
5693657b54
commit
85af8a5859
@ -149,6 +149,14 @@
|
|||||||
editingFieldIdentifier.value = toIdentifier(editingFieldName.value)
|
editingFieldIdentifier.value = toIdentifier(editingFieldName.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateNewFieldType (entityId: number) {
|
||||||
|
newFields[entityId].relationshipType = newFields[entityId].type === 'USER' ? 'ONE_TO_MANY' : 'ONE_TO_ONE'
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateEditingFieldType () {
|
||||||
|
editingRelationshipType.value = editingFieldType.value === 'USER' ? 'ONE_TO_MANY' : 'ONE_TO_ONE'
|
||||||
|
}
|
||||||
|
|
||||||
async function addEntity () {
|
async function addEntity () {
|
||||||
const name = newEntityName.value.trim()
|
const name = newEntityName.value.trim()
|
||||||
const identifier = newEntityIdentifier.value.trim()
|
const identifier = newEntityIdentifier.value.trim()
|
||||||
@ -208,6 +216,8 @@
|
|||||||
if (!draft.targetEntityId) return
|
if (!draft.targetEntityId) return
|
||||||
values.targetEntityId = String(draft.targetEntityId)
|
values.targetEntityId = String(draft.targetEntityId)
|
||||||
values.relationshipType = draft.relationshipType
|
values.relationshipType = draft.relationshipType
|
||||||
|
} else if (draft.type === 'USER') {
|
||||||
|
values.relationshipType = draft.relationshipType
|
||||||
}
|
}
|
||||||
const response = await request(`/api/entity-definitions/${entity.id}/fields`, 'POST', values)
|
const response = await request(`/api/entity-definitions/${entity.id}/fields`, 'POST', values)
|
||||||
if (!response.ok) throw new Error('Field create failed')
|
if (!response.ok) throw new Error('Field create failed')
|
||||||
@ -227,7 +237,7 @@
|
|||||||
editingFieldIdentifier.value = field.identifier
|
editingFieldIdentifier.value = field.identifier
|
||||||
editingFieldType.value = field.type
|
editingFieldType.value = field.type
|
||||||
editingTargetEntityId.value = field.targetEntityId
|
editingTargetEntityId.value = field.targetEntityId
|
||||||
editingRelationshipType.value = field.relationshipType ?? 'ONE_TO_ONE'
|
editingRelationshipType.value = field.relationshipType ?? (field.type === 'USER' ? 'ONE_TO_MANY' : 'ONE_TO_ONE')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveField (entity: EntityDefinition, field: EntityField) {
|
async function saveField (entity: EntityDefinition, field: EntityField) {
|
||||||
@ -244,6 +254,8 @@
|
|||||||
if (!editingTargetEntityId.value) return
|
if (!editingTargetEntityId.value) return
|
||||||
values.targetEntityId = String(editingTargetEntityId.value)
|
values.targetEntityId = String(editingTargetEntityId.value)
|
||||||
values.relationshipType = editingRelationshipType.value
|
values.relationshipType = editingRelationshipType.value
|
||||||
|
} else if (editingFieldType.value === 'USER') {
|
||||||
|
values.relationshipType = editingRelationshipType.value
|
||||||
}
|
}
|
||||||
const response = await request(`/api/entity-definitions/${entity.id}/fields/${field.id}`, 'PATCH', values)
|
const response = await request(`/api/entity-definitions/${entity.id}/fields/${field.id}`, 'PATCH', values)
|
||||||
if (!response.ok) throw new Error('Field update failed')
|
if (!response.ok) throw new Error('Field update failed')
|
||||||
@ -346,6 +358,10 @@
|
|||||||
return type === 'ONE_TO_MANY' ? 'One to many' : 'One to one'
|
return type === 'ONE_TO_MANY' ? 'One to many' : 'One to one'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function userRelationshipLabel (type?: RelationshipType) {
|
||||||
|
return type === 'ONE_TO_ONE' ? 'One to one' : 'Many to one'
|
||||||
|
}
|
||||||
|
|
||||||
function targetName (field: EntityField) {
|
function targetName (field: EntityField) {
|
||||||
return field.targetEntityName
|
return field.targetEntityName
|
||||||
?? entities.value.find(entity => entity.id === field.targetEntityId)?.name
|
?? entities.value.find(entity => entity.id === field.targetEntityId)?.name
|
||||||
@ -488,7 +504,7 @@
|
|||||||
<input :id="`edit-field-identifier-${field.id}`" v-model="editingFieldIdentifier" required>
|
<input :id="`edit-field-identifier-${field.id}`" v-model="editingFieldIdentifier" required>
|
||||||
<label class="sr-only" :for="`edit-type-${field.id}`">Field type</label>
|
<label class="sr-only" :for="`edit-type-${field.id}`">Field type</label>
|
||||||
|
|
||||||
<select :id="`edit-type-${field.id}`" v-model="editingFieldType">
|
<select :id="`edit-type-${field.id}`" v-model="editingFieldType" @change="updateEditingFieldType">
|
||||||
<option v-for="type in fieldTypes" :key="type" :value="type">{{ typeLabel(type) }}</option>
|
<option v-for="type in fieldTypes" :key="type" :value="type">{{ typeLabel(type) }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@ -508,6 +524,15 @@
|
|||||||
</select>
|
</select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="editingFieldType === 'USER'">
|
||||||
|
<label class="sr-only" :for="`edit-user-relationship-${field.id}`">User relationship type</label>
|
||||||
|
|
||||||
|
<select :id="`edit-user-relationship-${field.id}`" v-model="editingRelationshipType">
|
||||||
|
<option value="ONE_TO_MANY">Many to one</option>
|
||||||
|
<option value="ONE_TO_ONE">One to one</option>
|
||||||
|
</select>
|
||||||
|
</template>
|
||||||
|
|
||||||
<button class="text-button" type="submit">Save field</button>
|
<button class="text-button" type="submit">Save field</button>
|
||||||
<button class="text-button muted" type="button" @click="editingFieldId = undefined">Cancel</button>
|
<button class="text-button muted" type="button" @click="editingFieldId = undefined">Cancel</button>
|
||||||
</form>
|
</form>
|
||||||
@ -522,7 +547,9 @@
|
|||||||
{{ targetName(field) }} · {{ relationshipLabel(field.relationshipType) }}
|
{{ targetName(field) }} · {{ relationshipLabel(field.relationshipType) }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span v-else-if="field.type === 'USER'" class="reference-detail">Built-in User entity</span>
|
<span v-else-if="field.type === 'USER'" class="reference-detail">
|
||||||
|
Built-in User entity · {{ userRelationshipLabel(field.relationshipType) }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
@ -549,7 +576,7 @@
|
|||||||
<input :id="`new-field-identifier-${entity.id}`" v-model="newFields[entity.id].identifier" placeholder="Identifier" required>
|
<input :id="`new-field-identifier-${entity.id}`" v-model="newFields[entity.id].identifier" placeholder="Identifier" required>
|
||||||
<label class="sr-only" :for="`new-type-${entity.id}`">Field type</label>
|
<label class="sr-only" :for="`new-type-${entity.id}`">Field type</label>
|
||||||
|
|
||||||
<select :id="`new-type-${entity.id}`" v-model="newFields[entity.id].type">
|
<select :id="`new-type-${entity.id}`" v-model="newFields[entity.id].type" @change="updateNewFieldType(entity.id)">
|
||||||
<option v-for="type in fieldTypes" :key="type" :value="type">{{ typeLabel(type) }}</option>
|
<option v-for="type in fieldTypes" :key="type" :value="type">{{ typeLabel(type) }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@ -569,6 +596,15 @@
|
|||||||
</select>
|
</select>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="newFields[entity.id].type === 'USER'">
|
||||||
|
<label class="sr-only" :for="`new-user-relationship-${entity.id}`">User relationship type</label>
|
||||||
|
|
||||||
|
<select :id="`new-user-relationship-${entity.id}`" v-model="newFields[entity.id].relationshipType">
|
||||||
|
<option value="ONE_TO_MANY">Many to one</option>
|
||||||
|
<option value="ONE_TO_ONE">One to one</option>
|
||||||
|
</select>
|
||||||
|
</template>
|
||||||
|
|
||||||
<button class="secondary-button" :disabled="saving" type="submit">Add field</button>
|
<button class="secondary-button" :disabled="saving" type="submit">Add field</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -184,9 +184,10 @@ test('admin can add, edit, and remove an entity and its fields', async ({ page }
|
|||||||
|
|
||||||
await organizationFieldForm.getByLabel('New field').fill('Account owner')
|
await organizationFieldForm.getByLabel('New field').fill('Account owner')
|
||||||
await organizationFieldForm.getByLabel('Field type').selectOption('USER')
|
await organizationFieldForm.getByLabel('Field type').selectOption('USER')
|
||||||
|
await organizationFieldForm.getByLabel('User relationship type').selectOption('ONE_TO_ONE')
|
||||||
await organizationFieldForm.getByRole('button', { name: 'Add field' }).click()
|
await organizationFieldForm.getByRole('button', { name: 'Add field' }).click()
|
||||||
await expect(organization.locator('.type-badge').filter({ hasText: 'User reference' })).toBeVisible()
|
await expect(organization.locator('.type-badge').filter({ hasText: 'User reference' })).toBeVisible()
|
||||||
await expect(organization.getByText('Built-in User entity')).toBeVisible()
|
await expect(organization.getByText('Built-in User entity · One to one')).toBeVisible()
|
||||||
|
|
||||||
await organization.getByRole('button', { name: 'Remove entity' }).click()
|
await organization.getByRole('button', { name: 'Remove entity' }).click()
|
||||||
await expect(page.getByRole('heading', { name: 'Organization' })).not.toBeVisible()
|
await expect(page.getByRole('heading', { name: 'Organization' })).not.toBeVisible()
|
||||||
|
|||||||
@ -140,6 +140,11 @@ class EntityDefinitionController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Context.relationshipDetails(fieldType: FieldType?): RelationshipDetails? {
|
private fun Context.relationshipDetails(fieldType: FieldType?): RelationshipDetails? {
|
||||||
|
if (fieldType == FieldType.USER) {
|
||||||
|
val relationshipType = formParam("relationshipType")?.let(RelationshipType::from)
|
||||||
|
?: RelationshipType.ONE_TO_MANY
|
||||||
|
return RelationshipDetails(null, relationshipType)
|
||||||
|
}
|
||||||
if (fieldType != FieldType.RELATIONSHIP) return RelationshipDetails(null, null)
|
if (fieldType != FieldType.RELATIONSHIP) return RelationshipDetails(null, null)
|
||||||
|
|
||||||
val targetEntityId = formParam("targetEntityId")?.toLongOrNull()
|
val targetEntityId = formParam("targetEntityId")?.toLongOrNull()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user