mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3399 Primitives | Object's featured properties (#2211)
This commit is contained in:
parent
3bf0c305a0
commit
bef75d1cbf
13 changed files with 691 additions and 321 deletions
|
@ -805,6 +805,7 @@ class EditorViewModel(
|
|||
anchor = context,
|
||||
indent = INITIAL_INDENT,
|
||||
details = objectViewDetails,
|
||||
participantCanEdit = permission?.isOwnerOrEditor() == true,
|
||||
restrictions = orchestrator.stores.objectRestrictions.current(),
|
||||
selection = currentSelection()
|
||||
) { onRenderFlagFound -> flags.add(onRenderFlagFound) }
|
||||
|
|
|
@ -1287,8 +1287,9 @@ sealed class BlockView : ViewType {
|
|||
data class FeaturedRelation(
|
||||
override val id: String,
|
||||
val relations: List<ObjectRelationView>,
|
||||
val allowChangingObjectType: Boolean = true,
|
||||
val isTodoLayout: Boolean = false
|
||||
val allowChangingObjectType: Boolean = false,
|
||||
val isTodoLayout: Boolean = false,
|
||||
val hasFeaturePropertiesConflict: Boolean = false,
|
||||
) : BlockView() {
|
||||
override fun getViewType(): Int = HOLDER_FEATURED_RELATION
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ interface BlockViewRenderer {
|
|||
selection: Set<Id>,
|
||||
count: Int = 0,
|
||||
parentScheme: NestedDecorationData = emptyList(),
|
||||
participantCanEdit: Boolean = false,
|
||||
onRenderFlag: (RenderFlag) -> Unit = {},
|
||||
): List<BlockView>
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import com.anytypeio.anytype.core_models.Block.Content
|
|||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.Key
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.ObjectTypeIds.BOOKMARK
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.ThemeColor
|
||||
|
@ -30,7 +29,6 @@ import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
|||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView.Appearance.InEditor
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView.Mode
|
||||
import com.anytypeio.anytype.presentation.editor.toggle.ToggleStateHolder
|
||||
import com.anytypeio.anytype.presentation.extension.getTypeForObject
|
||||
import com.anytypeio.anytype.presentation.mapper.objectIcon
|
||||
import com.anytypeio.anytype.presentation.mapper.marks
|
||||
import com.anytypeio.anytype.presentation.mapper.toFileView
|
||||
|
@ -39,13 +37,9 @@ import com.anytypeio.anytype.presentation.mapper.toVideoView
|
|||
import com.anytypeio.anytype.presentation.mapper.toView
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.appearance.LinkAppearanceFactory
|
||||
import com.anytypeio.anytype.presentation.objects.getFeaturedPropertiesIds
|
||||
import com.anytypeio.anytype.presentation.objects.getProperType
|
||||
import com.anytypeio.anytype.presentation.objects.toFeaturedPropertiesViews
|
||||
import com.anytypeio.anytype.presentation.relations.BasicObjectCoverWrapper
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
|
||||
import com.anytypeio.anytype.presentation.relations.getCover
|
||||
import com.anytypeio.anytype.presentation.relations.linksFeaturedRelation
|
||||
import com.anytypeio.anytype.presentation.relations.objectTypeRelation
|
||||
import com.anytypeio.anytype.presentation.relations.view
|
||||
import com.anytypeio.anytype.presentation.widgets.collection.ResourceProvider
|
||||
import javax.inject.Inject
|
||||
|
@ -74,6 +68,7 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
selection: Set<Id>,
|
||||
count: Int,
|
||||
parentScheme: NestedDecorationData,
|
||||
participantCanEdit: Boolean,
|
||||
onRenderFlag: (BlockViewRenderer.RenderFlag) -> Unit,
|
||||
): List<BlockView> {
|
||||
|
||||
|
@ -710,10 +705,15 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
is Content.FeaturedRelations -> {
|
||||
isPreviousBlockMedia = false
|
||||
mCounter = 0
|
||||
val featured = featured(
|
||||
ctx = root.id,
|
||||
block = block,
|
||||
details = details
|
||||
val featured = toFeaturedPropertiesViews(
|
||||
objectId = root.id,
|
||||
details = details,
|
||||
storeOfRelations = storeOfRelations,
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
urlBuilder = urlBuilder,
|
||||
fieldParser = fieldParser,
|
||||
blocks = listOf(block),
|
||||
participantCanEdit = participantCanEdit
|
||||
)
|
||||
|
||||
if (!featured?.relations.isNullOrEmpty()) {
|
||||
|
@ -2074,25 +2074,6 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun featured(
|
||||
ctx: Id,
|
||||
block: Block,
|
||||
details: ObjectViewDetails
|
||||
): BlockView.FeaturedRelation? {
|
||||
val obj = details.getObject(ctx) ?: return null
|
||||
val views = mapFeaturedRelations(
|
||||
ctx = ctx,
|
||||
details = details,
|
||||
currentObject = obj
|
||||
)
|
||||
return BlockView.FeaturedRelation(
|
||||
id = block.id,
|
||||
relations = views,
|
||||
allowChangingObjectType = obj.type.contains(BOOKMARK) != true,
|
||||
isTodoLayout = obj.layout == ObjectType.Layout.TODO
|
||||
)
|
||||
}
|
||||
|
||||
private fun workaroundGlobalNameOrIdentityRelation(
|
||||
featured: List<Key>,
|
||||
values: Map<String, Any?>
|
||||
|
@ -2116,68 +2097,6 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
return result
|
||||
}
|
||||
|
||||
private suspend fun mapFeaturedRelations(
|
||||
ctx: Id,
|
||||
currentObject: ObjectWrapper.Basic,
|
||||
details: ObjectViewDetails,
|
||||
): List<ObjectRelationView> {
|
||||
|
||||
val objectFeaturedPropertiesKeys = currentObject.featuredRelations
|
||||
|
||||
val featuredProperties = if (objectFeaturedPropertiesKeys.isNotEmpty()) {
|
||||
objectFeaturedPropertiesKeys.mapNotNull { key ->
|
||||
storeOfRelations.getByKey(key)
|
||||
}
|
||||
.sortedByDescending { it.key == Relations.TYPE }
|
||||
} else {
|
||||
currentObject.getFeaturedPropertiesIds(
|
||||
storeOfRelations = storeOfRelations,
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
fieldParser = fieldParser
|
||||
).mapNotNull { id ->
|
||||
storeOfRelations.getById(id = id)
|
||||
}
|
||||
}
|
||||
|
||||
return featuredProperties.mapNotNull { property ->
|
||||
|
||||
when (property.key) {
|
||||
Relations.DESCRIPTION -> null
|
||||
Relations.TYPE -> {
|
||||
val objectTypeId = details.getObject(ctx)?.getProperType()
|
||||
if (objectTypeId != null) {
|
||||
details.objectTypeRelation(
|
||||
relationKey = property.key,
|
||||
isFeatured = true,
|
||||
objectTypeId = objectTypeId
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
Relations.BACKLINKS, Relations.LINKS -> {
|
||||
details.linksFeaturedRelation(
|
||||
relations = storeOfRelations.getAll(),
|
||||
ctx = ctx,
|
||||
relationKey = property.key,
|
||||
isFeatured = true
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
val values = details.getObject(ctx)?.map.orEmpty()
|
||||
property.view(
|
||||
details = details,
|
||||
values = values,
|
||||
urlBuilder = urlBuilder,
|
||||
isFeatured = true,
|
||||
fieldParser = fieldParser,
|
||||
storeOfObjectTypes = storeOfObjectTypes
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkIfSelected(
|
||||
mode: Editor.Mode,
|
||||
block: Block,
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
package com.anytypeio.anytype.presentation.objects
|
||||
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.ObjectTypeIds
|
||||
import com.anytypeio.anytype.core_models.ObjectViewDetails
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.permissions.toObjectPermissionsForTypes
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfRelations
|
||||
import com.anytypeio.anytype.domain.primitives.FieldParser
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.extension.getObject
|
||||
import com.anytypeio.anytype.presentation.extension.getTypeForObject
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
|
||||
import com.anytypeio.anytype.presentation.relations.isSystemKey
|
||||
import com.anytypeio.anytype.presentation.relations.linksFeaturedRelation
|
||||
import com.anytypeio.anytype.presentation.relations.view
|
||||
import kotlin.collections.mapNotNull
|
||||
|
||||
enum class ConflictResolutionStrategy {
|
||||
MERGE,
|
||||
OBJECT_ONLY
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an object's featured properties into a [BlockView.FeaturedRelation] view.
|
||||
*
|
||||
* Retrieves the current object and its type from [details] using [objectId]. If the object's type is TEMPLATE,
|
||||
* its target type is used as the effective type. The method then obtains the featured properties from the object
|
||||
* (via keys) and parses the recommended featured property IDs from the effective type using [fieldParser]. It fetches
|
||||
* the corresponding properties from [storeOfRelations] and checks for conflicts (i.e. any property key not equal
|
||||
* to [Relations.DESCRIPTION]).
|
||||
*
|
||||
* In case of a conflict, the [conflictResolution] strategy is applied:
|
||||
* - [ConflictResolutionStrategy.MERGE]: Merges the type and object properties, giving precedence to type properties.
|
||||
* - [ConflictResolutionStrategy.OBJECT_ONLY] (default): Uses only the object properties.
|
||||
*
|
||||
* Finally, permissions are computed and the featured relation view is returned.
|
||||
*
|
||||
* @param objectId The object's ID.
|
||||
* @param blocks The list of blocks; the featured relations block is used.
|
||||
* @param urlBuilder Used for URL generation in views.
|
||||
* @param fieldParser Parses fields for view rendering.
|
||||
* @param storeOfObjectTypes Store for object type information.
|
||||
* @param storeOfRelations Store for relation properties.
|
||||
* @param details Provides object view context.
|
||||
* @param participantCanEdit Indicates if the participant has edit permissions.
|
||||
* @param conflictResolution Determines which strategy to use when a conflict is detected.
|
||||
*
|
||||
* @return The [BlockView.FeaturedRelation] view, or `null` if no valid featured block or object is found.
|
||||
*/
|
||||
suspend fun toFeaturedPropertiesViews(
|
||||
objectId: Id,
|
||||
blocks: List<Block>,
|
||||
urlBuilder: UrlBuilder,
|
||||
fieldParser: FieldParser,
|
||||
storeOfObjectTypes: StoreOfObjectTypes,
|
||||
storeOfRelations: StoreOfRelations,
|
||||
details: ObjectViewDetails,
|
||||
participantCanEdit: Boolean,
|
||||
conflictResolutionStrategy: ConflictResolutionStrategy = ConflictResolutionStrategy.OBJECT_ONLY
|
||||
): BlockView.FeaturedRelation? {
|
||||
|
||||
val block = blocks.find { it.content is Block.Content.FeaturedRelations }
|
||||
|
||||
if (block != null) {
|
||||
val views = mutableListOf<ObjectRelationView>()
|
||||
val currentObject = details.getObject(objectId)
|
||||
if (currentObject?.isValid != true) {
|
||||
//object not found or not valid, do not render featured properties
|
||||
return null
|
||||
}
|
||||
val objectFeaturedProperties = storeOfRelations.getByKeys(
|
||||
keys = currentObject.featuredRelations
|
||||
)
|
||||
|
||||
val currType = details.getTypeForObject(objectId)
|
||||
// Determine the effective object type. If the type is TEMPLATE, use the target object type.
|
||||
val effectiveType = if (currType?.uniqueKey == ObjectTypeIds.TEMPLATE) {
|
||||
currentObject.targetObjectType?.let { storeOfObjectTypes.get(it) }
|
||||
} else {
|
||||
currType
|
||||
}
|
||||
|
||||
val typeRecommendedFeaturedPropertiesIds = if (effectiveType != null) {
|
||||
// Parse the object's properties using the effective type.
|
||||
val parsedProperties = fieldParser.getObjectParsedProperties(
|
||||
objectType = effectiveType,
|
||||
objPropertiesKeys = currentObject.map.keys.toList(),
|
||||
storeOfRelations = storeOfRelations
|
||||
)
|
||||
parsedProperties.header.map { it.id }
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val typeRecommendedFeaturedProperties = storeOfRelations.getById(
|
||||
ids = typeRecommendedFeaturedPropertiesIds
|
||||
)
|
||||
|
||||
val hasConflict = objectFeaturedProperties.any { property -> property.key != Relations.DESCRIPTION } == true
|
||||
|
||||
if (!hasConflict) {
|
||||
val featuredViews = typeRecommendedFeaturedProperties.mapNotNull { property ->
|
||||
property.toView(
|
||||
currentObject = currentObject,
|
||||
typeOfCurrentObject = currType,
|
||||
details = details,
|
||||
urlBuilder = urlBuilder,
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
fieldParser = fieldParser,
|
||||
storeOfRelations = storeOfRelations
|
||||
)
|
||||
}
|
||||
views.addAll(featuredViews)
|
||||
} else {
|
||||
when (conflictResolutionStrategy) {
|
||||
ConflictResolutionStrategy.MERGE -> {
|
||||
val displayPropertiesMap = LinkedHashMap<String, ObjectWrapper.Relation>()
|
||||
for (prop in typeRecommendedFeaturedProperties) {
|
||||
displayPropertiesMap[prop.id] = prop
|
||||
}
|
||||
for (prop in objectFeaturedProperties) {
|
||||
displayPropertiesMap.putIfAbsent(prop.id, prop)
|
||||
}
|
||||
val featuredViews = displayPropertiesMap.values.mapNotNull { property ->
|
||||
property.toView(
|
||||
currentObject = currentObject,
|
||||
typeOfCurrentObject = currType,
|
||||
details = details,
|
||||
urlBuilder = urlBuilder,
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
fieldParser = fieldParser,
|
||||
storeOfRelations = storeOfRelations
|
||||
)
|
||||
}
|
||||
views.addAll(featuredViews)
|
||||
}
|
||||
ConflictResolutionStrategy.OBJECT_ONLY -> {
|
||||
val featuredViews = objectFeaturedProperties.mapNotNull { property ->
|
||||
property.toView(
|
||||
currentObject = currentObject,
|
||||
typeOfCurrentObject = currType,
|
||||
details = details,
|
||||
urlBuilder = urlBuilder,
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
fieldParser = fieldParser,
|
||||
storeOfRelations = storeOfRelations
|
||||
)
|
||||
}
|
||||
views.addAll(featuredViews)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val canChangeType = currType?.toObjectPermissionsForTypes(participantCanEdit)?.canChangeType == true
|
||||
return BlockView.FeaturedRelation(
|
||||
id = block.id,
|
||||
relations = views,
|
||||
allowChangingObjectType = canChangeType,
|
||||
isTodoLayout = currType?.recommendedLayout == ObjectType.Layout.TODO,
|
||||
hasFeaturePropertiesConflict = hasConflict
|
||||
)
|
||||
} else {
|
||||
//featured block not found
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun ObjectWrapper.Relation.toView(
|
||||
currentObject: ObjectWrapper.Basic,
|
||||
typeOfCurrentObject: ObjectWrapper.Type?,
|
||||
details: ObjectViewDetails,
|
||||
urlBuilder: UrlBuilder,
|
||||
storeOfObjectTypes: StoreOfObjectTypes,
|
||||
storeOfRelations: StoreOfRelations,
|
||||
fieldParser: FieldParser
|
||||
) : ObjectRelationView? {
|
||||
val property = this
|
||||
val propertyKey = property.key
|
||||
return when (propertyKey) {
|
||||
Relations.DESCRIPTION -> null
|
||||
Relations.TYPE -> {
|
||||
if (typeOfCurrentObject == null || typeOfCurrentObject.isDeleted == true) {
|
||||
val id = currentObject.getProperType()
|
||||
if (id == null) {
|
||||
null
|
||||
} else {
|
||||
ObjectRelationView.ObjectType.Deleted(
|
||||
id = id,
|
||||
key = propertyKey,
|
||||
featured = true,
|
||||
readOnly = false,
|
||||
system = false
|
||||
)
|
||||
}
|
||||
} else {
|
||||
ObjectRelationView.ObjectType.Base(
|
||||
id = id,
|
||||
key = propertyKey,
|
||||
name = fieldParser.getObjectName(typeOfCurrentObject),
|
||||
featured = true,
|
||||
readOnly = false,
|
||||
type = typeOfCurrentObject.id,
|
||||
system = uniqueKey?.isSystemKey() == true
|
||||
)
|
||||
}
|
||||
}
|
||||
Relations.SET_OF -> {
|
||||
|
||||
val source = currentObject.setOf.firstOrNull()
|
||||
|
||||
val wrapper = if (source != null) {
|
||||
details.getObject(source)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val isValid = wrapper?.isValid == true
|
||||
val isDeleted = wrapper?.isDeleted == true
|
||||
val isReadOnly = wrapper?.relationReadonlyValue == true
|
||||
|
||||
val sources = if (isValid && !isDeleted) {
|
||||
listOf(
|
||||
wrapper.toObjectViewDefault(
|
||||
urlBuilder = urlBuilder,
|
||||
fieldParser = fieldParser,
|
||||
storeOfObjectTypes = storeOfObjectTypes
|
||||
)
|
||||
)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
ObjectRelationView.Source(
|
||||
id = currentObject.id,
|
||||
key = propertyKey,
|
||||
name = Relations.RELATION_NAME_EMPTY,
|
||||
featured = true,
|
||||
readOnly = isReadOnly,
|
||||
sources = sources,
|
||||
system = propertyKey.isSystemKey()
|
||||
)
|
||||
}
|
||||
Relations.BACKLINKS, Relations.LINKS -> {
|
||||
details.linksFeaturedRelation(
|
||||
relations = storeOfRelations.getAll(),
|
||||
ctx = currentObject.id,
|
||||
relationKey = propertyKey,
|
||||
isFeatured = true
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
property.view(
|
||||
details = details,
|
||||
values = currentObject.map,
|
||||
urlBuilder = urlBuilder,
|
||||
isFeatured = true,
|
||||
fieldParser = fieldParser,
|
||||
storeOfObjectTypes = storeOfObjectTypes
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -370,41 +370,4 @@ private fun updateObjectIcon(obj: ObjectView): ObjectView {
|
|||
is ObjectView.Default -> obj.copy(icon = ObjectIcon.None)
|
||||
is ObjectView.Deleted -> obj
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of featured header property IDs for the current [ObjectWrapper.Basic] object.
|
||||
*
|
||||
* All objects have an associated type which can be obtained from [StoreOfObjectTypes]. In the case that the object's
|
||||
* type is a Template (i.e. its unique key equals [ObjectTypeIds.TEMPLATE]), the target object type is resolved using
|
||||
* the [targetObjectType] property. Once the effective object type is determined, the function uses [FieldParser] to
|
||||
* obtain parsed properties and returns the header IDs.
|
||||
*
|
||||
* @param storeOfObjectTypes The store that provides object types.
|
||||
* @param storeOfRelations The store that provides relations between objects.
|
||||
* @param fieldParser The parser used to extract parsed properties from an object.
|
||||
* @return A list of header property IDs, or an empty list if the necessary object type is not found.
|
||||
*/
|
||||
suspend fun ObjectWrapper.Basic.getFeaturedPropertiesIds(
|
||||
storeOfObjectTypes: StoreOfObjectTypes,
|
||||
storeOfRelations: StoreOfRelations,
|
||||
fieldParser: FieldParser,
|
||||
): List<Id> {
|
||||
// Retrieve the object's current type.
|
||||
val currentObjType = storeOfObjectTypes.getTypeOfObject(this) ?: return emptyList()
|
||||
|
||||
// Determine the effective object type. If the type is TEMPLATE, use the target object type.
|
||||
val effectiveType = if (currentObjType.uniqueKey == ObjectTypeIds.TEMPLATE) {
|
||||
this.targetObjectType?.let { storeOfObjectTypes.get(it) } ?: return emptyList()
|
||||
} else {
|
||||
currentObjType
|
||||
}
|
||||
|
||||
// Parse the object's properties using the effective type.
|
||||
val parsedProperties = fieldParser.getObjectParsedProperties(
|
||||
objectType = effectiveType,
|
||||
objPropertiesKeys = this.map.keys.toList(),
|
||||
storeOfRelations = storeOfRelations
|
||||
)
|
||||
return parsedProperties.header.map { it.id }
|
||||
}
|
|
@ -12,7 +12,6 @@ import com.anytypeio.anytype.core_models.ObjectViewDetails
|
|||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.presentation.extension.getObject
|
||||
import com.anytypeio.anytype.presentation.extension.getOptionObject
|
||||
import com.anytypeio.anytype.presentation.extension.getTypeObject
|
||||
import com.anytypeio.anytype.presentation.number.NumberParser
|
||||
import com.anytypeio.anytype.presentation.sets.buildFileViews
|
||||
import com.anytypeio.anytype.presentation.objects.buildRelationValueObjectViews
|
||||
|
@ -224,33 +223,6 @@ fun tagRelation(
|
|||
)
|
||||
}
|
||||
|
||||
fun ObjectViewDetails.objectTypeRelation(
|
||||
relationKey: Key,
|
||||
isFeatured: Boolean,
|
||||
objectTypeId: Id
|
||||
): ObjectRelationView {
|
||||
val objectType = getTypeObject(objectTypeId)
|
||||
return if (objectType == null || objectType.isDeleted == true) {
|
||||
ObjectRelationView.ObjectType.Deleted(
|
||||
id = objectTypeId,
|
||||
key = relationKey,
|
||||
featured = isFeatured,
|
||||
readOnly = false,
|
||||
system = relationKey.isSystemKey()
|
||||
)
|
||||
} else {
|
||||
ObjectRelationView.ObjectType.Base(
|
||||
id = objectTypeId,
|
||||
key = relationKey,
|
||||
name = objectType.name.orEmpty(),
|
||||
featured = isFeatured,
|
||||
readOnly = false,
|
||||
type = objectTypeId,
|
||||
system = relationKey.isSystemKey()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun ObjectViewDetails.linksFeaturedRelation(
|
||||
relations: List<ObjectWrapper.Relation>,
|
||||
relationKey: Key,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.anytypeio.anytype.presentation.sets
|
||||
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.CoverType
|
||||
import com.anytypeio.anytype.core_models.DVFilter
|
||||
import com.anytypeio.anytype.core_models.DVFilterCondition
|
||||
|
@ -38,22 +37,13 @@ import com.anytypeio.anytype.domain.misc.DateProvider
|
|||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfRelations
|
||||
import com.anytypeio.anytype.domain.primitives.FieldParser
|
||||
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
|
||||
import com.anytypeio.anytype.core_models.ObjectViewDetails
|
||||
import com.anytypeio.anytype.presentation.extension.getObject
|
||||
import com.anytypeio.anytype.presentation.extension.getTypeObject
|
||||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.anytypeio.anytype.presentation.objects.getProperType
|
||||
import com.anytypeio.anytype.presentation.objects.toObjectViewDefault
|
||||
import com.anytypeio.anytype.presentation.relations.BasicObjectCoverWrapper
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig.ID_KEY
|
||||
import com.anytypeio.anytype.presentation.relations.getCover
|
||||
import com.anytypeio.anytype.presentation.relations.isSystemKey
|
||||
import com.anytypeio.anytype.presentation.relations.linksFeaturedRelation
|
||||
import com.anytypeio.anytype.presentation.relations.title
|
||||
import com.anytypeio.anytype.presentation.relations.view
|
||||
import com.anytypeio.anytype.presentation.sets.model.SimpleRelationView
|
||||
import com.anytypeio.anytype.presentation.sets.model.Viewer
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
|
@ -63,38 +53,6 @@ import com.anytypeio.anytype.presentation.sets.viewer.ViewerView
|
|||
import com.anytypeio.anytype.presentation.templates.TemplateView
|
||||
import timber.log.Timber
|
||||
|
||||
suspend fun ObjectState.DataView.featuredRelations(
|
||||
ctx: Id,
|
||||
urlBuilder: UrlBuilder,
|
||||
relations: List<ObjectWrapper.Relation>,
|
||||
fieldParser: FieldParser,
|
||||
storeOfObjectTypes: StoreOfObjectTypes,
|
||||
): BlockView.FeaturedRelation? {
|
||||
val block = blocks.find { it.content is Block.Content.FeaturedRelations }
|
||||
if (block != null) {
|
||||
val views = mutableListOf<ObjectRelationView>()
|
||||
val currentObject = details.getObject(ctx)
|
||||
val ids = currentObject?.featuredRelations
|
||||
views.addAll(
|
||||
mapFeaturedRelations(
|
||||
ctx = ctx,
|
||||
keys = ids,
|
||||
details = details,
|
||||
relations = relations,
|
||||
urlBuilder = urlBuilder,
|
||||
fieldParser = fieldParser,
|
||||
storeOfObjectTypes = storeOfObjectTypes
|
||||
)
|
||||
)
|
||||
return BlockView.FeaturedRelation(
|
||||
id = block.id,
|
||||
relations = views
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun ObjectState.DataView.header(
|
||||
ctx: Id,
|
||||
urlBuilder: UrlBuilder,
|
||||
|
@ -127,113 +85,6 @@ fun ObjectState.DataView.header(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun ObjectState.DataView.mapFeaturedRelations(
|
||||
ctx: Id,
|
||||
keys: List<String>?,
|
||||
details: ObjectViewDetails,
|
||||
relations: List<ObjectWrapper.Relation>,
|
||||
urlBuilder: UrlBuilder,
|
||||
fieldParser: FieldParser,
|
||||
storeOfObjectTypes: StoreOfObjectTypes,
|
||||
): List<ObjectRelationView> {
|
||||
val currentObject = details.getObject(ctx) ?: return emptyList()
|
||||
val featuredRelationsIds = currentObject.featuredRelations
|
||||
return featuredRelationsIds.mapNotNull { key ->
|
||||
when (key) {
|
||||
Relations.DESCRIPTION -> null
|
||||
Relations.TYPE -> {
|
||||
val currentObjectType = currentObject.getProperType()
|
||||
if (currentObjectType != null) {
|
||||
val wrapper = details.getTypeObject(currentObjectType)
|
||||
if (wrapper != null) {
|
||||
val isDeleted = wrapper.isDeleted == true
|
||||
if (isDeleted) {
|
||||
ObjectRelationView.ObjectType.Deleted(
|
||||
id = wrapper.id,
|
||||
key = key,
|
||||
featured = true,
|
||||
readOnly = false,
|
||||
system = key.isSystemKey()
|
||||
)
|
||||
} else {
|
||||
ObjectRelationView.ObjectType.Base(
|
||||
id = wrapper.id,
|
||||
key = key,
|
||||
name = wrapper.name.orEmpty(),
|
||||
featured = true,
|
||||
readOnly = false,
|
||||
type = wrapper.id,
|
||||
system = key.isSystemKey()
|
||||
)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
Relations.SET_OF -> {
|
||||
|
||||
val source = currentObject.setOf.firstOrNull()
|
||||
|
||||
val wrapper = if (source != null) {
|
||||
details.getObject(source)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val isValid = wrapper?.isValid == true
|
||||
val isDeleted = wrapper?.isDeleted == true
|
||||
val isReadOnly = wrapper?.relationReadonlyValue == true
|
||||
|
||||
val sources = if (isValid && !isDeleted) {
|
||||
listOf(
|
||||
wrapper.toObjectViewDefault(
|
||||
urlBuilder = urlBuilder,
|
||||
fieldParser = fieldParser,
|
||||
storeOfObjectTypes = storeOfObjectTypes
|
||||
)
|
||||
)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
ObjectRelationView.Source(
|
||||
id = currentObject.id,
|
||||
key = key,
|
||||
name = Relations.RELATION_NAME_EMPTY,
|
||||
featured = true,
|
||||
readOnly = isReadOnly,
|
||||
sources = sources,
|
||||
system = key.isSystemKey()
|
||||
)
|
||||
}
|
||||
Relations.BACKLINKS, Relations.LINKS -> {
|
||||
details.linksFeaturedRelation(
|
||||
relations = relations,
|
||||
ctx = ctx,
|
||||
relationKey = key,
|
||||
isFeatured = true
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
val relation = relations.firstOrNull { it.key == key }
|
||||
relation?.view(
|
||||
details = details,
|
||||
values = currentObject.map,
|
||||
urlBuilder = urlBuilder,
|
||||
isFeatured = true,
|
||||
fieldParser = fieldParser,
|
||||
storeOfObjectTypes = storeOfObjectTypes
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.sortedByDescending { it.key == Relations.SET_OF }
|
||||
.sortedByDescending { it.key == Relations.TYPE }
|
||||
}
|
||||
|
||||
fun List<DVRecord>.update(new: List<DVRecord>): List<DVRecord> {
|
||||
val update = new.associateBy { rec -> rec[ID_KEY] as String }
|
||||
val result = mutableListOf<DVRecord>()
|
||||
|
|
|
@ -82,6 +82,7 @@ import com.anytypeio.anytype.presentation.navigation.leftButtonClickAnalytics
|
|||
import com.anytypeio.anytype.presentation.objects.getCreateObjectParams
|
||||
import com.anytypeio.anytype.presentation.objects.isCreateObjectAllowed
|
||||
import com.anytypeio.anytype.presentation.objects.isTemplatesAllowed
|
||||
import com.anytypeio.anytype.presentation.objects.toFeaturedPropertiesViews
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectRelationView
|
||||
import com.anytypeio.anytype.presentation.relations.ObjectSetConfig.DEFAULT_LIMIT
|
||||
import com.anytypeio.anytype.presentation.relations.RelationListViewModel
|
||||
|
@ -244,12 +245,15 @@ class ObjectSetViewModel(
|
|||
state to permission
|
||||
}
|
||||
.collectLatest { (state, permission) ->
|
||||
featured.value = state.featuredRelations(
|
||||
ctx = vmParams.ctx,
|
||||
featured.value = toFeaturedPropertiesViews(
|
||||
objectId = vmParams.ctx,
|
||||
urlBuilder = urlBuilder,
|
||||
relations = storeOfRelations.getAll(),
|
||||
fieldParser = fieldParser,
|
||||
storeOfObjectTypes = storeOfObjectTypes
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
storeOfRelations = storeOfRelations,
|
||||
blocks = state.blocks,
|
||||
details = state.details,
|
||||
participantCanEdit = permission?.isOwnerOrEditor() == true
|
||||
)
|
||||
_header.value = state.header(
|
||||
ctx = vmParams.ctx,
|
||||
|
|
|
@ -154,6 +154,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
),
|
||||
BlockView.FeaturedRelation(
|
||||
id = featuredBlock.id,
|
||||
hasFeaturePropertiesConflict = true,
|
||||
relations = listOf(
|
||||
ObjectRelationView.ObjectType.Base(
|
||||
id = objectTypeId,
|
||||
|
@ -161,7 +162,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
name = objectTypeName,
|
||||
featured = true,
|
||||
type = objectTypeId,
|
||||
system = true
|
||||
system = false
|
||||
),
|
||||
ObjectRelationView.Default(
|
||||
id = r3.id,
|
||||
|
@ -195,7 +196,10 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
val first = test.awaitValue()
|
||||
val second = test.awaitValue()
|
||||
|
||||
second.assertValue(ViewState.Success(expected))
|
||||
assertEquals(
|
||||
expected = ViewState.Success(expected),
|
||||
actual = second.value()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -492,6 +496,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
),
|
||||
BlockView.FeaturedRelation(
|
||||
id = featuredBlock.id,
|
||||
hasFeaturePropertiesConflict = true,
|
||||
relations = listOf(
|
||||
ObjectRelationView.ObjectType.Base(
|
||||
id = objectTypeId,
|
||||
|
@ -499,7 +504,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
name = objectTypeName,
|
||||
featured = true,
|
||||
type = objectTypeId,
|
||||
system = true
|
||||
system = false
|
||||
)
|
||||
)
|
||||
),
|
||||
|
@ -622,6 +627,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
),
|
||||
BlockView.FeaturedRelation(
|
||||
id = featuredBlock.id,
|
||||
hasFeaturePropertiesConflict = true,
|
||||
relations = listOf(
|
||||
ObjectRelationView.ObjectType.Base(
|
||||
id = objectTypeId,
|
||||
|
@ -629,7 +635,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
name = objectTypeName,
|
||||
featured = true,
|
||||
type = objectTypeId,
|
||||
system = true
|
||||
system = false
|
||||
),
|
||||
ObjectRelationView.Default(
|
||||
id = r1.id,
|
||||
|
@ -761,12 +767,13 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
),
|
||||
BlockView.FeaturedRelation(
|
||||
id = featuredBlock.id,
|
||||
hasFeaturePropertiesConflict = true,
|
||||
relations = listOf(
|
||||
ObjectRelationView.ObjectType.Deleted(
|
||||
id = objectTypeId,
|
||||
key = Relations.TYPE,
|
||||
featured = true,
|
||||
system = true
|
||||
system = false
|
||||
),
|
||||
ObjectRelationView.Default(
|
||||
id = r3.id,
|
||||
|
@ -893,12 +900,13 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
),
|
||||
BlockView.FeaturedRelation(
|
||||
id = featuredBlock.id,
|
||||
hasFeaturePropertiesConflict = true,
|
||||
relations = listOf(
|
||||
ObjectRelationView.ObjectType.Deleted(
|
||||
id = objectTypeId,
|
||||
key = Relations.TYPE,
|
||||
featured = true,
|
||||
system = true
|
||||
system = false
|
||||
),
|
||||
ObjectRelationView.Default(
|
||||
id = r3.id,
|
||||
|
@ -1023,6 +1031,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
),
|
||||
BlockView.FeaturedRelation(
|
||||
id = featuredBlock.id,
|
||||
hasFeaturePropertiesConflict = true,
|
||||
relations = listOf(
|
||||
ObjectRelationView.Links.Backlinks(
|
||||
id = backlinksRelation.id,
|
||||
|
@ -1157,7 +1166,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `should use Featured Properties Ids from Object Type when object featured ids are empty `() =
|
||||
fun `should use Featured Properties Ids from Object Type when Type is not the Template`() =
|
||||
runTest {
|
||||
|
||||
val title = MockTypicalDocumentFactory.title
|
||||
|
@ -1244,6 +1253,8 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
),
|
||||
BlockView.FeaturedRelation(
|
||||
id = featuredBlock.id,
|
||||
//no conflict, because object featured properties are empty
|
||||
hasFeaturePropertiesConflict = false,
|
||||
relations = listOf(
|
||||
ObjectRelationView.Default(
|
||||
id = property1.id,
|
||||
|
@ -1288,7 +1299,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `should use Featured Properties Ids from TargetObjectTypeId when object is Template and his FeatureRelations are empty`() =
|
||||
fun `should use Recommended Featured Properties Ids from TargetObjectTypeId when object is Template`() =
|
||||
runTest {
|
||||
|
||||
val title = MockTypicalDocumentFactory.title
|
||||
|
@ -1336,7 +1347,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
id = MockDataFactory.randomString(),
|
||||
uniqueKey = ObjectTypeIds.TEMPLATE,
|
||||
layout = ObjectType.Layout.OBJECT_TYPE.code.toDouble(),
|
||||
recommendedFeaturedRelations = listOf(property1.id, property2.id)
|
||||
recommendedFeaturedRelations = listOf(property2.id)
|
||||
)
|
||||
|
||||
val targetObjectType = StubObjectType(
|
||||
|
@ -1397,6 +1408,7 @@ class EditorFeaturedRelationsTest : EditorPresentationTestSetup() {
|
|||
),
|
||||
BlockView.FeaturedRelation(
|
||||
id = featuredBlock.id,
|
||||
hasFeaturePropertiesConflict = false,
|
||||
relations = listOf(
|
||||
ObjectRelationView.Default(
|
||||
id = property3.id,
|
||||
|
|
|
@ -131,6 +131,8 @@ class EditorNoteLayoutTest : EditorPresentationTestSetup() {
|
|||
val expected = listOf(
|
||||
BlockView.FeaturedRelation(
|
||||
id = featuredBlock.id,
|
||||
hasFeaturePropertiesConflict = true,
|
||||
allowChangingObjectType = false,
|
||||
relations = listOf(
|
||||
ObjectRelationView.Default(
|
||||
id = r1.id,
|
||||
|
@ -231,6 +233,8 @@ class EditorNoteLayoutTest : EditorPresentationTestSetup() {
|
|||
val expected = listOf(
|
||||
BlockView.FeaturedRelation(
|
||||
id = featuredBlock.id,
|
||||
allowChangingObjectType = false,
|
||||
hasFeaturePropertiesConflict = true,
|
||||
relations = listOf(
|
||||
ObjectRelationView.Default(
|
||||
id = r1.id,
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.anytypeio.anytype.core_models.StubWidgetBlock
|
|||
import com.anytypeio.anytype.core_models.UNKNOWN_SPACE_TYPE
|
||||
import com.anytypeio.anytype.core_models.WidgetSession
|
||||
import com.anytypeio.anytype.core_models.multiplayer.SpaceMemberPermissions
|
||||
import com.anytypeio.anytype.core_models.primitives.Space
|
||||
import com.anytypeio.anytype.core_models.primitives.SpaceId
|
||||
import com.anytypeio.anytype.core_models.primitives.TypeId
|
||||
import com.anytypeio.anytype.core_models.primitives.TypeKey
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
package com.anytypeio.anytype.presentation.sets
|
||||
|
||||
import com.anytypeio.anytype.core_models.ObjectType
|
||||
import com.anytypeio.anytype.core_models.ObjectTypeIds
|
||||
import com.anytypeio.anytype.core_models.ObjectViewDetails
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_models.Relations
|
||||
import com.anytypeio.anytype.core_models.StubFeatured
|
||||
import com.anytypeio.anytype.core_models.StubObject
|
||||
import com.anytypeio.anytype.core_models.StubObjectType
|
||||
import com.anytypeio.anytype.core_models.StubRelationObject
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.debugging.Logger
|
||||
import com.anytypeio.anytype.domain.misc.DateProvider
|
||||
import com.anytypeio.anytype.domain.misc.UrlBuilder
|
||||
import com.anytypeio.anytype.domain.objects.DefaultStoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.DefaultStoreOfRelations
|
||||
import com.anytypeio.anytype.domain.objects.GetDateObjectByTimestamp
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
|
||||
import com.anytypeio.anytype.domain.objects.StoreOfRelations
|
||||
import com.anytypeio.anytype.domain.primitives.FieldParser
|
||||
import com.anytypeio.anytype.domain.primitives.FieldParserImpl
|
||||
import com.anytypeio.anytype.domain.resources.StringResourceProvider
|
||||
import com.anytypeio.anytype.presentation.objects.ConflictResolutionStrategy
|
||||
import com.anytypeio.anytype.presentation.objects.toFeaturedPropertiesViews
|
||||
import com.anytypeio.anytype.presentation.sets.state.ObjectState
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.TestCoroutineScheduler
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.test.setMain
|
||||
import org.junit.Before
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.stub
|
||||
|
||||
class SetObjectFeaturedPropertiesTest {
|
||||
|
||||
@Mock
|
||||
lateinit var urlBuilder: UrlBuilder
|
||||
|
||||
lateinit var fieldParser: FieldParser
|
||||
|
||||
@Mock
|
||||
lateinit var dateProvider: DateProvider
|
||||
|
||||
@Mock
|
||||
lateinit var getDateObjectByTimestamp: GetDateObjectByTimestamp
|
||||
|
||||
@Mock
|
||||
lateinit var stringResourceProvider: StringResourceProvider
|
||||
|
||||
@Mock
|
||||
lateinit var logger: Logger
|
||||
|
||||
private val dispatcher = StandardTestDispatcher(TestCoroutineScheduler())
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val dispatchers = AppCoroutineDispatchers(
|
||||
io = dispatcher,
|
||||
main = dispatcher,
|
||||
computation = dispatcher
|
||||
).also { Dispatchers.setMain(dispatcher) }
|
||||
|
||||
private val storeOfRelations: StoreOfRelations = DefaultStoreOfRelations()
|
||||
private val storeOfObjectTypes: StoreOfObjectTypes = DefaultStoreOfObjectTypes()
|
||||
|
||||
@Before
|
||||
fun before() {
|
||||
MockitoAnnotations.openMocks(this)
|
||||
fieldParser = FieldParserImpl(dateProvider, logger, getDateObjectByTimestamp, stringResourceProvider)
|
||||
urlBuilder.stub {
|
||||
on { large(any()) } doReturn "any/url"
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `case when without conflict`() = runTest {
|
||||
|
||||
val propertyObjectType = StubRelationObject(
|
||||
id = "propertyObjectType_id",
|
||||
name = "Object type",
|
||||
)
|
||||
val propertyTag = StubRelationObject(
|
||||
id = "propertyTag_id",
|
||||
name = "Tag",
|
||||
)
|
||||
val propertyBacklinks = StubRelationObject(
|
||||
id = "propertyBacklinks_id",
|
||||
name = "Backlinks",
|
||||
)
|
||||
val propertyDescription = StubRelationObject(
|
||||
id = "propertyDescription_id",
|
||||
name = "Description",
|
||||
key = Relations.DESCRIPTION
|
||||
)
|
||||
|
||||
storeOfRelations.merge(
|
||||
relations = listOf(
|
||||
propertyObjectType,
|
||||
propertyTag,
|
||||
propertyBacklinks,
|
||||
propertyDescription
|
||||
)
|
||||
)
|
||||
|
||||
val objType = StubObjectType(
|
||||
name = "Query",
|
||||
uniqueKey = ObjectTypeIds.SET,
|
||||
recommendedLayout = ObjectType.Layout.SET.code.toDouble(),
|
||||
recommendedFeaturedRelations = listOf(
|
||||
propertyObjectType.id,
|
||||
propertyTag.id,
|
||||
propertyBacklinks.id,
|
||||
propertyDescription.id
|
||||
)
|
||||
)
|
||||
|
||||
storeOfObjectTypes.merge(
|
||||
types = listOf(objType)
|
||||
)
|
||||
|
||||
val objectSet = StubObject(
|
||||
id = "id",
|
||||
name = "Pages",
|
||||
description = "This the description of Pages Set",
|
||||
objectType = objType.id,
|
||||
extraFields = mapOf(
|
||||
Relations.FEATURED_RELATIONS to propertyDescription.key
|
||||
)
|
||||
)
|
||||
|
||||
val featuredBlock = StubFeatured()
|
||||
|
||||
val objectState = ObjectState.DataView.Set(
|
||||
root = objectSet.id,
|
||||
blocks = listOf(featuredBlock),
|
||||
details = ObjectViewDetails(
|
||||
details = mapOf(
|
||||
objectSet.id to objectSet.map,
|
||||
objType.id to objType.map,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val featuredPropertiesBlock = toFeaturedPropertiesViews(
|
||||
objectId = objectSet.id,
|
||||
storeOfRelations = storeOfRelations,
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
urlBuilder = urlBuilder,
|
||||
fieldParser = fieldParser,
|
||||
details = objectState.details,
|
||||
blocks = objectState.blocks,
|
||||
participantCanEdit = true
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expected = listOf(propertyObjectType.key, propertyTag.key, propertyBacklinks.key),
|
||||
actual = featuredPropertiesBlock!!.relations.map { it.key })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `case when with conflict, using default Strategy - OBJECT_ONLY`() = runTest {
|
||||
|
||||
val propertyObjectType = StubRelationObject(
|
||||
id = "propertyObjectType_id",
|
||||
name = "Object type",
|
||||
key = Relations.TYPE
|
||||
)
|
||||
val propertyTag = StubRelationObject(
|
||||
id = "propertyTag_id",
|
||||
name = "Tag",
|
||||
key = "key-tag"
|
||||
)
|
||||
val propertyBacklinks = StubRelationObject(
|
||||
id = "propertyBacklinks_id",
|
||||
name = "Backlinks",
|
||||
key = "key-backlinks"
|
||||
)
|
||||
val propertyDescription = StubRelationObject(
|
||||
id = "propertyDescription_id",
|
||||
name = "Description",
|
||||
key = Relations.DESCRIPTION
|
||||
)
|
||||
|
||||
val propertyAuthor = StubRelationObject(
|
||||
id = "propertyAuthor_id",
|
||||
name = "Author",
|
||||
key = "key-author"
|
||||
)
|
||||
|
||||
storeOfRelations.merge(
|
||||
relations = listOf(
|
||||
propertyObjectType,
|
||||
propertyTag,
|
||||
propertyBacklinks,
|
||||
propertyDescription,
|
||||
propertyAuthor
|
||||
)
|
||||
)
|
||||
|
||||
val objType = StubObjectType(
|
||||
name = "Query",
|
||||
uniqueKey = ObjectTypeIds.SET,
|
||||
recommendedLayout = ObjectType.Layout.SET.code.toDouble(),
|
||||
recommendedFeaturedRelations = listOf(
|
||||
propertyObjectType.id,
|
||||
propertyTag.id,
|
||||
propertyBacklinks.id,
|
||||
propertyDescription.id
|
||||
)
|
||||
)
|
||||
|
||||
storeOfObjectTypes.merge(
|
||||
types = listOf(objType)
|
||||
)
|
||||
|
||||
val objectSet = StubObject(
|
||||
id = "id",
|
||||
name = "Pages",
|
||||
description = "This the description of Pages Set",
|
||||
objectType = objType.id,
|
||||
extraFields = mapOf(
|
||||
Relations.FEATURED_RELATIONS to listOf(
|
||||
propertyBacklinks.key,
|
||||
propertyAuthor.key,
|
||||
propertyDescription.key
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val featuredBlock = StubFeatured()
|
||||
|
||||
val objectState = ObjectState.DataView.Set(
|
||||
root = objectSet.id,
|
||||
blocks = listOf(featuredBlock),
|
||||
details = ObjectViewDetails(
|
||||
details = mapOf(
|
||||
objectSet.id to objectSet.map,
|
||||
objType.id to objType.map,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val featuredPropertiesBlock = toFeaturedPropertiesViews(
|
||||
objectId = objectSet.id,
|
||||
storeOfRelations = storeOfRelations,
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
urlBuilder = urlBuilder,
|
||||
fieldParser = fieldParser,
|
||||
details = objectState.details,
|
||||
blocks = objectState.blocks,
|
||||
participantCanEdit = true
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expected = listOf(
|
||||
propertyBacklinks.key,
|
||||
propertyAuthor.key
|
||||
),
|
||||
actual = featuredPropertiesBlock!!.relations.map { it.key })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `case when with conflict, using Strategy - MERGE`() = runTest {
|
||||
|
||||
val propertyObjectType = StubRelationObject(
|
||||
id = "propertyObjectType_id",
|
||||
name = "Object type",
|
||||
key = Relations.TYPE
|
||||
)
|
||||
val propertyTag = StubRelationObject(
|
||||
id = "propertyTag_id",
|
||||
name = "Tag",
|
||||
key = "key-tag"
|
||||
)
|
||||
val propertyBacklinks = StubRelationObject(
|
||||
id = "propertyBacklinks_id",
|
||||
name = "Backlinks",
|
||||
key = "key-backlinks"
|
||||
)
|
||||
val propertyDescription = StubRelationObject(
|
||||
id = "propertyDescription_id",
|
||||
name = "Description",
|
||||
key = Relations.DESCRIPTION
|
||||
)
|
||||
|
||||
val propertyAuthor = StubRelationObject(
|
||||
id = "propertyAuthor_id",
|
||||
name = "Author",
|
||||
key = "key-author"
|
||||
)
|
||||
|
||||
storeOfRelations.merge(
|
||||
relations = listOf(
|
||||
propertyObjectType,
|
||||
propertyTag,
|
||||
propertyBacklinks,
|
||||
propertyDescription,
|
||||
propertyAuthor
|
||||
)
|
||||
)
|
||||
|
||||
val objType = StubObjectType(
|
||||
name = "Query",
|
||||
uniqueKey = ObjectTypeIds.SET,
|
||||
recommendedLayout = ObjectType.Layout.SET.code.toDouble(),
|
||||
recommendedFeaturedRelations = listOf(
|
||||
propertyObjectType.id,
|
||||
propertyTag.id,
|
||||
propertyBacklinks.id,
|
||||
propertyDescription.id
|
||||
)
|
||||
)
|
||||
|
||||
storeOfObjectTypes.merge(
|
||||
types = listOf(objType)
|
||||
)
|
||||
|
||||
val objectSet = StubObject(
|
||||
id = "id",
|
||||
name = "Pages",
|
||||
description = "This the description of Pages Set",
|
||||
objectType = objType.id,
|
||||
extraFields = mapOf(
|
||||
Relations.FEATURED_RELATIONS to listOf(
|
||||
propertyBacklinks.key,
|
||||
propertyAuthor.key,
|
||||
propertyDescription.key
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val featuredBlock = StubFeatured()
|
||||
|
||||
val objectState = ObjectState.DataView.Set(
|
||||
root = objectSet.id,
|
||||
blocks = listOf(featuredBlock),
|
||||
details = ObjectViewDetails(
|
||||
details = mapOf(
|
||||
objectSet.id to objectSet.map,
|
||||
objType.id to objType.map,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val featuredPropertiesBlock = toFeaturedPropertiesViews(
|
||||
objectId = objectSet.id,
|
||||
storeOfRelations = storeOfRelations,
|
||||
storeOfObjectTypes = storeOfObjectTypes,
|
||||
urlBuilder = urlBuilder,
|
||||
fieldParser = fieldParser,
|
||||
details = objectState.details,
|
||||
blocks = objectState.blocks,
|
||||
participantCanEdit = true,
|
||||
conflictResolutionStrategy = ConflictResolutionStrategy.MERGE
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
expected = listOf(
|
||||
propertyObjectType.key,
|
||||
propertyTag.key,
|
||||
propertyBacklinks.key,
|
||||
propertyAuthor.key
|
||||
),
|
||||
actual = featuredPropertiesBlock!!.relations.map { it.key })
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue