From 49d233d92ab91e8b8a94db6b62fe054176dd618d Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 28 Jul 2025 22:06:09 +0800 Subject: [PATCH 1/7] :art: Export preview mode supports focus use https://github.com/siyuan-note/siyuan/issues/15340 --- kernel/api/export.go | 7 ++++++- kernel/model/export.go | 11 ++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/kernel/api/export.go b/kernel/api/export.go index 63d9f00f8..e9336014e 100644 --- a/kernel/api/export.go +++ b/kernel/api/export.go @@ -431,7 +431,12 @@ func exportMdContent(c *gin.Context) { fillCSSVar = arg["fillCSSVar"].(bool) } - hPath, content := model.ExportMarkdownContent(id, refMode, embedMode, yfm, fillCSSVar) + adjustHeadingLevel := false + if nil != arg["adjustHeadingLevel"] { + adjustHeadingLevel = arg["adjustHeadingLevel"].(bool) + } + + hPath, content := model.ExportMarkdownContent(id, refMode, embedMode, yfm, fillCSSVar, adjustHeadingLevel) ret.Data = map[string]interface{}{ "hPath": hPath, "content": content, diff --git a/kernel/model/export.go b/kernel/model/export.go index abacbb090..18cf138fc 100644 --- a/kernel/model/export.go +++ b/kernel/model/export.go @@ -1458,12 +1458,13 @@ func processPDFLinkEmbedAssets(pdfCtx *model.Context, assetDests []string, remov } func ExportStdMarkdown(id string, assetsDestSpace2Underscore, adjustHeadingLevel bool) string { - tree, err := LoadTreeByBlockID(id) - if err != nil { - logging.LogErrorf("load tree by block id [%s] failed: %s", id, err) + bt := treenode.GetBlockTree(id) + if nil == bt { + logging.LogErrorf("block tree [%s] not found", id) return "" } + tree := prepareExportTree(bt) cloudAssetsBase := "" if IsSubscriber() { cloudAssetsBase = util.GetCloudAssetsServer() + Conf.GetUser().UserId + "/" @@ -1981,7 +1982,7 @@ func walkRelationAvs(avID string, exportAvIDs *hashset.Set) { } } -func ExportMarkdownContent(id string, refMode, embedMode int, addYfm, fillCSSVar bool) (hPath, exportedMd string) { +func ExportMarkdownContent(id string, refMode, embedMode int, addYfm, fillCSSVar, adjustHeadingLv bool) (hPath, exportedMd string) { bt := treenode.GetBlockTree(id) if nil == bt { return @@ -1989,7 +1990,7 @@ func ExportMarkdownContent(id string, refMode, embedMode int, addYfm, fillCSSVar tree := prepareExportTree(bt) hPath = tree.HPath - exportedMd = exportMarkdownContent0(id, tree, "", false, false, + exportedMd = exportMarkdownContent0(id, tree, "", false, adjustHeadingLv, ".md", refMode, embedMode, Conf.Export.FileAnnotationRefMode, Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker, Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight, From 0816925e76c9e18f8e8edeceeccecc57a0d8fd12 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 28 Jul 2025 22:44:56 +0800 Subject: [PATCH 2/7] :art: Database grouping by field https://github.com/siyuan-note/siyuan/issues/10964 --- kernel/model/attribute_view.go | 67 ++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index b65310ad7..e934e8008 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -2936,24 +2936,8 @@ func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, a targetView = groupView } } - viewable := sql.RenderGroupView(attrView, view, targetView) - av.Filter(viewable, attrView) - av.Sort(viewable, attrView) - items := viewable.(av.Collection).GetItems() - if 0 < len(items) { - if "" != previousBlockID { - for _, row := range items { - if row.GetID() == previousBlockID { - nearItem = row - break - } - } - } else { - if 0 < len(items) { - nearItem = items[0] - } - } - } + + nearItem = getNearItem(attrView, view, targetView, previousBlockID) } filterKeyIDs := map[string]bool{} @@ -3054,13 +3038,12 @@ func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, a if !filterKeyIDs[groupKey.ID] /* 过滤条件应用过的话就不重复处理了 */ && "" != groupID { if groupView := view.GetGroup(groupID); nil != groupView { if keyValues, _ := attrView.GetKeyValues(groupKey.ID); nil != keyValues { - var newValue, defaultVal *av.Value + var newValue *av.Value if nil != nearItem { - defaultVal = nearItem.GetValue(groupKey.ID) - } - if nil != defaultVal { + defaultVal := nearItem.GetValue(groupKey.ID) newValue = defaultVal.Clone() - } else { + } + if nil == newValue { newValue = av.GetAttributeViewDefaultValue(ast.NewNodeID(), groupKey.ID, blockID, groupKey.Type) } @@ -3096,6 +3079,29 @@ func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, a return } +func getNearItem(attrView *av.AttributeView, view, groupView *av.View, previousItemID string) (ret av.Item) { + viewable := sql.RenderGroupView(attrView, view, groupView) + av.Filter(viewable, attrView) + av.Sort(viewable, attrView) + items := viewable.(av.Collection).GetItems() + if 0 < len(items) { + if "" != previousItemID { + for _, row := range items { + if row.GetID() == previousItemID { + ret = row + return + } + } + } else { + if 0 < len(items) { + ret = items[0] + return + } + } + } + return +} + func (tx *Transaction) doRemoveAttrViewBlock(operation *Operation) (ret *TxErr) { err := removeAttributeViewBlock(operation.SrcIDs, operation.AvID, tx) if err != nil { @@ -3565,6 +3571,21 @@ func sortAttributeViewRow(operation *Operation) (err error) { targetGroupView = view.GetGroup(operation.TargetGroupID) } if nil != targetGroupView { + groupKey := view.GetGroupKey(attrView) + nearItem := getNearItem(attrView, view, targetGroupView, operation.PreviousID) + var newValue *av.Value + if nil != nearItem { + defaultVal := nearItem.GetValue(view.Group.Field) + newValue = defaultVal.Clone() + } + if nil == newValue { + newValue = av.GetAttributeViewDefaultValue(ast.NewNodeID(), groupKey.ID, operation.ID, groupKey.Type) + + } + val := attrView.GetValue(groupKey.ID, operation.ID) + newValueRaw := newValue.GetValByType(groupKey.Type) + val.SetValByType(groupKey.Type, newValueRaw) + for i, r := range targetGroupView.GroupItemIDs { if r == operation.PreviousID { previousIndex = i + 1 From f7d28dc1ded3eb72c10f723d807aeae67217a344 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 28 Jul 2025 22:53:04 +0800 Subject: [PATCH 3/7] :art: Database grouping by field https://github.com/siyuan-note/siyuan/issues/10964 --- kernel/model/attribute_view.go | 59 +++++++++++++++++----------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index e934e8008..1a7e97f8d 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -3038,15 +3038,7 @@ func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, a if !filterKeyIDs[groupKey.ID] /* 过滤条件应用过的话就不重复处理了 */ && "" != groupID { if groupView := view.GetGroup(groupID); nil != groupView { if keyValues, _ := attrView.GetKeyValues(groupKey.ID); nil != keyValues { - var newValue *av.Value - if nil != nearItem { - defaultVal := nearItem.GetValue(groupKey.ID) - newValue = defaultVal.Clone() - } - if nil == newValue { - newValue = av.GetAttributeViewDefaultValue(ast.NewNodeID(), groupKey.ID, blockID, groupKey.Type) - } - + newValue := getNewValueByNearItem(nearItem, groupKey, blockID) if av.KeyTypeBlock == newValue.Type { // 如果是主键的话前面已经添加过了,这里仅修改内容 blockValue.Block.Content = newValue.Block.Content @@ -3079,6 +3071,17 @@ func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, a return } +func getNewValueByNearItem(nearItem av.Item, key *av.Key, blockID string) (ret *av.Value) { + if nil != nearItem { + defaultVal := nearItem.GetValue(key.ID) + ret = defaultVal.Clone() + } + if nil == ret { + ret = av.GetAttributeViewDefaultValue(ast.NewNodeID(), key.ID, blockID, key.Type) + } + return +} + func getNearItem(attrView *av.AttributeView, view, groupView *av.View, previousItemID string) (ret av.Item) { viewable := sql.RenderGroupView(attrView, view, groupView) av.Filter(viewable, attrView) @@ -3566,33 +3569,31 @@ func sortAttributeViewRow(operation *Operation) (err error) { } groupView.GroupItemIDs = append(groupView.GroupItemIDs[:idx], groupView.GroupItemIDs[idx+1:]...) - targetGroupView := groupView - if operation.GroupID != operation.TargetGroupID { // 跨分组拖拽 - targetGroupView = view.GetGroup(operation.TargetGroupID) - } - if nil != targetGroupView { - groupKey := view.GetGroupKey(attrView) - nearItem := getNearItem(attrView, view, targetGroupView, operation.PreviousID) - var newValue *av.Value - if nil != nearItem { - defaultVal := nearItem.GetValue(view.Group.Field) - newValue = defaultVal.Clone() - } - if nil == newValue { - newValue = av.GetAttributeViewDefaultValue(ast.NewNodeID(), groupKey.ID, operation.ID, groupKey.Type) + if operation.GroupID != operation.TargetGroupID { // 跨分组排序 + if targetGroupView := view.GetGroup(operation.TargetGroupID); nil != targetGroupView { + groupKey := view.GetGroupKey(attrView) + nearItem := getNearItem(attrView, view, targetGroupView, operation.PreviousID) + newValue := getNewValueByNearItem(nearItem, groupKey, operation.ID) + val := attrView.GetValue(groupKey.ID, operation.ID) + newValueRaw := newValue.GetValByType(groupKey.Type) + val.SetValByType(groupKey.Type, newValueRaw) + for i, r := range targetGroupView.GroupItemIDs { + if r == operation.PreviousID { + previousIndex = i + 1 + break + } + } + targetGroupView.GroupItemIDs = util.InsertElem(targetGroupView.GroupItemIDs, previousIndex, itemID) } - val := attrView.GetValue(groupKey.ID, operation.ID) - newValueRaw := newValue.GetValByType(groupKey.Type) - val.SetValByType(groupKey.Type, newValueRaw) - - for i, r := range targetGroupView.GroupItemIDs { + } else { // 同分组内排序 + for i, r := range groupView.GroupItemIDs { if r == operation.PreviousID { previousIndex = i + 1 break } } - targetGroupView.GroupItemIDs = util.InsertElem(targetGroupView.GroupItemIDs, previousIndex, itemID) + groupView.GroupItemIDs = util.InsertElem(groupView.GroupItemIDs, previousIndex, itemID) } } } else { From 99cf9874654905cd63813b4fb271844fd3665598 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 28 Jul 2025 23:10:11 +0800 Subject: [PATCH 4/7] :art: Database grouping by field https://github.com/siyuan-note/siyuan/issues/10964 --- kernel/model/attribute_view.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 1a7e97f8d..5cdee4eb9 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -3030,6 +3030,24 @@ func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, a } else { v.ItemIDs = append([]string{addingBlockID}, v.ItemIDs...) } + + for _, g := range v.Groups { + if "" != previousBlockID { + changed := false + for i, id := range g.GroupItemIDs { + if id == previousBlockID { + g.GroupItemIDs = append(g.GroupItemIDs[:i+1], append([]string{addingBlockID}, g.GroupItemIDs[i+1:]...)...) + changed = true + break + } + } + if !changed { + g.GroupItemIDs = append(g.GroupItemIDs, addingBlockID) + } + } else { + g.GroupItemIDs = append([]string{addingBlockID}, g.GroupItemIDs...) + } + } } // 如果存在分组条件,则将分组条件应用到新添加的块上 @@ -3159,7 +3177,7 @@ func removeAttributeViewBlock(srcIDs []string, avID string, tx *Transaction) (er for _, groupView := range view.Groups { for _, blockID := range srcIDs { - groupView.ItemIDs = gulu.Str.RemoveElem(groupView.ItemIDs, blockID) + groupView.GroupItemIDs = gulu.Str.RemoveElem(groupView.GroupItemIDs, blockID) } } } From 155b2de26092cf04c671874d9ecef13de306016a Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 28 Jul 2025 23:28:57 +0800 Subject: [PATCH 5/7] :art: Database grouping by field https://github.com/siyuan-note/siyuan/issues/10964 --- kernel/model/attribute_view.go | 8 +++++--- kernel/model/transaction.go | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 5cdee4eb9..11a139036 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -1514,7 +1514,7 @@ func renderAttributeView(attrView *av.AttributeView, blockID, viewID, query stri if isGroupByDate(view) { updatedDate := time.UnixMilli(view.GroupUpdated).Format("2006-01-02") if time.Now().Format("2006-01-02") != updatedDate { - genAttrViewViewGroups(view, attrView) + regenAttrViewViewGroups(attrView, "force") av.SaveAttributeView(attrView) } @@ -4562,8 +4562,10 @@ func regenAttrViewViewGroups(attrView *av.AttributeView, keyID string) { continue } - if av.KeyTypeTemplate != groupKey.Type && view.Group.Field != keyID { - continue + if "force" != keyID { + if av.KeyTypeTemplate != groupKey.Type && view.Group.Field != keyID { + continue + } } genAttrViewViewGroups(view, attrView) diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index 6d53042d3..a9a0aff78 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -1539,6 +1539,12 @@ func upsertAvBlockRel(node *ast.Node) { affectedAvIDs = append(affectedAvIDs, relatedAvIDs...) affectedAvIDs = gulu.Str.RemoveDuplicatedElem(affectedAvIDs) for _, avID := range affectedAvIDs { + attrView, _ := av.ParseAttributeView(avID) + if nil != attrView { + regenAttrViewViewGroups(attrView, "force") + av.SaveAttributeView(attrView) + } + ReloadAttrView(avID) } }() From 396450a2ec999965fbd87297c5a93a81500f85a8 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 28 Jul 2025 23:39:00 +0800 Subject: [PATCH 6/7] :art: Database grouping by field https://github.com/siyuan-note/siyuan/issues/10964 --- kernel/model/attribute_view.go | 5 ++++- kernel/model/transaction.go | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 11a139036..9406315e8 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -4936,8 +4936,11 @@ func setAttributeViewColumnOptionDesc(operation *Operation) (err error) { } func getAttrViewViewByBlockID(attrView *av.AttributeView, blockID string) (ret *av.View, err error) { - node, _, _ := getNodeByBlockID(nil, blockID) var viewID string + var node *ast.Node + if "" != blockID { + node, _, _ = getNodeByBlockID(nil, blockID) + } if nil != node { viewID = node.IALAttr(av.NodeAttrView) } diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index a9a0aff78..0734a05eb 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -1006,6 +1006,7 @@ func syncDelete2AttributeView(node *ast.Node) (changedAvIDs []string) { } if changedAv { + regenAttrViewViewGroups(attrView, "force") av.SaveAttributeView(attrView) changedAvIDs = append(changedAvIDs, avID) } From 7906e8f516ebe35a9af93f59a64decffea59317a Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 28 Jul 2025 23:48:24 +0800 Subject: [PATCH 7/7] :art: Database grouping by field https://github.com/siyuan-note/siyuan/issues/10964 --- kernel/model/attribute_view.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 9406315e8..56bf2f7a8 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -1569,12 +1569,14 @@ func genAttrViewViewGroups(view *av.View, attrView *av.AttributeView) { type GroupState struct { Folded bool Hidden int + Sort int } groupStates := map[string]*GroupState{} - for _, groupView := range view.Groups { + for i, groupView := range view.Groups { groupStates[groupView.Name] = &GroupState{ Folded: groupView.GroupFolded, Hidden: groupView.GroupHidden, + Sort: i, } } @@ -1730,7 +1732,7 @@ func genAttrViewViewGroups(view *av.View, attrView *av.AttributeView) { view.GroupUpdated = time.Now().UnixMilli() - // 则恢复分组视图状态 + // 恢复分组视图状态 for _, groupView := range view.Groups { if state, ok := groupStates[groupView.Name]; ok { groupView.GroupFolded = state.Folded @@ -1738,6 +1740,18 @@ func genAttrViewViewGroups(view *av.View, attrView *av.AttributeView) { } } + // 恢复分组视图的顺序 + if len(groupStates) > 0 { + sort.SliceStable(view.Groups, func(i, j int) bool { + if stateI, ok := groupStates[view.Groups[i].Name]; ok { + if stateJ, ok := groupStates[view.Groups[j].Name]; ok { + return stateI.Sort < stateJ.Sort + } + } + return false + }) + } + if av.GroupOrderMan != view.Group.Order { sort.SliceStable(view.Groups, func(i, j int) bool { iName, jName := view.Groups[i].Name, view.Groups[j].Name