1
0
Fork 0
mirror of https://github.com/anyproto/anytype-heart.git synced 2025-06-08 05:47:07 +09:00

GO-4459 Merge branch 'main' of ssh://github.com/anyproto/anytype-heart into GO-4459-rest-api-docs

This commit is contained in:
Roman Khafizianov 2025-03-31 16:18:39 +02:00
commit 09c22d2262
No known key found for this signature in database
GPG key ID: F07A7D55A2684852
37 changed files with 1876 additions and 1117 deletions

View file

@ -267,12 +267,15 @@ func (s *service) createFavoriteWidget(spc clientspace.Space) error {
if err != nil {
return fmt.Errorf("get widget details: %w", err)
}
if widgetDetails.GetBool(bundle.RelationKeyAutoWidgetDisabled) {
return nil
}
targetIds := widgetDetails.GetStringList(bundle.RelationKeyAutoWidgetTargets)
if slices.Contains(targetIds, widget.DefaultWidgetFavorite) {
return nil
}
return cache.DoState(s.objectGetter, widgetObjectId, func(st *state.State, w widget.Widget) (err error) {
return w.AddAutoWidget(st, widget.DefaultWidgetFavorite, widget.DefaultWidgetFavorite, "", model.BlockContentWidget_CompactList)
return w.AddAutoWidget(st, widget.DefaultWidgetFavorite, widget.DefaultWidgetFavorite, "", model.BlockContentWidget_CompactList, widget.DefaultWidgetFavoriteEventName)
})
}

View file

@ -90,6 +90,9 @@ func (p *Archive) autoInstallBinWidget() error {
if err != nil {
return err
}
if widgetDetails.GetBool(bundle.RelationKeyAutoWidgetDisabled) {
return nil
}
keys := widgetDetails.Get(bundle.RelationKeyAutoWidgetTargets).StringList()
if slices.Contains(keys, widget.DefaultWidgetBin) {
// cache to avoid unnecessary objectstore requests
@ -100,7 +103,7 @@ func (p *Archive) autoInstallBinWidget() error {
st := sb.NewState()
if w, ok := sb.(widget.Widget); ok {
// We rely on AddAutoWidget to check if the widget was already installed/removed before
err = w.AddAutoWidget(st, widget.DefaultWidgetBin, widget.DefaultWidgetBin, "", model.BlockContentWidget_Link)
err = w.AddAutoWidget(st, widget.DefaultWidgetBin, widget.DefaultWidgetBin, "", model.BlockContentWidget_Link, widget.DefaultWidgetBinEventName)
if err != nil {
return err
}

View file

@ -14,6 +14,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/session"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
@ -56,6 +57,7 @@ func (w *WidgetObject) CreationStateMigration(ctx *smartblock.InitContext) migra
return migration.Migration{
Version: 2,
Proc: func(st *state.State) {
// we purposefully do not add the ALl Objects widget here(as in migration3), because for new users we don't want to auto-create it
template.InitTemplate(st,
template.WithEmpty,
template.WithObjectTypes([]domain.TypeKey{bundle.TypeKeyDashboard}),
@ -112,6 +114,28 @@ func (w *WidgetObject) StateMigrations() migration.Migrations {
},
},
{
Version: 3,
Proc: func(s *state.State) {
// add All Objects widget for existing spaces
_, err := w.CreateBlock(s, &pb.RpcBlockCreateWidgetRequest{
ContextId: s.RootId(),
WidgetLayout: model.BlockContentWidget_Link,
Position: model.Block_InnerFirst,
TargetId: s.RootId(),
ViewId: "",
Block: &model.Block{
Id: "allObjects",
Content: &model.BlockContentOfLink{Link: &model.BlockContentLink{
TargetBlockId: widget.DefaultWidgetAll,
}},
},
})
if err != nil {
log.Warnf("all objects migration failed: %s", err.Error())
}
},
},
},
)
}

View file

@ -8,6 +8,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/event"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
@ -19,15 +20,20 @@ const (
DefaultWidgetRecent = "recent"
DefaultWidgetCollection = "collection"
DefaultWidgetBin = "bin"
DefaultWidgetAll = "allObjects"
DefaultWidgetRecentOpen = "recentOpen"
autoWidgetBlockIdPrefix = "auto_" // in case blockId is specifically provided to avoid bad tree merges
autoWidgetBlockSuffix = "-wrapper" // in case blockId is specifically provided to avoid bad tree merges
DefaultWidgetFavoriteEventName = "Favorite"
DefaultWidgetBinEventName = "Bin"
)
type Widget interface {
CreateBlock(s *state.State, req *pb.RpcBlockCreateWidgetRequest) (string, error)
// AddAutoWidget adds a widget block. If widget with the same targetId was installed/removed before, it will not be added again.
// blockId is optional and used to protect from multi-device conflicts.
AddAutoWidget(s *state.State, targetId, blockId, viewId string, layout model.BlockContentWidgetLayout) error
// if eventName is empty no event is produced
AddAutoWidget(s *state.State, targetId, blockId, viewId string, layout model.BlockContentWidgetLayout, eventName string) error
}
type widget struct {
@ -71,7 +77,11 @@ func NewWidget(sb smartblock.SmartBlock) Widget {
}
}
func (w *widget) AddAutoWidget(st *state.State, targetId, widgetBlockId, viewId string, layout model.BlockContentWidgetLayout) error {
func (w *widget) AddAutoWidget(st *state.State, targetId, widgetBlockId, viewId string, layout model.BlockContentWidgetLayout, eventName string) error {
isDisabled := st.Details().Get(bundle.RelationKeyAutoWidgetDisabled).Bool()
if isDisabled {
return nil
}
targets := st.Details().Get(bundle.RelationKeyAutoWidgetTargets).StringList()
if slices.Contains(targets, targetId) {
return nil
@ -125,7 +135,7 @@ func (w *widget) AddAutoWidget(st *state.State, targetId, widgetBlockId, viewId
position = model.Block_Bottom
}
_, err = w.CreateBlock(st, &pb.RpcBlockCreateWidgetRequest{
_, err = w.createBlock(st, &pb.RpcBlockCreateWidgetRequest{
ContextId: st.RootId(),
ObjectLimit: 6,
WidgetLayout: layout,
@ -138,11 +148,30 @@ func (w *widget) AddAutoWidget(st *state.State, targetId, widgetBlockId, viewId
TargetBlockId: targetId,
}},
},
})
return err
}, true)
if err != nil {
return err
}
if eventName != "" {
msg := event.NewMessage(w.SpaceID(), &pb.EventMessageValueOfSpaceAutoWidgetAdded{
SpaceAutoWidgetAdded: &pb.EventSpaceAutoWidgetAdded{
TargetId: targetId,
TargetName: eventName,
WidgetBlockId: widgetBlockId,
},
})
w.SendEvent([]*pb.EventMessage{msg})
}
return nil
}
func (w *widget) CreateBlock(s *state.State, req *pb.RpcBlockCreateWidgetRequest) (string, error) {
return w.createBlock(s, req, false)
}
func (w *widget) createBlock(s *state.State, req *pb.RpcBlockCreateWidgetRequest, isAutoAdded bool) (string, error) {
if req.Block.Content == nil {
return "", fmt.Errorf("block has no content")
}
@ -158,8 +187,8 @@ func (w *widget) CreateBlock(s *state.State, req *pb.RpcBlockCreateWidgetRequest
}
var wrapperBlockId string
if b.Model().Id != "" {
wrapperBlockId = autoWidgetBlockIdPrefix + b.Model().Id
if b.Model().Id != "" && isAutoAdded {
wrapperBlockId = b.Model().Id + autoWidgetBlockSuffix
}
wrapper := simple.New(&model.Block{
@ -169,9 +198,10 @@ func (w *widget) CreateBlock(s *state.State, req *pb.RpcBlockCreateWidgetRequest
},
Content: &model.BlockContentOfWidget{
Widget: &model.BlockContentWidget{
Layout: req.WidgetLayout,
Limit: req.ObjectLimit,
ViewId: req.ViewId,
Layout: req.WidgetLayout,
Limit: req.ObjectLimit,
ViewId: req.ViewId,
AutoAdded: isAutoAdded,
},
},
})

View file

@ -66,6 +66,8 @@ const (
FilesObjects = "filesObjects"
Files = "files"
defaultFileName = "untitled"
)
var log = logging.Logger("anytype-mw-export")
@ -1313,6 +1315,9 @@ func (fn *namer) Get(path, hash, title, ext string) (name string) {
title = slug.Make(strings.TrimSuffix(title, ext))
name = text.TruncateEllipsized(title, fileLenLimit)
name = strings.TrimSuffix(name, text.TruncateEllipsis)
if name == "" {
name = defaultFileName
}
var (
i = 0
b = 36

View file

@ -75,3 +75,22 @@ func TestZipWriter_WriteFile(t *testing.T) {
}
assert.True(t, found)
}
func TestZipWriter_Get(t *testing.T) {
t.Run("file without name", func(t *testing.T) {
// given
path, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(path)
wr, err := newZipWriter(path, uniqName()+".zip")
require.NoError(t, err)
// when
name := wr.Namer().Get(Files, "hash", "", "")
// then
require.NoError(t, wr.Close())
assert.Equal(t, filepath.Join(Files, defaultFileName), name)
})
}

View file

@ -12,7 +12,6 @@ import (
"github.com/anyproto/anytype-heart/core/block/simple"
simpleDataview "github.com/anyproto/anytype-heart/core/block/simple/dataview"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
"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/pb/model"
@ -22,25 +21,52 @@ type ImportCollectionSetting struct {
collectionName string
targetObjects []string
icon string
fileKeys []*pb.ChangeFileKeys
needToAddDate, shouldBeFavorite, shouldAddRelations bool
}
func MakeImportCollectionSetting(
collectionName string,
targetObjects []string,
icon string,
fileKeys []*pb.ChangeFileKeys,
needToAddDate, shouldBeFavorite, shouldAddRelations bool,
) *ImportCollectionSetting {
return &ImportCollectionSetting{
collectionName: collectionName,
targetObjects: targetObjects,
icon: icon,
fileKeys: fileKeys,
needToAddDate: needToAddDate,
shouldBeFavorite: shouldBeFavorite,
shouldAddRelations: shouldAddRelations,
type ImportCollectionOption func(*ImportCollectionSetting)
func NewImportCollectionSetting(opts ...ImportCollectionOption) *ImportCollectionSetting {
s := &ImportCollectionSetting{}
for _, opt := range opts {
opt(s)
}
return s
}
func WithCollectionName(name string) ImportCollectionOption {
return func(s *ImportCollectionSetting) {
s.collectionName = name
}
}
func WithTargetObjects(objs []string) ImportCollectionOption {
return func(s *ImportCollectionSetting) {
s.targetObjects = objs
}
}
func WithIcon(icon string) ImportCollectionOption {
return func(s *ImportCollectionSetting) {
s.icon = icon
}
}
func WithAddDate() ImportCollectionOption {
return func(s *ImportCollectionSetting) {
s.needToAddDate = true
}
}
func WithFavorite() ImportCollectionOption {
return func(s *ImportCollectionSetting) {
s.shouldBeFavorite = true
}
}
func WithRelations() ImportCollectionOption {
return func(s *ImportCollectionSetting) {
s.shouldAddRelations = true
}
}
@ -75,14 +101,13 @@ func (r *ImportCollection) MakeImportCollection(req *ImportCollectionSetting) (*
detailsStruct = st.CombinedDetails().Merge(detailsStruct)
st.UpdateStoreSlice(template.CollectionStoreKey, req.targetObjects)
return r.getRootCollectionSnapshot(req.collectionName, st, detailsStruct, req.fileKeys), nil
return r.getRootCollectionSnapshot(req.collectionName, st, detailsStruct), nil
}
func (r *ImportCollection) getRootCollectionSnapshot(
collectionName string,
st *state.State,
detailsStruct *domain.Details,
fileKeys []*pb.ChangeFileKeys,
) *Snapshot {
if detailsStruct == nil {
detailsStruct = domain.NewDetails()
@ -100,7 +125,6 @@ func (r *ImportCollection) getRootCollectionSnapshot(
RelationLinks: st.GetRelationLinks(),
Collections: st.Store(),
},
FileKeys: fileKeys,
},
}
}

View file

@ -0,0 +1,61 @@
package common
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/anyproto/anytype-heart/core/block/collection"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
)
func TestMakeImportCollection(t *testing.T) {
tests := []struct {
name string
needToAddDate bool
shouldBeFavorite bool
shouldAddRelation bool
}{
{"all false", false, false, false},
{"add date", true, false, false},
{"add favorite", false, true, false},
{"add relations", false, false, true},
{"all True", true, true, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
importer := NewImportCollection(collection.New())
req := NewImportCollectionSetting(
WithCollectionName("My Collection"),
WithTargetObjects([]string{"obj1", "obj2"}),
WithIcon("icon.png"),
)
req.needToAddDate = tt.needToAddDate
req.shouldBeFavorite = tt.shouldBeFavorite
req.shouldAddRelations = tt.shouldAddRelation
root, err := importer.MakeImportCollection(req)
assert.NoError(t, err)
assert.NotNil(t, root)
if tt.needToAddDate {
assert.Contains(t, root.FileName, time.Now().Format("2006"))
} else {
assert.Equal(t, "My Collection", root.FileName)
}
if tt.shouldBeFavorite {
assert.Equal(t, domain.Bool(true), root.Snapshot.Data.Details.Get(bundle.RelationKeyIsFavorite))
} else {
assert.Equal(t, domain.Bool(false), root.Snapshot.Data.Details.Get(bundle.RelationKeyIsFavorite))
}
})
}
}

View file

@ -67,7 +67,12 @@ func (c *CSV) GetSnapshots(ctx context.Context, req *pb.RpcObjectImportRequest,
return nil, allErrors
}
rootCollection := common.NewImportCollection(c.collectionService)
settings := common.MakeImportCollectionSetting(rootCollectionName, result.objectIDs, "", nil, true, true, true)
settings := common.NewImportCollectionSetting(
common.WithCollectionName(rootCollectionName),
common.WithTargetObjects(result.objectIDs),
common.WithAddDate(),
common.WithRelations(),
)
rootCol, err := rootCollection.MakeImportCollection(settings)
if err != nil {
allErrors.Add(err)

View file

@ -66,7 +66,12 @@ func (h *HTML) GetSnapshots(ctx context.Context, req *pb.RpcObjectImportRequest,
return nil, allErrors
}
rootCollection := common.NewImportCollection(h.collectionService)
settings := common.MakeImportCollectionSetting(rootCollectionName, targetObjects, "", nil, true, true, true)
settings := common.NewImportCollectionSetting(
common.WithCollectionName(rootCollectionName),
common.WithTargetObjects(targetObjects),
common.WithAddDate(),
common.WithRelations(),
)
rootCollectionSnapshot, err := rootCollection.MakeImportCollection(settings)
if err != nil {
allErrors.Add(err)

View file

@ -70,6 +70,7 @@ type Import struct {
importCtx context.Context
importCtxCancel context.CancelFunc
spaceService space.Service
}
func New() Importer {
@ -82,6 +83,7 @@ func (i *Import) Init(a *app.App) (err error) {
i.s = app.MustComponent[*block.Service](a)
accountService := app.MustComponent[account.Service](a)
spaceService := app.MustComponent[space.Service](a)
i.spaceService = spaceService
col := app.MustComponent[*collection.Service](a)
i.tempDirProvider = app.MustComponent[core.TempDirProvider](a)
converters := []common.Converter{
@ -180,10 +182,33 @@ func (i *Import) importObjects(ctx context.Context, importRequest *ImportRequest
func (i *Import) onImportFinish(res *ImportResponse, req *ImportRequest, importId string) {
i.finishImportProcess(res.Err, req)
i.sendFileEvents(res.Err)
if res.RootCollectionId != "" {
i.addRootCollectionWidget(res, req)
}
i.recordEvent(&metrics.ImportFinishedEvent{ID: importId, ImportType: req.Type.String()})
i.sendImportFinishEventToClient(res.RootCollectionId, req.IsSync, res.ObjectsCount, req.Type)
}
func (i *Import) addRootCollectionWidget(res *ImportResponse, req *ImportRequest) {
spc, err := i.spaceService.Get(i.importCtx, req.SpaceId)
if err != nil {
log.Errorf("failed to create widget from root collection, error: %s", err.Error())
} else {
_, err = i.s.CreateWidgetBlock(nil, &pb.RpcBlockCreateWidgetRequest{
ContextId: spc.DerivedIDs().Widgets,
WidgetLayout: model.BlockContentWidget_CompactList,
Block: &model.Block{
Content: &model.BlockContentOfLink{Link: &model.BlockContentLink{
TargetBlockId: res.RootCollectionId,
}},
},
})
if err != nil {
log.Errorf("failed to create widget from root collection, error: %s", err.Error())
}
}
}
func (i *Import) sendFileEvents(returnedErr error) {
if returnedErr == nil {
i.fileSync.SendImportEvents()

View file

@ -16,6 +16,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/import/web/parsers/mock_parsers"
"github.com/anyproto/anytype-heart/core/block/process"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/space/mock_space"
"github.com/anyproto/anytype-heart/core/block/import/common"
"github.com/anyproto/anytype-heart/core/block/import/common/mock_common"
@ -971,6 +972,9 @@ func Test_ImportRootCollectionInResponse(t *testing.T) {
fileSync.EXPECT().SendImportEvents().Return().Times(1)
fileSync.EXPECT().ClearImportEvents().Return().Times(1)
i.fileSync = fileSync
mockSpaceService := mock_space.NewMockService(t)
mockSpaceService.EXPECT().Get(nil, "space1").Return(nil, fmt.Errorf("not found"))
i.spaceService = mockSpaceService
// when
importRequest := &ImportRequest{

View file

@ -102,7 +102,12 @@ func (m *Markdown) processFiles(req *pb.RpcObjectImportRequest, progress process
func (m *Markdown) createRootCollection(allSnapshots []*common.Snapshot, allRootObjectsIds []string) ([]*common.Snapshot, string, error) {
rootCollection := common.NewImportCollection(m.service)
settings := common.MakeImportCollectionSetting(rootCollectionName, allRootObjectsIds, "", nil, true, true, true)
settings := common.NewImportCollectionSetting(
common.WithCollectionName(rootCollectionName),
common.WithTargetObjects(allRootObjectsIds),
common.WithAddDate(),
common.WithRelations(),
)
rootCol, err := rootCollection.MakeImportCollection(settings)
if err != nil {
return nil, "", err
@ -424,7 +429,10 @@ func (m *Markdown) createSnapshots(
func (m *Markdown) addCollectionSnapshot(fileName string, file *FileInfo, snapshots []*common.Snapshot) ([]*common.Snapshot, error) {
c := common.NewImportCollection(m.service)
settings := common.MakeImportCollectionSetting(file.Title, file.CollectionsObjectsIds, "", nil, false, false, false)
settings := common.NewImportCollectionSetting(
common.WithCollectionName(file.Title),
common.WithTargetObjects(file.CollectionsObjectsIds),
)
csvCollection, err := c.MakeImportCollection(settings)
if err != nil {
return nil, err

View file

@ -351,7 +351,12 @@ func (ds *Service) AddObjectsToNotionCollection(notionContext *api.NotionImportC
allObjects := ds.filterObjects(notionContext, notionDB, notionPages)
rootCollection := common.NewImportCollection(ds.collectionService)
settings := common.MakeImportCollectionSetting(rootCollectionName, allObjects, "", nil, true, true, true)
settings := common.NewImportCollectionSetting(
common.WithCollectionName(rootCollectionName),
common.WithTargetObjects(allObjects),
common.WithAddDate(),
common.WithRelations(),
)
rootCol, err := rootCollection.MakeImportCollection(settings)
if err != nil {
return nil, err

View file

@ -2,7 +2,6 @@ package pb
import (
"github.com/globalsign/mgo/bson"
"github.com/samber/lo"
"github.com/anyproto/anytype-heart/core/block/collection"
"github.com/anyproto/anytype-heart/core/block/editor/state"
@ -40,13 +39,9 @@ func (g *GalleryImport) ProvideCollection(snapshots []*common.Snapshot,
if widget != nil {
widgetObjects = g.getObjectsFromWidgets(widget)
}
var (
icon string
fileKeys []*pb.ChangeFileKeys
)
var icon string
if workspaceSnapshot != nil { // we use space icon for import collection
icon = workspaceSnapshot.Snapshot.Data.Details.GetString(bundle.RelationKeyIconImage)
fileKeys = lo.Filter(workspaceSnapshot.Snapshot.FileKeys, func(item *pb.ChangeFileKeys, index int) bool { return item.Hash == icon })
}
collectionName := params.GetCollectionTitle() // collection name should be the name of experience
if collectionName == "" {
@ -54,13 +49,18 @@ func (g *GalleryImport) ProvideCollection(snapshots []*common.Snapshot,
}
rootCollection := common.NewImportCollection(g.service)
if len(widgetObjects) > 0 {
collectionsSnapshots, err = g.getWidgetsCollection(collectionName, rootCollection, widgetObjects, icon, fileKeys, widget, collectionsSnapshots)
collectionsSnapshots, err = g.getWidgetsCollection(collectionName, rootCollection, widgetObjects, icon, widget, collectionsSnapshots)
if err != nil {
return nil, err
}
}
objectsIDs := g.getObjectsIDs(snapshots)
settings := common.MakeImportCollectionSetting(collectionName, objectsIDs, icon, fileKeys, false, true, true)
settings := common.NewImportCollectionSetting(
common.WithCollectionName(collectionName),
common.WithTargetObjects(objectsIDs),
common.WithIcon(icon),
common.WithRelations(),
)
objectsCollection, err := rootCollection.MakeImportCollection(settings)
if err != nil {
return nil, err
@ -73,12 +73,16 @@ func (g *GalleryImport) getWidgetsCollection(collectionName string,
rootCollection *common.ImportCollection,
widgetObjects []string,
icon string,
fileKeys []*pb.ChangeFileKeys,
widget *common.Snapshot,
collectionsSnapshots []*common.Snapshot,
) ([]*common.Snapshot, error) {
widgetCollectionName := collectionName + widgetCollectionPattern
settings := common.MakeImportCollectionSetting(widgetCollectionName, widgetObjects, icon, fileKeys, false, false, true)
settings := common.NewImportCollectionSetting(
common.WithCollectionName(widgetCollectionName),
common.WithTargetObjects(widgetObjects),
common.WithIcon(icon),
common.WithRelations(),
)
widgetsCollectionSnapshot, err := rootCollection.MakeImportCollection(settings)
if err != nil {
return nil, err

View file

@ -56,7 +56,12 @@ func (s *SpaceImport) ProvideCollection(snapshots []*common.Snapshot,
})
}
rootCollection := common.NewImportCollection(s.service)
settings := common.MakeImportCollectionSetting(rootCollectionName, rootObjects, "", nil, true, true, true)
settings := common.NewImportCollectionSetting(
common.WithCollectionName(rootCollectionName),
common.WithTargetObjects(rootObjects),
common.WithRelations(),
common.WithAddDate(),
)
rootCollectionSnapshot, err := rootCollection.MakeImportCollection(settings)
if err != nil {
return nil, err

View file

@ -56,7 +56,12 @@ func (t *TXT) GetSnapshots(ctx context.Context, req *pb.RpcObjectImportRequest,
return nil, allErrors
}
rootCollection := common.NewImportCollection(t.service)
settings := common.MakeImportCollectionSetting(rootCollectionName, targetObjects, "", nil, true, true, true)
settings := common.NewImportCollectionSetting(
common.WithCollectionName(rootCollectionName),
common.WithTargetObjects(targetObjects),
common.WithRelations(),
common.WithAddDate(),
)
rootCol, err := rootCollection.MakeImportCollection(settings)
if err != nil {
allErrors.Add(err)

View file

@ -95,8 +95,12 @@ func (s *Service) CreateTypeWidgetIfMissing(ctx context.Context, spaceId string,
return err
}
widgetObjectId := space.DerivedIDs().Widgets
widgetDetails, err := s.objectStore.SpaceIndex(space.Id()).GetDetails(widgetObjectId)
spaceIndex := s.objectStore.SpaceIndex(space.Id())
widgetDetails, err := spaceIndex.GetDetails(widgetObjectId)
if err == nil {
if widgetDetails.GetBool(bundle.RelationKeyAutoWidgetDisabled) {
return nil
}
keys := widgetDetails.Get(bundle.RelationKeyAutoWidgetTargets).StringList()
if slices.Contains(keys, typeId) {
// widget was created before
@ -104,7 +108,7 @@ func (s *Service) CreateTypeWidgetIfMissing(ctx context.Context, spaceId string,
}
}
// this is not optimal, maybe it should be some cheaper way
records, err := s.objectStore.SpaceIndex(space.Id()).QueryRaw(&database.Filters{FilterObj: database.FiltersAnd{
records, err := spaceIndex.QueryRaw(&database.Filters{FilterObj: database.FiltersAnd{
database.FilterEq{
Key: bundle.RelationKeyType,
Cond: model.BlockContentDataviewFilter_Equal,
@ -128,7 +132,16 @@ func (s *Service) CreateTypeWidgetIfMissing(ctx context.Context, spaceId string,
// only create widget if this was the first object of this type created
return nil
}
var targetName string
typeDetails, err := spaceIndex.GetDetails(typeId)
if err == nil {
targetName = typeDetails.Get(bundle.RelationKeyPluralName).String()
if targetName == "" {
targetName = typeDetails.Get(bundle.RelationKeyName).String()
}
}
return cache.DoState(s, widgetObjectId, func(st *state.State, w widget.Widget) (err error) {
return w.AddAutoWidget(st, typeId, key.String(), addr.ObjectTypeAllViewId, model.BlockContentWidget_View)
return w.AddAutoWidget(st, typeId, key.String(), addr.ObjectTypeAllViewId, model.BlockContentWidget_View, targetName)
})
}

View file

@ -223,7 +223,7 @@ func (c config) GetYamux() yamux.Config {
func (c config) GetQuic() quic.Config {
return quic.Config{
WriteTimeoutSec: 60,
WriteTimeoutSec: 1200,
DialTimeoutSec: 60,
KeepAlivePeriodSec: 120,
}

View file

@ -75,7 +75,7 @@ func (es *GrpcSender) sendEvent(server SessionServer, event *pb.Event) {
if s, ok := status.FromError(err); ok && s.Code() == codes.Unavailable {
es.shutdownCh <- server.Token
}
if strings.Contains(err.Error(), "rpc error: code = Unavailable desc = transport is closing") {
if strings.Contains(err.Error(), "transport is closing") {
log.Errorf("failed to send event: %v", err)
}
}

View file

@ -210,6 +210,9 @@ func logIndexLoop(err error) {
if errors.Is(err, rpcstore.ErrNoConnectionToAnyFileClient) {
return
}
if errors.Is(err, files.FailedProtoUnmarshallError) {
return
}
log.Errorf("index loop: %v", err)
}

View file

@ -42,7 +42,10 @@ const (
CName = "files"
)
var log = logging.Logger("anytype-files")
var (
log = logging.Logger("anytype-files")
FailedProtoUnmarshallError = errors.New("failed proto unmarshall")
)
var _ Service = (*service)(nil)
@ -306,7 +309,7 @@ func (s *service) fileInfoFromPath(ctx context.Context, spaceId string, fileId d
}
err = proto.Unmarshal(b, &file)
if err != nil || file.Hash == "" {
return nil, fmt.Errorf("failed to unmarshal not-encrypted file info: %w", err)
return nil, fmt.Errorf("failed to unmarshal not-encrypted file info: %w", FailedProtoUnmarshallError)
}
}

View file

@ -349,7 +349,6 @@ func (s *fileSync) uploadFile(ctx context.Context, spaceID string, fileId domain
if err != nil {
log.Warn("delete limit reached error logged", zap.String("fileId", fileId.String()), zap.Error(err))
}
log.Warn("done upload", zap.String("fileId", fileId.String()), zap.Int("bytesToUpload", blocksAvailability.bytesToUpload), zap.Int("bytesUploaded", totalBytesUploaded))
return nil
}

View file

@ -124,7 +124,7 @@ func uniqName() string {
return time.Now().Format("Anytype.WebPublish.20060102.150405.99")
}
func (s *service) exportToDir(ctx context.Context, spaceId, pageId string) (dirEntries []fs.DirEntry, exportPath string, err error) {
func (s *service) exportToDir(ctx context.Context, spaceId, pageId string, includeSpaceInfo bool) (dirEntries []fs.DirEntry, exportPath string, err error) {
tempDir := os.TempDir()
exportPath, _, err = s.exportService.Export(ctx, pb.RpcObjectListExportRequest{
SpaceId: spaceId,
@ -137,7 +137,7 @@ func (s *service) exportToDir(ctx context.Context, spaceId, pageId string) (dirE
NoProgress: true,
IncludeNested: true,
IncludeBacklinks: true,
IncludeSpace: true,
IncludeSpace: includeSpaceInfo,
LinksStateFilters: &pb.RpcObjectListExportStateFilters{
RelationsWhiteList: relationsWhiteListToPbModel(),
RemoveBlocks: true,
@ -155,7 +155,12 @@ func (s *service) exportToDir(ctx context.Context, spaceId, pageId string) (dirE
}
func (s *service) publishToPublishServer(ctx context.Context, spaceId, pageId, uri, globalName string, joinSpace bool) (err error) {
dirEntries, exportPath, err := s.exportToDir(ctx, spaceId, pageId)
spc, err := s.spaceService.Get(ctx, spaceId)
if err != nil {
return err
}
includeInviteLinkAndSpaceInfo := joinSpace && !spc.IsPersonal()
dirEntries, exportPath, err := s.exportToDir(ctx, spaceId, pageId, includeInviteLinkAndSpaceInfo)
if err != nil {
return err
}
@ -177,12 +182,7 @@ func (s *service) publishToPublishServer(ctx context.Context, spaceId, pageId, u
return err
}
spc, err := s.spaceService.Get(ctx, spaceId)
if err != nil {
return err
}
err = s.applyInviteLink(ctx, spc, &uberSnapshot, joinSpace)
err = s.applyInviteLink(ctx, spaceId, &uberSnapshot, includeInviteLinkAndSpaceInfo)
if err != nil {
return err
}
@ -210,12 +210,18 @@ func (s *service) publishToPublishServer(ctx context.Context, spaceId, pageId, u
return nil
}
func (s *service) applyInviteLink(ctx context.Context, spc clientspace.Space, snapshot *PublishingUberSnapshot, joinSpace bool) error {
inviteLink, err := s.extractInviteLink(ctx, spc.Id(), joinSpace, spc.IsPersonal())
func (s *service) applyInviteLink(ctx context.Context, spaceId string, snapshot *PublishingUberSnapshot, includeInviteLink bool) error {
if !includeInviteLink {
return nil
}
inviteInfo, err := s.inviteService.GetCurrent(ctx, spaceId)
if err != nil && errors.Is(err, inviteservice.ErrInviteNotExists) {
return nil
}
if err != nil {
return err
}
snapshot.Meta.InviteLink = inviteLink
snapshot.Meta.InviteLink = fmt.Sprintf(inviteLinkUrlTemplate, inviteInfo.InviteFileCid, inviteInfo.InviteFileKey)
return nil
}
@ -366,21 +372,6 @@ func (s *service) publishToServer(ctx context.Context, spaceId, pageId, uri, ver
return nil
}
func (s *service) extractInviteLink(ctx context.Context, spaceId string, joinSpace, isPersonal bool) (string, error) {
var inviteLink string
if joinSpace && !isPersonal {
inviteInfo, err := s.inviteService.GetCurrent(ctx, spaceId)
if err != nil && errors.Is(err, inviteservice.ErrInviteNotExists) {
return "", nil
}
if err != nil {
return "", err
}
inviteLink = fmt.Sprintf(inviteLinkUrlTemplate, inviteInfo.InviteFileCid, inviteInfo.InviteFileKey)
}
return inviteLink, nil
}
func (s *service) evaluateDocumentVersion(ctx context.Context, spc clientspace.Space, pageId string, joinSpace bool) (string, error) {
treeStorage, err := spc.Storage().TreeStorage(ctx, pageId)
if err != nil {

View file

@ -139,7 +139,9 @@ func TestPublish(t *testing.T) {
t.Run("success", func(t *testing.T) {
// given
isPersonal := true
spaceService, err := prepareSpaceService(t, isPersonal)
includeSpaceInfo := false
spaceService, err := prepareSpaceService(t, isPersonal, includeSpaceInfo)
objectTypeId := "customObjectType"
expectedUri := "test"
@ -159,7 +161,7 @@ func TestPublish(t *testing.T) {
identityService := mock_identity.NewMockService(t)
identityService.EXPECT().GetMyProfileDetails(context.Background()).Return("identity", nil, domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{}))
exp := prepareExporter(t, objectTypeId, spaceService)
exp := prepareExporter(t, objectTypeId, spaceService, false)
svc := &service{
spaceService: spaceService,
@ -169,7 +171,7 @@ func TestPublish(t *testing.T) {
}
// when
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, false)
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, includeSpaceInfo)
// then
assert.NoError(t, err)
@ -182,7 +184,9 @@ func TestPublish(t *testing.T) {
t.Run("success with space sharing", func(t *testing.T) {
// given
isPersonal := false
spaceService, err := prepareSpaceService(t, isPersonal)
includeSpaceInfo := true
spaceService, err := prepareSpaceService(t, isPersonal, includeSpaceInfo)
objectTypeId := "customObjectType"
expectedUri := "test"
@ -206,7 +210,7 @@ func TestPublish(t *testing.T) {
identityService := mock_identity.NewMockService(t)
identityService.EXPECT().GetMyProfileDetails(context.Background()).Return("identity", nil, domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{}))
exp := prepareExporter(t, objectTypeId, spaceService)
exp := prepareExporter(t, objectTypeId, spaceService, includeSpaceInfo)
inviteService := mock_inviteservice.NewMockInviteService(t)
inviteService.EXPECT().GetCurrent(context.Background(), "spaceId").Return(domain.InviteInfo{
@ -223,7 +227,7 @@ func TestPublish(t *testing.T) {
}
// when
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, true)
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, includeSpaceInfo)
// then
assert.NoError(t, err)
@ -235,7 +239,9 @@ func TestPublish(t *testing.T) {
})
t.Run("success with space sharing - invite not exists", func(t *testing.T) {
isPersonal := false
spaceService, err := prepareSpaceService(t, isPersonal)
includeSpaceInfo := true
spaceService, err := prepareSpaceService(t, isPersonal, includeSpaceInfo)
objectTypeId := "customObjectType"
expectedUri := "test"
@ -256,7 +262,7 @@ func TestPublish(t *testing.T) {
identityService := mock_identity.NewMockService(t)
identityService.EXPECT().GetMyProfileDetails(context.Background()).Return("identity", nil, domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{}))
exp := prepareExporter(t, objectTypeId, spaceService)
exp := prepareExporter(t, objectTypeId, spaceService, includeSpaceInfo)
inviteService := mock_inviteservice.NewMockInviteService(t)
inviteService.EXPECT().GetCurrent(context.Background(), "spaceId").Return(domain.InviteInfo{}, inviteservice.ErrInviteNotExists)
@ -270,7 +276,7 @@ func TestPublish(t *testing.T) {
}
// when
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, true)
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, includeSpaceInfo)
// then
assert.NoError(t, err)
@ -283,7 +289,8 @@ func TestPublish(t *testing.T) {
t.Run("success for member", func(t *testing.T) {
// given
isPersonal := false
spaceService, err := prepareSpaceService(t, isPersonal)
includeSpaceInfo := true
spaceService, err := prepareSpaceService(t, isPersonal, includeSpaceInfo)
objectTypeId := "customObjectType"
expectedUri := "test"
@ -311,7 +318,7 @@ func TestPublish(t *testing.T) {
},
}
exp := prepareExporter(t, objectTypeId, spaceService)
exp := prepareExporter(t, objectTypeId, spaceService, includeSpaceInfo)
inviteService := mock_inviteservice.NewMockInviteService(t)
inviteService.EXPECT().GetCurrent(context.Background(), "spaceId").Return(domain.InviteInfo{
@ -328,7 +335,7 @@ func TestPublish(t *testing.T) {
}
// when
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, true)
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, includeSpaceInfo)
// then
assert.NoError(t, err)
@ -341,7 +348,9 @@ func TestPublish(t *testing.T) {
t.Run("internal error", func(t *testing.T) {
// given
isPersonal := true
spaceService, err := prepareSpaceService(t, isPersonal)
includeSpaceInfo := true
spaceService, err := prepareSpaceService(t, isPersonal, includeSpaceInfo)
objectTypeId := "customObjectType"
expectedUri := "test"
@ -363,7 +372,7 @@ func TestPublish(t *testing.T) {
expectedErr: fmt.Errorf("internal error"),
}
exp := prepareExporter(t, objectTypeId, spaceService)
exp := prepareExporter(t, objectTypeId, spaceService, false)
svc := &service{
spaceService: spaceService,
@ -373,7 +382,7 @@ func TestPublish(t *testing.T) {
}
// when
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, true)
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, includeSpaceInfo)
// then
assert.Error(t, err)
@ -385,7 +394,14 @@ func TestPublish(t *testing.T) {
})
t.Run("limit error for members", func(t *testing.T) {
// given
isPersonal := false
includeSpaceInfo := true
spaceService := mock_space.NewMockService(t)
space := mock_clientspace.NewMockSpace(t)
space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Workspace: workspaceId})
space.EXPECT().IsPersonal().Return(isPersonal)
spaceService.EXPECT().Get(context.Background(), spaceId).Return(space, nil)
expectedUri := "test"
testFile := "test"
@ -415,7 +431,7 @@ func TestPublish(t *testing.T) {
}
// when
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, true)
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, includeSpaceInfo)
// then
assert.Error(t, err)
@ -424,7 +440,14 @@ func TestPublish(t *testing.T) {
})
t.Run("default limit error", func(t *testing.T) {
// given
isPersonal := false
includeSpaceInfo := true
spaceService := mock_space.NewMockService(t)
space := mock_clientspace.NewMockSpace(t)
space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Workspace: workspaceId})
space.EXPECT().IsPersonal().Return(isPersonal)
spaceService.EXPECT().Get(context.Background(), spaceId).Return(space, nil)
expectedUri := "test"
testFile := "test"
@ -451,7 +474,7 @@ func TestPublish(t *testing.T) {
}
// when
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, true)
publish, err := svc.Publish(context.Background(), spaceId, objectId, expectedUri, includeSpaceInfo)
// then
assert.Error(t, err)
@ -666,24 +689,27 @@ func TestService_PublishingList(t *testing.T) {
var ctx = context.Background()
func prepareSpaceService(t *testing.T, isPersonal bool) (*mock_space.MockService, error) {
func prepareSpaceService(t *testing.T, isPersonal bool, includeSpaceInfo bool) (*mock_space.MockService, error) {
spaceService := mock_space.NewMockService(t)
space := mock_clientspace.NewMockSpace(t)
ctrl := gomock.NewController(t)
space.EXPECT().IsPersonal().Return(isPersonal)
space.EXPECT().Id().Return(spaceId)
st := mock_anystorage.NewMockClientSpaceStorage(t)
mockSt := mock_objecttree.NewMockStorage(ctrl)
st.EXPECT().TreeStorage(mock.Anything, mock.Anything).Return(mockSt, nil)
mockSt.EXPECT().Heads(gomock.Any()).Return([]string{"heads"}, nil)
space.EXPECT().Storage().Return(st)
space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Workspace: workspaceId})
if includeSpaceInfo && !isPersonal {
space.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{Workspace: workspaceId})
}
if includeSpaceInfo {
space.EXPECT().IsPersonal().Return(isPersonal)
}
spaceService.EXPECT().Get(context.Background(), spaceId).Return(space, nil)
return spaceService, nil
}
func prepareExporter(t *testing.T, objectTypeId string, spaceService *mock_space.MockService) export.Export {
func prepareExporter(t *testing.T, objectTypeId string, spaceService *mock_space.MockService, includeSpaceInfo bool) export.Export {
storeFixture := objectstore.NewStoreFixture(t)
objectTypeUniqueKey, err := domain.NewUniqueKey(smartblock.SmartBlockTypeObjectType, objectTypeId)
assert.Nil(t, err)
@ -740,23 +766,25 @@ func prepareExporter(t *testing.T, objectTypeId string, spaceService *mock_space
objectType.Doc = objectTypeDoc
objectType.SetType(smartblock.SmartBlockTypeObjectType)
workspaceTest := smarttest.New(workspaceId)
workspaceDoc := workspaceTest.NewState().SetDetails(domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyId: domain.String(workspaceId),
bundle.RelationKeyType: domain.String(objectTypeId),
}))
workspaceDoc.AddRelationLinks(&model.RelationLink{
Key: bundle.RelationKeyId.String(),
Format: model.RelationFormat_longtext,
}, &model.RelationLink{
Key: bundle.RelationKeyType.String(),
Format: model.RelationFormat_longtext,
})
workspaceTest.Doc = workspaceDoc
if includeSpaceInfo {
workspaceTest := smarttest.New(workspaceId)
workspaceDoc := workspaceTest.NewState().SetDetails(domain.NewDetailsFromMap(map[domain.RelationKey]domain.Value{
bundle.RelationKeyId: domain.String(workspaceId),
bundle.RelationKeyType: domain.String(objectTypeId),
}))
workspaceDoc.AddRelationLinks(&model.RelationLink{
Key: bundle.RelationKeyId.String(),
Format: model.RelationFormat_longtext,
}, &model.RelationLink{
Key: bundle.RelationKeyType.String(),
Format: model.RelationFormat_longtext,
})
workspaceTest.Doc = workspaceDoc
objectGetter.EXPECT().GetObject(context.Background(), workspaceId).Return(workspaceTest, nil)
}
objectGetter.EXPECT().GetObject(context.Background(), objectId).Return(smartBlockTest, nil)
objectGetter.EXPECT().GetObject(context.Background(), objectTypeId).Return(objectType, nil)
objectGetter.EXPECT().GetObject(context.Background(), workspaceId).Return(workspaceTest, nil)
a := &app.App{}
mockSender := mock_event.NewMockSender(t)

View file

@ -1855,6 +1855,7 @@
- [Event.Process.New](#anytype-Event-Process-New)
- [Event.Process.Update](#anytype-Event-Process-Update)
- [Event.Space](#anytype-Event-Space)
- [Event.Space.AutoWidgetAdded](#anytype-Event-Space-AutoWidgetAdded)
- [Event.Space.SyncStatus](#anytype-Event-Space-SyncStatus)
- [Event.Space.SyncStatus.Update](#anytype-Event-Space-SyncStatus-Update)
- [Event.Status](#anytype-Event-Status)
@ -28839,6 +28840,7 @@ Precondition: user A opened a block
| payloadBroadcast | [Event.Payload.Broadcast](#anytype-Event-Payload-Broadcast) | | |
| membershipUpdate | [Event.Membership.Update](#anytype-Event-Membership-Update) | | |
| spaceSyncStatusUpdate | [Event.Space.SyncStatus.Update](#anytype-Event-Space-SyncStatus-Update) | | |
| spaceAutoWidgetAdded | [Event.Space.AutoWidgetAdded](#anytype-Event-Space-AutoWidgetAdded) | | |
| p2pStatusUpdate | [Event.P2PStatus.Update](#anytype-Event-P2PStatus-Update) | | |
| importFinish | [Event.Import.Finish](#anytype-Event-Import-Finish) | | |
| chatAdd | [Event.Chat.Add](#anytype-Event-Chat-Add) | | |
@ -29305,6 +29307,23 @@ Removes document from subscription
<a name="anytype-Event-Space-AutoWidgetAdded"></a>
### Event.Space.AutoWidgetAdded
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| targetId | [string](#string) | | |
| targetName | [string](#string) | | pluralName (if exists) for types, fallback to name. Special cases for &#34;bin&#34; and &#34;favorites&#34; |
| widgetBlockId | [string](#string) | | |
<a name="anytype-Event-Space-SyncStatus"></a>
### Event.Space.SyncStatus
@ -30669,6 +30688,7 @@ Link: block to link some content from an external sources.
| layout | [Block.Content.Widget.Layout](#anytype-model-Block-Content-Widget-Layout) | | |
| limit | [int32](#int32) | | |
| viewId | [string](#string) | | |
| autoAdded | [bool](#bool) | | |

4
go.mod
View file

@ -8,7 +8,7 @@ require (
github.com/VividCortex/ewma v1.2.0
github.com/adrium/goheif v0.0.0-20230113233934-ca402e77a786
github.com/anyproto/any-store v0.1.12
github.com/anyproto/any-sync v0.6.8
github.com/anyproto/any-sync v0.6.10
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250131145601-de288583ff2a
github.com/anyproto/go-chash v0.1.0
github.com/anyproto/go-naturaldate/v2 v2.0.2-0.20230524105841-9829cfd13438
@ -109,7 +109,7 @@ require (
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
golang.org/x/image v0.25.0
golang.org/x/mobile v0.0.0-20250218173827-cd096645fcd3
golang.org/x/net v0.37.0
golang.org/x/net v0.38.0
golang.org/x/oauth2 v0.28.0
golang.org/x/sys v0.31.0
golang.org/x/text v0.23.0

8
go.sum
View file

@ -80,8 +80,8 @@ github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kk
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/anyproto/any-store v0.1.12 h1:VgTyfxM4BvFnYMbwWxV9FQmXWNlwp9xriWFh6VOjcm0=
github.com/anyproto/any-store v0.1.12/go.mod h1:T6WNuCHcuXIRiaZ+QAcBHdxIbPbgNCMIf1u3P9jvAyU=
github.com/anyproto/any-sync v0.6.8 h1:aMS7U+RWCqAqaCokCQjtBbiEsoBSBdLGz0kckxqMB2w=
github.com/anyproto/any-sync v0.6.8/go.mod h1:P1hd0Hrc66juMNlr/k7SG55aEwOrBAsKGkh9TsLdml8=
github.com/anyproto/any-sync v0.6.10 h1:TV3yLkp5NK7FkddUvVtfxT01t/Xi+DlKbvisGEQwmC0=
github.com/anyproto/any-sync v0.6.10/go.mod h1:TSKgCoTV40Bt8AfCh3RxPUUAfYGrhc8Mzh8/AiVlvX4=
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250131145601-de288583ff2a h1:ZZM+0OUCQMWSLSflpkf0ZMVo3V76qEDDIXPpQOClNs0=
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250131145601-de288583ff2a/go.mod h1:4fkueCZcGniSMXkrwESO8zzERrh/L7WHimRNWecfGM0=
github.com/anyproto/badger/v4 v4.2.1-0.20240110160636-80743fa3d580 h1:Ba80IlCCxkZ9H1GF+7vFu/TSpPvbpDCxXJ5ogc4euYc=
@ -1307,8 +1307,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=

File diff suppressed because it is too large Load diff

View file

@ -108,6 +108,7 @@ message Event {
Membership.Update membershipUpdate = 117;
Space.SyncStatus.Update spaceSyncStatusUpdate = 119;
Space.AutoWidgetAdded spaceAutoWidgetAdded = 122;
P2PStatus.Update p2pStatusUpdate = 120;
@ -1154,6 +1155,12 @@ message Event {
IncompatibleVersion = 2;
NetworkError = 3;
}
message AutoWidgetAdded {
string targetId = 1;
string targetName = 2; // pluralName (if exists) for types, fallback to name. Special cases for "bin" and "favorites"
string widgetBlockId = 3;
}
}
message P2PStatus {
message Update {

View file

@ -9,7 +9,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
)
const RelationChecksum = "e8392d6bf8efab6b707d68bc3922e4284a18a68370828e3ec6b18e0267b84bea"
const RelationChecksum = "a23583f8faef1cbfcd05ca1d2761538e67bbdd1336d1a467a0d657b5f986b313"
const (
RelationKeyTag domain.RelationKey = "tag"
RelationKeyCamera domain.RelationKey = "camera"
@ -158,6 +158,7 @@ const (
RelationKeyDefaultViewType domain.RelationKey = "defaultViewType"
RelationKeyDefaultTypeId domain.RelationKey = "defaultTypeId"
RelationKeyAutoWidgetTargets domain.RelationKey = "autoWidgetTargets"
RelationKeyAutoWidgetDisabled domain.RelationKey = "autoWidgetDisabled"
RelationKeyPluralName domain.RelationKey = "pluralName"
)
@ -282,6 +283,19 @@ var (
Revision: 1,
Scope: model.Relation_type,
},
RelationKeyAutoWidgetDisabled: {
DataSource: model.Relation_details,
Description: "",
Format: model.RelationFormat_checkbox,
Hidden: true,
Id: "_brautoWidgetDisabled",
Key: "autoWidgetDisabled",
Name: "Auto Widget disabled",
ReadOnly: false,
ReadOnlyRelation: true,
Scope: model.Relation_type,
},
RelationKeyAutoWidgetTargets: {
DataSource: model.Relation_details,

View file

@ -1517,6 +1517,15 @@
"readonly": false,
"source": "details"
},
{
"format": "checkbox",
"hidden": true,
"key": "autoWidgetDisabled",
"maxCount": 0,
"name": "Auto Widget disabled",
"readonly": false,
"source": "details"
},
{
"description": "Name of Object type in plural form",
"format": "longtext",

View file

@ -25,6 +25,7 @@ import (
"unicode"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/app/debugstat"
tantivy "github.com/anyproto/tantivy-go"
"github.com/valyala/fastjson"
@ -102,6 +103,19 @@ type ftSearch struct {
lang tantivy.Language
}
func (f *ftSearch) ProvideStat() any {
count, _ := f.DocCount()
return count
}
func (f *ftSearch) StatId() string {
return "doc_count"
}
func (f *ftSearch) StatType() string {
return CName
}
func TantivyNew() FTSearch {
return new(ftSearch)
}
@ -138,6 +152,10 @@ func (f *ftSearch) DeleteObject(objectId string) error {
func (f *ftSearch) Init(a *app.App) error {
repoPath := app.MustComponent[wallet.Wallet](a).RepoPath()
statService, _ := app.GetComponent[debugstat.StatService](a)
if statService != nil {
statService.AddProvider(f)
}
f.lang = validateLanguage(app.MustComponent[wallet.Wallet](a).FtsPrimaryLang())
f.rootPath = filepath.Join(repoPath, ftsDir2)
f.blevePath = filepath.Join(repoPath, ftsDir)

View file

@ -11,6 +11,7 @@ import (
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-store/anyenc"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/app/debugstat"
"github.com/anyproto/any-sync/coordinator/coordinatorproto"
"golang.org/x/exp/maps"
@ -124,6 +125,19 @@ type dsObjectStore struct {
componentCtxCancel context.CancelFunc
}
func (s *dsObjectStore) ProvideStat() any {
count, _ := s.ListIdsCrossSpace()
return len(count)
}
func (s *dsObjectStore) StatId() string {
return "ds_count"
}
func (s *dsObjectStore) StatType() string {
return CName
}
func (s *dsObjectStore) IterateSpaceIndex(f func(store spaceindex.Store) error) error {
s.Lock()
spaceIndexes := make([]spaceindex.Store, 0, len(s.spaceIndexes))
@ -169,6 +183,10 @@ func (s *dsObjectStore) Init(a *app.App) (err error) {
s.setDefaultConfig()
s.oldStore = app.MustComponent[oldstore.Service](a)
s.techSpaceIdProvider = app.MustComponent[TechSpaceIdProvider](a)
statService, _ := app.GetComponent[debugstat.StatService](a)
if statService != nil {
statService.AddProvider(s)
}
return nil
}

File diff suppressed because it is too large Load diff

View file

@ -593,6 +593,7 @@ message Block {
Layout layout = 1;
int32 limit = 2;
string viewId = 3;
bool autoAdded = 4;
enum Layout {
Link = 0;

View file

@ -405,7 +405,7 @@ func (b *builtinObjects) createWidgets(ctx session.Context, spaceId string, useC
}
if err = cache.DoStateCtx(b.objectGetter, ctx, widgetObjectID, func(s *state.State, w widget.Widget) error {
for _, targetId := range widgetTargetsToCreate {
if err := w.AddAutoWidget(s, targetId, "", addr.ObjectTypeAllViewId, model.BlockContentWidget_View); err != nil {
if err := w.AddAutoWidget(s, targetId, "", addr.ObjectTypeAllViewId, model.BlockContentWidget_View, ""); err != nil {
log.Errorf("failed to create widget block for type '%s': %v", targetId, err)
}
}