Skip to content

Commit

Permalink
Merge pull request #1511 from anyproto/go-3942-add-layouts
Browse files Browse the repository at this point in the history
GO-3942: add layouts for tag as an object
  • Loading branch information
AnastasiaShemyakinskaya authored Oct 10, 2024
2 parents 7ff714f + dde96f5 commit 84a4190
Show file tree
Hide file tree
Showing 18 changed files with 786 additions and 611 deletions.
13 changes: 13 additions & 0 deletions core/block/editor/converter/layout.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ func (c *layoutConverter) Convert(space smartblock.Space, st *state.State, fromL

// TODO We need more granular cases (not catch-all)

if toLayout == model.ObjectType_tag {
return c.fromAnyToTag(st)
}

return c.fromAnyToAny(st)
}

Expand Down Expand Up @@ -322,3 +326,12 @@ func (c *layoutConverter) appendTypesFilter(types []string, filters []*model.Blo
}
return filters
}

func (c *layoutConverter) fromAnyToTag(st *state.State) error {
template.InitTemplate(st,
template.WithTitle,
template.WithNoDescription,
template.WithRelations([]domain.RelationKey{bundle.RelationKeyRelationOptionColor}),
)
return nil
}
5 changes: 5 additions & 0 deletions core/block/editor/page.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ func (p *Page) CreationStateMigration(ctx *smartblock.InitContext) migration.Mig
template.WithAddedFeaturedRelation(bundle.RelationKeyType),
)
// TODO case for relationOption?
case model.ObjectType_tag:
templates = append(templates,
template.WithTitle,
template.WithNoDescription,
template.WithRelations([]domain.RelationKey{bundle.RelationKeyRelationOptionColor}))
default:
templates = append(templates,
template.WithTitle,
Expand Down
2 changes: 1 addition & 1 deletion core/block/import/common/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (r *ImportCollection) addRelations(st *state.State) error {
for _, relation := range []*model.RelationLink{
{
Key: bundle.RelationKeyTag.String(),
Format: model.RelationFormat_tag,
Format: model.RelationFormat_object,
},
{
Key: bundle.RelationKeyCreatedDate.String(),
Expand Down
124 changes: 79 additions & 45 deletions core/block/import/pb/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,70 +315,104 @@ func (p *Pb) normalizeSnapshot(snapshot *pb.SnapshotWithType,
id, profileID, path string,
isMigration bool,
pbFiles source.Source) (string, error) {
p.normalizeRelationLinks(snapshot)
if snapshot.SbType == model.SmartBlockType_STRelationOption {
p.normalizeRelationOption(snapshot)
}
if _, ok := model.SmartBlockType_name[int32(snapshot.SbType)]; !ok {
newSbType := model.SmartBlockType_Page
if int32(snapshot.SbType) == 96 { // fallback for objectType smartblocktype
newSbType = model.SmartBlockType_SubObject
}
snapshot.SbType = newSbType
p.normalizeNormalizeOldType(snapshot)
}

if snapshot.SbType == model.SmartBlockType_SubObject {
details := snapshot.Snapshot.Data.Details
originalId := pbtypes.GetString(snapshot.Snapshot.Data.Details, bundle.RelationKeyId.String())
var sourceObjectId string
// migrate old sub objects into real objects
if snapshot.Snapshot.Data.ObjectTypes[0] == bundle.TypeKeyObjectType.URL() {
snapshot.SbType = model.SmartBlockType_STType
typeKey, err := bundle.TypeKeyFromUrl(originalId)
if err == nil {
sourceObjectId = typeKey.BundledURL()
}
} else if snapshot.Snapshot.Data.ObjectTypes[0] == bundle.TypeKeyRelation.URL() {
snapshot.SbType = model.SmartBlockType_STRelation
relationKey, err := bundle.RelationKeyFromID(originalId)
if err == nil {
sourceObjectId = relationKey.BundledURL()
}
} else if snapshot.Snapshot.Data.ObjectTypes[0] == bundle.TypeKeyRelationOption.URL() {
snapshot.SbType = model.SmartBlockType_STRelationOption
} else {
return "", fmt.Errorf("unknown sub object type %s", snapshot.Snapshot.Data.ObjectTypes[0])
}
if sourceObjectId != "" {
if pbtypes.GetString(details, bundle.RelationKeySourceObject.String()) == "" {
details.Fields[bundle.RelationKeySourceObject.String()] = pbtypes.String(sourceObjectId)
}
}
id = originalId
return p.normalizeSubObject(snapshot, id)
}

if snapshot.SbType == model.SmartBlockType_ProfilePage {
var err error
id, err = p.getIDForUserProfile(snapshot, profileID, id, isMigration)
if err != nil {
return "", fmt.Errorf("get user profile id: %w", err)
}
p.setProfileIconOption(snapshot, profileID)
return p.normalizeProfile(snapshot, id, profileID, isMigration)
}
if snapshot.SbType == model.SmartBlockType_Page {
p.cleanupEmptyBlock(snapshot)
}
if snapshot.SbType == model.SmartBlockType_File {
if snapshot.SbType == model.SmartBlockType_File || snapshot.SbType == model.SmartBlockType_FileObject {
err := p.normalizeFilePath(snapshot, pbFiles, path)
if err != nil {
return "", fmt.Errorf("failed to update file path in file snapshot %w", err)
}
}
if snapshot.SbType == model.SmartBlockType_FileObject {
err := p.normalizeFilePath(snapshot, pbFiles, path)
if err != nil {
return "", fmt.Errorf("failed to update file path in file snapshot %w", err)
return id, nil
}

func (p *Pb) normalizeRelationLinks(snapshot *pb.SnapshotWithType) {
for _, link := range snapshot.Snapshot.Data.RelationLinks {
if link.Key == bundle.RelationKeyTag.String() {
link.Format = model.RelationFormat_object
break
}
}
}

func (p *Pb) normalizeRelationOption(snapshot *pb.SnapshotWithType) {
key := pbtypes.GetString(snapshot.Snapshot.Data.Details, bundle.RelationKeyRelationKey.String())
if key != bundle.RelationKeyTag.String() {
return
}
snapshot.SbType = model.SmartBlockType_Page
snapshot.Snapshot.Data.Key = ""
snapshot.Snapshot.Data.ObjectTypes = []string{bundle.TypeKeyTag.URL()}
if snapshot.Snapshot.Data.Details == nil || snapshot.Snapshot.Data.Details.Fields == nil {
snapshot.Snapshot.Data.Details.Fields = map[string]*types.Value{}
}
snapshot.Snapshot.Data.Details.Fields[bundle.RelationKeyLayout.String()] = pbtypes.Int64(int64(model.ObjectType_tag))
delete(snapshot.Snapshot.Data.Details.Fields, bundle.RelationKeyRelationKey.String())
delete(snapshot.Snapshot.Data.Details.Fields, bundle.RelationKeyUniqueKey.String())
}

func (p *Pb) normalizeProfile(snapshot *pb.SnapshotWithType, id string, profileID string, isMigration bool) (string, error) {
id, err := p.getIDForUserProfile(snapshot, profileID, id, isMigration)
if err != nil {
return "", fmt.Errorf("get user profile id: %w", err)
}
p.setProfileIconOption(snapshot, profileID)
return id, nil
}

func (p *Pb) normalizeSubObject(snapshot *pb.SnapshotWithType, id string) (string, error) {
details := snapshot.Snapshot.Data.Details
originalId := pbtypes.GetString(snapshot.Snapshot.Data.Details, bundle.RelationKeyId.String())
var sourceObjectId string
// migrate old sub objects into real objects
if snapshot.Snapshot.Data.ObjectTypes[0] == bundle.TypeKeyObjectType.URL() {
snapshot.SbType = model.SmartBlockType_STType
typeKey, err := bundle.TypeKeyFromUrl(originalId)
if err == nil {
sourceObjectId = typeKey.BundledURL()
}
} else if snapshot.Snapshot.Data.ObjectTypes[0] == bundle.TypeKeyRelation.URL() {
snapshot.SbType = model.SmartBlockType_STRelation
relationKey, err := bundle.RelationKeyFromID(originalId)
if err == nil {
sourceObjectId = relationKey.BundledURL()
}
} else if snapshot.Snapshot.Data.ObjectTypes[0] == bundle.TypeKeyRelationOption.URL() {
snapshot.SbType = model.SmartBlockType_STRelationOption
} else {
return "", fmt.Errorf("unknown sub object type %s", snapshot.Snapshot.Data.ObjectTypes[0])
}
if sourceObjectId != "" {
if pbtypes.GetString(details, bundle.RelationKeySourceObject.String()) == "" {
details.Fields[bundle.RelationKeySourceObject.String()] = pbtypes.String(sourceObjectId)
}
}
id = originalId
return id, nil
}

func (p *Pb) normalizeNormalizeOldType(snapshot *pb.SnapshotWithType) {
newSbType := model.SmartBlockType_Page
if int32(snapshot.SbType) == 96 { // fallback for objectType smartblocktype
newSbType = model.SmartBlockType_SubObject
}
snapshot.SbType = newSbType
}

func (p *Pb) normalizeFilePath(snapshot *pb.SnapshotWithType, pbFiles source.Source, path string) error {
filePath := pbtypes.GetString(snapshot.Snapshot.Data.Details, bundle.RelationKeySource.String())
fileName, _, err := common.ProvideFileName(filePath, pbFiles, path, p.tempDirProvider)
Expand Down
74 changes: 74 additions & 0 deletions core/block/import/pb/converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,18 @@ import (
"sync"
"testing"

"github.com/globalsign/mgo/bson"
"github.com/gogo/protobuf/types"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"

"github.com/anyproto/anytype-heart/core/block/process"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
)

func Test_GetSnapshotsSuccess(t *testing.T) {
Expand Down Expand Up @@ -187,6 +194,73 @@ func Test_GetSnapshotsSkipFileWithoutExtension(t *testing.T) {
assert.Contains(t, res.Snapshots[1].FileName, rootCollectionName)
}

func Test_normalizeSnapshot(t *testing.T) {
t.Run("normalize relation option", func(t *testing.T) {
// given
p := &Pb{}

key := bson.NewObjectId().Hex()
uniqueKey, err := domain.NewUniqueKey(smartblock.SmartBlockTypeRelationOption, key)
assert.NoError(t, err)

snapshot := &pb.SnapshotWithType{
SbType: model.SmartBlockType_STRelationOption,
Snapshot: &pb.ChangeSnapshot{
Data: &model.SmartBlockSnapshotBase{
Details: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyUniqueKey.String(): pbtypes.String(uniqueKey.Marshal()),
bundle.RelationKeyRelationKey.String(): pbtypes.String(bundle.RelationKeyTag.String()),
}},
ObjectTypes: []string{bundle.TypeKeyRelationOption.URL()},
Key: "key",
},
},
}
// when
_, err = p.normalizeSnapshot(snapshot, uuid.New().String(), "", "path", false, nil)

// then
assert.NoError(t, err)
assert.Equal(t, model.SmartBlockType_Page, snapshot.SbType)
assert.Empty(t, snapshot.Snapshot.Data.Details.Fields[bundle.RelationKeyUniqueKey.String()])
assert.Empty(t, snapshot.Snapshot.Data.Details.Fields[bundle.RelationKeyRelationKey.String()])
assert.Equal(t, []string{bundle.TypeKeyTag.URL()}, snapshot.Snapshot.Data.ObjectTypes)
assert.Empty(t, snapshot.Snapshot.Data.Key)
})
t.Run("normalize relation option, but it's not tag relation option", func(t *testing.T) {
// given
p := &Pb{}

key := bson.NewObjectId().Hex()
uniqueKey, err := domain.NewUniqueKey(smartblock.SmartBlockTypeRelationOption, key)
assert.NoError(t, err)

snapshot := &pb.SnapshotWithType{
SbType: model.SmartBlockType_STRelationOption,
Snapshot: &pb.ChangeSnapshot{
Data: &model.SmartBlockSnapshotBase{
Details: &types.Struct{Fields: map[string]*types.Value{
bundle.RelationKeyUniqueKey.String(): pbtypes.String(uniqueKey.Marshal()),
bundle.RelationKeyRelationKey.String(): pbtypes.String("test"),
}},
ObjectTypes: []string{bundle.TypeKeyRelationOption.URL()},
Key: "key",
},
},
}
// when
_, err = p.normalizeSnapshot(snapshot, uuid.New().String(), "", "path", false, nil)

// then
assert.NoError(t, err)
assert.Equal(t, model.SmartBlockType_STRelationOption, snapshot.SbType)
assert.Equal(t, pbtypes.String(uniqueKey.Marshal()), snapshot.Snapshot.Data.Details.Fields[bundle.RelationKeyUniqueKey.String()])
assert.Equal(t, pbtypes.String("test"), snapshot.Snapshot.Data.Details.Fields[bundle.RelationKeyRelationKey.String()])
assert.Equal(t, []string{bundle.TypeKeyRelationOption.URL()}, snapshot.Snapshot.Data.ObjectTypes)
assert.Equal(t, "key", snapshot.Snapshot.Data.Key)
})
}

func newZipWriter(path string) (*zipWriter, error) {
filename := filepath.Join(path, "Anytype"+strconv.FormatInt(rand.Int63(), 10)+".zip")
f, err := os.Create(filename)
Expand Down
37 changes: 17 additions & 20 deletions core/kanban/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import (
"github.com/anyproto/any-sync/app"
"github.com/globalsign/mgo/bson"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
sb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/database"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
Expand All @@ -30,40 +33,34 @@ func Test_GrouperTags(t *testing.T) {

objectStore := objectstore.NewStoreFixture(t)

key := "key"
uniqueKey, err := domain.NewUniqueKey(sb.SmartBlockTypeRelation, key)
assert.NoError(t, err)

objectStore.AddObjects(t, []objectstore.TestObject{
{
bundle.RelationKeyId: pbtypes.String("tag1"),
bundle.RelationKeyUniqueKey: pbtypes.String("rel-tag"),
bundle.RelationKeyId: pbtypes.String("relationId"),
bundle.RelationKeyUniqueKey: pbtypes.String(uniqueKey.Marshal()),
bundle.RelationKeyRelationFormat: pbtypes.Int64(int64(model.RelationFormat_tag)),
bundle.RelationKeySpaceId: pbtypes.String(""),
},
})

kanbanSrv := New()
err := a.Register(objectStore).
err = a.Register(objectStore).
Register(kanbanSrv).
Register(tp).
Start(context.Background())
require.NoError(t, err)

require.NoError(t, objectStore.UpdateObjectDetails(context.Background(), "rel-tag", &types.Struct{
Fields: map[string]*types.Value{
"id": pbtypes.String("rel-tag"),
"relationKey": pbtypes.String("tag"),
"relationFormat": pbtypes.Int64(int64(model.RelationFormat_tag)),
"type": pbtypes.String(bundle.TypeKeyRelation.URL()),
"layout": pbtypes.Int64(int64(model.ObjectType_relation)),
},
}))

idTag1 := bson.NewObjectId().Hex()
idTag2 := bson.NewObjectId().Hex()
idTag3 := bson.NewObjectId().Hex()

require.NoError(t, objectStore.UpdateObjectDetails(context.Background(), idTag1, &types.Struct{
Fields: map[string]*types.Value{
"id": pbtypes.String(idTag1),
"relationKey": pbtypes.String("tag"),
"relationKey": pbtypes.String(key),
"type": pbtypes.String(bundle.TypeKeyRelationOption.URL()),
"layout": pbtypes.Int64(int64(model.ObjectType_relationOption)),
},
Expand All @@ -72,15 +69,15 @@ func Test_GrouperTags(t *testing.T) {
require.NoError(t, objectStore.UpdateObjectDetails(context.Background(), idTag2, &types.Struct{
Fields: map[string]*types.Value{
"id": pbtypes.String(idTag2),
"relationKey": pbtypes.String("tag"),
"relationKey": pbtypes.String(key),
"type": pbtypes.String(bundle.TypeKeyRelationOption.URL()),
"layout": pbtypes.Int64(int64(model.ObjectType_relationOption)),
},
}))
require.NoError(t, objectStore.UpdateObjectDetails(context.Background(), idTag3, &types.Struct{
Fields: map[string]*types.Value{
"id": pbtypes.String(idTag3),
"relationKey": pbtypes.String("tag"),
"relationKey": pbtypes.String(key),
"type": pbtypes.String(bundle.TypeKeyRelationOption.URL()),
"layout": pbtypes.Int64(int64(model.ObjectType_relationOption)),
},
Expand All @@ -97,20 +94,20 @@ func Test_GrouperTags(t *testing.T) {

require.NoError(t, objectStore.UpdateObjectDetails(context.Background(), id2, &types.Struct{Fields: map[string]*types.Value{
"name": pbtypes.String("two"),
"tag": pbtypes.StringList([]string{idTag1}),
key: pbtypes.StringList([]string{idTag1}),
}}))

require.NoError(t, objectStore.UpdateObjectDetails(context.Background(), id3, &types.Struct{Fields: map[string]*types.Value{
"name": pbtypes.String("three"),
"tag": pbtypes.StringList([]string{idTag1, idTag2, idTag3}),
key: pbtypes.StringList([]string{idTag1, idTag2, idTag3}),
}}))

require.NoError(t, objectStore.UpdateObjectDetails(context.Background(), id4, &types.Struct{Fields: map[string]*types.Value{
"name": pbtypes.String("four"),
"tag": pbtypes.StringList([]string{idTag1, idTag3}),
key: pbtypes.StringList([]string{idTag1, idTag3}),
}}))

grouper, err := kanbanSrv.Grouper("", "tag")
grouper, err := kanbanSrv.Grouper("", key)
require.NoError(t, err)
err = grouper.InitGroups("", nil)
require.NoError(t, err)
Expand Down
Loading

0 comments on commit 84a4190

Please sign in to comment.