mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
feat(lib): blanked out maps support (#416)
Co-authored-by: mahula <lenzmath@posteo.de> Co-authored-by: Ulf Gebhardt <ulf.gebhardt@webcraft-media.de>
This commit is contained in:
parent
9f1368e6c5
commit
e261d68534
@ -110,6 +110,7 @@ function MapContainer({ layers, map }: { layers: LayerProps[]; map: any }) {
|
|||||||
public_edit_items={layer.public_edit_items}
|
public_edit_items={layer.public_edit_items}
|
||||||
listed={layer.listed}
|
listed={layer.listed}
|
||||||
api={apis.find((api) => api.id === layer.id)?.api}
|
api={apis.find((api) => api.id === layer.id)?.api}
|
||||||
|
item_default_name={layer.item_default_name}
|
||||||
>
|
>
|
||||||
<PopupView>
|
<PopupView>
|
||||||
{layer.itemType.show_start_end && <StartEndView></StartEndView>}
|
{layer.itemType.show_start_end && <StartEndView></StartEndView>}
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"collection": "layers",
|
||||||
|
"field": "item_default_name",
|
||||||
|
"type": "string",
|
||||||
|
"meta": {
|
||||||
|
"collection": "layers",
|
||||||
|
"conditions": null,
|
||||||
|
"display": null,
|
||||||
|
"display_options": null,
|
||||||
|
"field": "item_default_name",
|
||||||
|
"group": null,
|
||||||
|
"hidden": false,
|
||||||
|
"interface": "input",
|
||||||
|
"note": null,
|
||||||
|
"options": null,
|
||||||
|
"readonly": false,
|
||||||
|
"required": false,
|
||||||
|
"sort": 16,
|
||||||
|
"special": null,
|
||||||
|
"translations": null,
|
||||||
|
"validation": null,
|
||||||
|
"validation_message": null,
|
||||||
|
"width": "half"
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"name": "item_default_name",
|
||||||
|
"table": "layers",
|
||||||
|
"data_type": "character varying",
|
||||||
|
"default_value": "item",
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
"readonly": false,
|
"readonly": false,
|
||||||
"required": false,
|
"required": false,
|
||||||
"sort": 16,
|
"sort": 17,
|
||||||
"special": [
|
"special": [
|
||||||
"cast-json"
|
"cast-json"
|
||||||
],
|
],
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
"options": {},
|
"options": {},
|
||||||
"readonly": false,
|
"readonly": false,
|
||||||
"required": false,
|
"required": false,
|
||||||
"sort": 17,
|
"sort": 18,
|
||||||
"special": [
|
"special": [
|
||||||
"m2m"
|
"m2m"
|
||||||
],
|
],
|
||||||
|
|||||||
@ -173,7 +173,7 @@ export const PopupView = ({ children }: { children?: React.ReactNode }) => {
|
|||||||
</ItemViewPopup>
|
</ItemViewPopup>
|
||||||
|
|
||||||
<Tooltip offset={[0, -38]} direction='top'>
|
<Tooltip offset={[0, -38]} direction='top'>
|
||||||
{item.name}
|
{item.name || item.layer?.item_default_name}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Marker>
|
</Marker>
|
||||||
</TemplateItemContext.Provider>
|
</TemplateItemContext.Provider>
|
||||||
|
|||||||
@ -35,6 +35,8 @@ export const Layer = ({
|
|||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
public_edit_items,
|
public_edit_items,
|
||||||
listed = true,
|
listed = true,
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
item_default_name = 'item',
|
||||||
}: LayerProps) => {
|
}: LayerProps) => {
|
||||||
const setItemsApi = useSetItemsApi()
|
const setItemsApi = useSetItemsApi()
|
||||||
const setItemsData = useSetItemsData()
|
const setItemsData = useSetItemsData()
|
||||||
@ -65,6 +67,8 @@ export const Layer = ({
|
|||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
public_edit_items,
|
public_edit_items,
|
||||||
listed,
|
listed,
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
item_default_name,
|
||||||
})
|
})
|
||||||
api &&
|
api &&
|
||||||
setItemsApi({
|
setItemsApi({
|
||||||
@ -86,6 +90,8 @@ export const Layer = ({
|
|||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
public_edit_items,
|
public_edit_items,
|
||||||
listed,
|
listed,
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
item_default_name,
|
||||||
})
|
})
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [data, api])
|
}, [data, api])
|
||||||
|
|||||||
@ -60,7 +60,7 @@ export function HeaderView({
|
|||||||
const avatar =
|
const avatar =
|
||||||
(item?.image && appState.assetsApi.url + item.image + '?width=160&heigth=160') ||
|
(item?.image && appState.assetsApi.url + item.image + '?width=160&heigth=160') ||
|
||||||
item?.image_external
|
item?.image_external
|
||||||
const title = item?.name
|
const title = item?.name ?? item?.layer?.item_default_name
|
||||||
const subtitle = item?.subname
|
const subtitle = item?.subname
|
||||||
|
|
||||||
const [address] = useState<string>('')
|
const [address] = useState<string>('')
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export const TextView = ({
|
|||||||
}: {
|
}: {
|
||||||
item?: Item
|
item?: Item
|
||||||
itemId?: string
|
itemId?: string
|
||||||
text?: string
|
text?: string | null
|
||||||
truncate?: boolean
|
truncate?: boolean
|
||||||
rawText?: string
|
rawText?: string
|
||||||
}) => {
|
}) => {
|
||||||
@ -44,7 +44,14 @@ export const TextView = ({
|
|||||||
|
|
||||||
if (rawText) {
|
if (rawText) {
|
||||||
innerText = replacedText = rawText
|
innerText = replacedText = rawText
|
||||||
} else if (text) {
|
} else if (text === undefined) {
|
||||||
|
// Field was omitted by backend (no permission)
|
||||||
|
innerText = replacedText = `Login to see this ${item?.layer?.item_default_name ?? 'item'}`
|
||||||
|
} else if (text === null || text === '') {
|
||||||
|
// Field is not set or empty - show nothing
|
||||||
|
innerText = ''
|
||||||
|
} else {
|
||||||
|
// Field has a value
|
||||||
innerText = text
|
innerText = text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,9 +5,19 @@
|
|||||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/no-misused-promises */
|
/* eslint-disable @typescript-eslint/no-misused-promises */
|
||||||
import { useCallback, useReducer, createContext, useContext, useState } from 'react'
|
import {
|
||||||
|
useCallback,
|
||||||
|
useReducer,
|
||||||
|
createContext,
|
||||||
|
useContext,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
} from 'react'
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
|
import { useAuth } from '#components/Auth/useAuth'
|
||||||
|
|
||||||
import { useAddLayer } from './useLayers'
|
import { useAddLayer } from './useLayers'
|
||||||
|
|
||||||
import type { Item } from '#types/Item'
|
import type { Item } from '#types/Item'
|
||||||
@ -18,6 +28,7 @@ type ActionType =
|
|||||||
| { type: 'UPDATE'; item: Item }
|
| { type: 'UPDATE'; item: Item }
|
||||||
| { type: 'REMOVE'; item: Item }
|
| { type: 'REMOVE'; item: Item }
|
||||||
| { type: 'RESET'; layer: LayerProps }
|
| { type: 'RESET'; layer: LayerProps }
|
||||||
|
| { type: 'CLEAR_ALL' }
|
||||||
|
|
||||||
type UseItemManagerResult = ReturnType<typeof useItemsManager>
|
type UseItemManagerResult = ReturnType<typeof useItemsManager>
|
||||||
|
|
||||||
@ -43,8 +54,10 @@ function useItemsManager(initialItems: Item[]): {
|
|||||||
allItemsLoaded: boolean
|
allItemsLoaded: boolean
|
||||||
} {
|
} {
|
||||||
const addLayer = useAddLayer()
|
const addLayer = useAddLayer()
|
||||||
|
const { user } = useAuth()
|
||||||
|
|
||||||
const [allItemsLoaded, setallItemsLoaded] = useState<boolean>(false)
|
const [allItemsLoaded, setallItemsLoaded] = useState<boolean>(false)
|
||||||
|
const layersRef = useRef<LayerProps[]>([])
|
||||||
|
|
||||||
const [items, dispatch] = useReducer((state: Item[], action: ActionType) => {
|
const [items, dispatch] = useReducer((state: Item[], action: ActionType) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
@ -65,6 +78,8 @@ function useItemsManager(initialItems: Item[]): {
|
|||||||
return state.filter((item) => item !== action.item)
|
return state.filter((item) => item !== action.item)
|
||||||
case 'RESET':
|
case 'RESET':
|
||||||
return state.filter((item) => item.layer?.name !== action.layer.name)
|
return state.filter((item) => item.layer?.name !== action.layer.name)
|
||||||
|
case 'CLEAR_ALL':
|
||||||
|
return []
|
||||||
default:
|
default:
|
||||||
throw new Error()
|
throw new Error()
|
||||||
}
|
}
|
||||||
@ -72,6 +87,7 @@ function useItemsManager(initialItems: Item[]): {
|
|||||||
|
|
||||||
const setItemsApi = useCallback(async (layer: LayerProps) => {
|
const setItemsApi = useCallback(async (layer: LayerProps) => {
|
||||||
addLayer(layer)
|
addLayer(layer)
|
||||||
|
layersRef.current.push(layer)
|
||||||
const result = await toast.promise(layer.api!.getItems(), {
|
const result = await toast.promise(layer.api!.getItems(), {
|
||||||
pending: `loading ${layer.name} ...`,
|
pending: `loading ${layer.name} ...`,
|
||||||
success: `${layer.name} loaded`,
|
success: `${layer.name} loaded`,
|
||||||
@ -127,6 +143,38 @@ function useItemsManager(initialItems: Item[]): {
|
|||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const reloadAllItems = useCallback(async () => {
|
||||||
|
dispatch({ type: 'CLEAR_ALL' })
|
||||||
|
setallItemsLoaded(false)
|
||||||
|
|
||||||
|
for (const layer of layersRef.current) {
|
||||||
|
if (layer.api) {
|
||||||
|
const result = await toast.promise(layer.api.getItems(), {
|
||||||
|
pending: `loading ${layer.name} ...`,
|
||||||
|
success: `${layer.name} loaded`,
|
||||||
|
error: {
|
||||||
|
render({ data }) {
|
||||||
|
return `${data}`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
result.map((item) => {
|
||||||
|
dispatch({ type: 'ADD', item: { ...item, layer } })
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setallItemsLoaded(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (layersRef.current.length > 0) {
|
||||||
|
void reloadAllItems()
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [user?.id])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items,
|
items,
|
||||||
updateItem,
|
updateItem,
|
||||||
|
|||||||
@ -24,6 +24,7 @@ export const GalleryView = ({ item }: { item: Item }) => {
|
|||||||
const appState = useAppState()
|
const appState = useAppState()
|
||||||
const images =
|
const images =
|
||||||
item.gallery?.flatMap((g, index) => {
|
item.gallery?.flatMap((g, index) => {
|
||||||
|
if (!g.directus_files_id) return []
|
||||||
const file = g.directus_files_id
|
const file = g.directus_files_id
|
||||||
if (typeof file === 'string') return []
|
if (typeof file === 'string') return []
|
||||||
const { id, type, width, height } = file
|
const { id, type, width, height } = file
|
||||||
|
|||||||
@ -17,15 +17,14 @@ export const ProfileTextView = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const text = get(item, dataField)
|
const text = get(item, dataField)
|
||||||
|
|
||||||
const parsedText = typeof text !== 'string' ? '' : text
|
// undefined = no permission, null = not set, string = value exists
|
||||||
|
const shouldShowHeading = !(hideWhenEmpty && (text === '' || text === null))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='tw:my-10 tw:mt-2 tw:px-6'>
|
<div className='tw:my-10 tw:mt-2 tw:px-6'>
|
||||||
{!(text === '' && hideWhenEmpty) && (
|
{shouldShowHeading && <h2 className='tw:text-lg tw:font-semibold'>{heading}</h2>}
|
||||||
<h2 className='tw:text-lg tw:font-semibold'>{heading}</h2>
|
|
||||||
)}
|
|
||||||
<div className='tw:mt-2 tw:text-sm'>
|
<div className='tw:mt-2 tw:text-sm'>
|
||||||
<TextView itemId={item.id} rawText={parsedText} />
|
<TextView item={item} text={text as string | null | undefined} itemId={item.id} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
1
lib/src/types/LayerProps.d.ts
vendored
1
lib/src/types/LayerProps.d.ts
vendored
@ -25,4 +25,5 @@ export interface LayerProps {
|
|||||||
public_edit_items?: boolean
|
public_edit_items?: boolean
|
||||||
listed?: boolean
|
listed?: boolean
|
||||||
item_presets?: Record<string, unknown>
|
item_presets?: Record<string, unknown>
|
||||||
|
item_default_name?: string
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user