mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
feat(lib): relation component (#387)
* Fix relations view * extended relation component * added backend fields * bidirectional direction * fix linting
This commit is contained in:
parent
a2b7c16133
commit
c5232093dc
@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"collection": "relations",
|
||||||
|
"field": "direction",
|
||||||
|
"type": "string",
|
||||||
|
"meta": {
|
||||||
|
"collection": "relations",
|
||||||
|
"conditions": null,
|
||||||
|
"display": null,
|
||||||
|
"display_options": null,
|
||||||
|
"field": "direction",
|
||||||
|
"group": null,
|
||||||
|
"hidden": false,
|
||||||
|
"interface": "select-dropdown",
|
||||||
|
"note": null,
|
||||||
|
"options": {
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"icon": "arrow_forward",
|
||||||
|
"text": "outgoing",
|
||||||
|
"value": "outgoing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": "arrow_back",
|
||||||
|
"text": "ingoing",
|
||||||
|
"value": "ingoing"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"readonly": false,
|
||||||
|
"required": false,
|
||||||
|
"sort": 4,
|
||||||
|
"special": null,
|
||||||
|
"translations": null,
|
||||||
|
"validation": null,
|
||||||
|
"validation_message": null,
|
||||||
|
"width": "full"
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"name": "direction",
|
||||||
|
"table": "relations",
|
||||||
|
"data_type": "character varying",
|
||||||
|
"default_value": "outgoing",
|
||||||
|
"max_length": 255,
|
||||||
|
"numeric_precision": null,
|
||||||
|
"numeric_scale": null,
|
||||||
|
"is_nullable": true,
|
||||||
|
"is_unique": false,
|
||||||
|
"is_indexed": false,
|
||||||
|
"is_primary_key": false,
|
||||||
|
"is_generated": false,
|
||||||
|
"generation_expression": null,
|
||||||
|
"has_auto_increment": false,
|
||||||
|
"foreign_key_table": null,
|
||||||
|
"foreign_key_column": null
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"collection": "relations",
|
||||||
|
"field": "heading",
|
||||||
|
"type": "string",
|
||||||
|
"meta": {
|
||||||
|
"collection": "relations",
|
||||||
|
"conditions": null,
|
||||||
|
"display": null,
|
||||||
|
"display_options": null,
|
||||||
|
"field": "heading",
|
||||||
|
"group": null,
|
||||||
|
"hidden": false,
|
||||||
|
"interface": "input",
|
||||||
|
"note": null,
|
||||||
|
"options": null,
|
||||||
|
"readonly": false,
|
||||||
|
"required": false,
|
||||||
|
"sort": 3,
|
||||||
|
"special": null,
|
||||||
|
"translations": null,
|
||||||
|
"validation": null,
|
||||||
|
"validation_message": null,
|
||||||
|
"width": "full"
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"name": "heading",
|
||||||
|
"table": "relations",
|
||||||
|
"data_type": "character varying",
|
||||||
|
"default_value": "Relations",
|
||||||
|
"max_length": 255,
|
||||||
|
"numeric_precision": null,
|
||||||
|
"numeric_scale": null,
|
||||||
|
"is_nullable": true,
|
||||||
|
"is_unique": false,
|
||||||
|
"is_indexed": false,
|
||||||
|
"is_primary_key": false,
|
||||||
|
"is_generated": false,
|
||||||
|
"generation_expression": null,
|
||||||
|
"has_auto_increment": false,
|
||||||
|
"foreign_key_table": null,
|
||||||
|
"foreign_key_column": null
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"collection": "relations",
|
||||||
|
"field": "hideWhenEmpty",
|
||||||
|
"type": "boolean",
|
||||||
|
"meta": {
|
||||||
|
"collection": "relations",
|
||||||
|
"conditions": null,
|
||||||
|
"display": null,
|
||||||
|
"display_options": null,
|
||||||
|
"field": "hideWhenEmpty",
|
||||||
|
"group": null,
|
||||||
|
"hidden": false,
|
||||||
|
"interface": "boolean",
|
||||||
|
"note": null,
|
||||||
|
"options": null,
|
||||||
|
"readonly": false,
|
||||||
|
"required": false,
|
||||||
|
"sort": 5,
|
||||||
|
"special": [
|
||||||
|
"cast-boolean"
|
||||||
|
],
|
||||||
|
"translations": null,
|
||||||
|
"validation": null,
|
||||||
|
"validation_message": null,
|
||||||
|
"width": "full"
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"name": "hideWhenEmpty",
|
||||||
|
"table": "relations",
|
||||||
|
"data_type": "boolean",
|
||||||
|
"default_value": true,
|
||||||
|
"max_length": null,
|
||||||
|
"numeric_precision": null,
|
||||||
|
"numeric_scale": null,
|
||||||
|
"is_nullable": true,
|
||||||
|
"is_unique": false,
|
||||||
|
"is_indexed": false,
|
||||||
|
"is_primary_key": false,
|
||||||
|
"is_generated": false,
|
||||||
|
"generation_expression": null,
|
||||||
|
"has_auto_increment": false,
|
||||||
|
"foreign_key_table": null,
|
||||||
|
"foreign_key_column": null
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,6 @@
|
|||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
|
import { useAppState } from '#components/AppShell/hooks/useAppState'
|
||||||
import { useItems } from '#components/Map/hooks/useItems'
|
import { useItems } from '#components/Map/hooks/useItems'
|
||||||
|
|
||||||
import type { Item } from '#types/Item'
|
import type { Item } from '#types/Item'
|
||||||
@ -5,27 +8,79 @@ import type { Item } from '#types/Item'
|
|||||||
interface Props {
|
interface Props {
|
||||||
item: Item
|
item: Item
|
||||||
relation: string
|
relation: string
|
||||||
|
heading: string
|
||||||
|
direction?: 'outgoing' | 'ingoing' | 'bidirectional'
|
||||||
|
hideWhenEmpty?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RelationsView = ({ item, relation }: Props) => {
|
export const RelationsView = ({
|
||||||
|
item,
|
||||||
|
relation,
|
||||||
|
heading,
|
||||||
|
direction = 'outgoing',
|
||||||
|
hideWhenEmpty = true,
|
||||||
|
}: Props) => {
|
||||||
const items = useItems()
|
const items = useItems()
|
||||||
|
const appState = useAppState()
|
||||||
|
|
||||||
if (!item.relations) return
|
if (!item.relations) return
|
||||||
|
|
||||||
const relationsOfRightType = item.relations.filter((r) => r.type === relation)
|
const relationsOfRightType = item.relations.filter((r) => r.type === relation)
|
||||||
|
|
||||||
const relatedItems = items.filter((i) => relationsOfRightType.some((r) => r.id === i.id))
|
const relatedItems = (() => {
|
||||||
|
const outgoingItems = items.filter((i) =>
|
||||||
|
relationsOfRightType.some((r) => r.related_items_id === i.id),
|
||||||
|
)
|
||||||
|
|
||||||
|
const ingoingItems = items.filter((i) =>
|
||||||
|
i.relations?.some((r) => r.type === relation && r.related_items_id === item.id),
|
||||||
|
)
|
||||||
|
|
||||||
|
switch (direction) {
|
||||||
|
case 'outgoing':
|
||||||
|
return outgoingItems
|
||||||
|
case 'ingoing':
|
||||||
|
return ingoingItems
|
||||||
|
case 'bidirectional': {
|
||||||
|
// Combine both arrays and remove duplicates
|
||||||
|
const allItems = [...outgoingItems, ...ingoingItems]
|
||||||
|
return allItems.filter(
|
||||||
|
(item, index, self) => index === self.findIndex((i) => i.id === item.id),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return outgoingItems
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
const hasRelatedItems = relatedItems.length > 0
|
const hasRelatedItems = relatedItems.length > 0
|
||||||
|
|
||||||
|
if (hideWhenEmpty && !hasRelatedItems) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className='tw:my-10 tw:mt-2 tw:px-6'>
|
||||||
<h2>{relation}</h2>
|
<h2 className='tw:text-lg tw:font-bold'>{heading}</h2>
|
||||||
{hasRelatedItems ? (
|
{hasRelatedItems ? (
|
||||||
<ul>
|
<ul>
|
||||||
{relatedItems.map((relatedItem) => (
|
{relatedItems.map((relatedItem) => (
|
||||||
<li key={relatedItem.id}>
|
<li key={relatedItem.id}>
|
||||||
<a href={`/item/${relatedItem.id}`}>{relatedItem.name}</a>
|
<Link to={relatedItem.id} className='tw:flex tw:flex-row'>
|
||||||
|
<div>
|
||||||
|
{relatedItem.image ? (
|
||||||
|
<img
|
||||||
|
className='tw:size-10 tw:rounded-full'
|
||||||
|
src={appState.assetsApi.url + '/' + relatedItem.image}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className='tw:size-10 tw:rounded-full tw:bg-gray-200' />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='tw:ml-2 tw:flex tw:items-center tw:min-h-[2.5rem]'>
|
||||||
|
<div>{relatedItem.name}</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user