diff --git a/app/src/protyle/render/av/action.ts b/app/src/protyle/render/av/action.ts index ced946a1c..77fc6bd30 100644 --- a/app/src/protyle/render/av/action.ts +++ b/app/src/protyle/render/av/action.ts @@ -4,7 +4,8 @@ import {transaction} from "../../wysiwyg/transaction"; import {openEditorTab} from "../../../menus/util"; import {openFileAttr} from "../../../menus/commonMenuItem"; import { - addDragFill, cellValueIsEmpty, + addDragFill, + cellValueIsEmpty, genCellValueByElement, getCellText, getTypeByCellElement, @@ -603,7 +604,6 @@ export const avContextmenu = (protyle: IProtyle, rowElement: HTMLElement, positi transaction(protyle, [{ action: "insertAttrViewBlock", avID, - ignoreFillFilter: true, srcs, blockID: listItemElement.dataset.blockId, groupID: rowElement.parentElement.getAttribute("data-group-id") diff --git a/app/src/protyle/render/av/addToDatabase.ts b/app/src/protyle/render/av/addToDatabase.ts index 060f86861..a611a7846 100644 --- a/app/src/protyle/render/av/addToDatabase.ts +++ b/app/src/protyle/render/av/addToDatabase.ts @@ -21,7 +21,6 @@ export const addFilesToDatabase = (fileLiElements: Element[]) => { transaction(undefined, [{ action: "insertAttrViewBlock", avID, - ignoreFillFilter: true, srcs, blockID: listItemElement.dataset.blockId }, { @@ -40,7 +39,6 @@ export const addEditorToDatabase = (protyle: IProtyle, range: Range, type?: stri transaction(protyle, [{ action: "insertAttrViewBlock", avID, - ignoreFillFilter: true, srcs: [{ id: protyle.block.rootID, isDetached: false @@ -91,7 +89,6 @@ export const addEditorToDatabase = (protyle: IProtyle, range: Range, type?: stri transaction(protyle, [{ action: "insertAttrViewBlock", avID, - ignoreFillFilter: true, srcs, blockID: listItemElement.dataset.blockId }, { diff --git a/app/src/protyle/render/av/relation.ts b/app/src/protyle/render/av/relation.ts index d9aeaf6c0..c6e993a7f 100644 --- a/app/src/protyle/render/av/relation.ts +++ b/app/src/protyle/render/av/relation.ts @@ -423,7 +423,6 @@ draggable="true">${genSelectItemHTML("selected", targetId, !target.querySelector const bodyElement = hasClosestByClassName(cellElements[0], "av__body"); transaction(protyle, [{ action: "insertAttrViewBlock", - ignoreFillFilter: true, avID: menuElement.firstElementChild.getAttribute("data-av-id"), srcs: [{ id: rowId, diff --git a/app/src/types/index.d.ts b/app/src/types/index.d.ts index fac4dfc6e..62b08eed3 100644 --- a/app/src/types/index.d.ts +++ b/app/src/types/index.d.ts @@ -543,7 +543,6 @@ interface IOperation { retData?: any nextID?: string // insert 专享 isDetached?: boolean // insertAttrViewBlock 专享 - ignoreFillFilter?: boolean // insertAttrViewBlock 专享 srcIDs?: string[] // removeAttrViewBlock 专享 srcs?: IOperationSrcs[] // insertAttrViewBlock 专享 name?: string // addAttrViewCol 专享 diff --git a/kernel/api/av.go b/kernel/api/av.go index 5b1d7dbe2..a2c337219 100644 --- a/kernel/api/av.go +++ b/kernel/api/av.go @@ -48,8 +48,12 @@ func getAttributeViewAddingBlockDefaultValues(c *gin.Context) { if nil != arg["previousID"] { previousID = arg["previousID"].(string) } + var addingBlockID string + if nil != arg["addingBlockID"] { + addingBlockID = arg["addingBlockID"].(string) + } - ret.Data = model.GetAttrViewAddingBlockDefaultValues(avID, viewID, groupID, previousID) + ret.Data = model.GetAttrViewAddingBlockDefaultValues(avID, viewID, groupID, previousID, addingBlockID) } func batchReplaceAttributeViewBlocks(c *gin.Context) { @@ -329,17 +333,13 @@ func addAttributeViewBlocks(c *gin.Context) { if nil != arg["previousID"] { previousID = arg["previousID"].(string) } - ignoreFillFilter := true - if nil != arg["ignoreFillFilter"] { - ignoreFillFilter = arg["ignoreFillFilter"].(bool) - } var srcs []map[string]interface{} for _, v := range arg["srcs"].([]interface{}) { src := v.(map[string]interface{}) srcs = append(srcs, src) } - err := model.AddAttributeViewBlock(nil, srcs, avID, blockID, groupID, previousID, ignoreFillFilter) + err := model.AddAttributeViewBlock(nil, srcs, avID, blockID, groupID, previousID) if err != nil { ret.Code = -1 ret.Msg = err.Error() diff --git a/kernel/av/filter.go b/kernel/av/filter.go index b680b1f5c..7cba746cb 100644 --- a/kernel/av/filter.go +++ b/kernel/av/filter.go @@ -829,7 +829,7 @@ func calcRelativeTimeRegion(count int, unit RelativeDateUnit, direction Relative return } -func (filter *ViewFilter) GetAffectValue(key *Key, defaultVal *Value) (ret *Value) { +func (filter *ViewFilter) GetAffectValue(key *Key, defaultVal *Value, addingBlockID string) (ret *Value) { if nil != filter.Value { if KeyTypeRelation == filter.Value.Type || KeyTypeTemplate == filter.Value.Type || KeyTypeRollup == filter.Value.Type || KeyTypeUpdated == filter.Value.Type || KeyTypeCreated == filter.Value.Type { // 所有生成的数据都不设置默认值 @@ -854,6 +854,9 @@ func (filter *ViewFilter) GetAffectValue(key *Key, defaultVal *Value) (ret *Valu } ret = filter.Value.Clone() + ret.ID = ast.NewNodeID() + ret.KeyID = key.ID + ret.BlockID = addingBlockID ret.CreatedAt = util.CurrentTimeMillis() ret.UpdatedAt = ret.CreatedAt + 1000 diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index e695db6fe..38c669c73 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -44,7 +44,7 @@ import ( "github.com/xrash/smetrics" ) -func GetAttrViewAddingBlockDefaultValues(avID, viewID, groupID, previousBlockID string) (ret map[string]*av.Value) { +func GetAttrViewAddingBlockDefaultValues(avID, viewID, groupID, previousBlockID, addingBlockID string) (ret map[string]*av.Value) { ret = map[string]*av.Value{} attrView, err := av.ParseAttributeView(avID) @@ -67,10 +67,10 @@ func GetAttrViewAddingBlockDefaultValues(avID, viewID, groupID, previousBlockID logging.LogErrorf("group [%s] not found in view [%s] of attribute view [%s]", groupID, viewID, avID) return } - return getAttrViewAddingBlockDefaultValues(attrView, view, groupView, previousBlockID) + return getAttrViewAddingBlockDefaultValues(attrView, view, groupView, previousBlockID, addingBlockID) } -func getAttrViewAddingBlockDefaultValues(attrView *av.AttributeView, view, groupView *av.View, previousBlockID string) (ret map[string]*av.Value) { +func getAttrViewAddingBlockDefaultValues(attrView *av.AttributeView, view, groupView *av.View, previousBlockID, addingBlockID string) (ret map[string]*av.Value) { ret = map[string]*av.Value{} nearItem := getNearItem(attrView, view, groupView, previousBlockID) @@ -90,7 +90,7 @@ func getAttrViewAddingBlockDefaultValues(attrView *av.AttributeView, view, group defaultVal = nearItem.GetValue(filter.Column) } - newValue := filter.GetAffectValue(keyValues.Key, defaultVal) + newValue := filter.GetAffectValue(keyValues.Key, defaultVal, addingBlockID) if nil != newValue { ret[keyValues.Key.ID] = newValue } @@ -99,13 +99,7 @@ func getAttrViewAddingBlockDefaultValues(attrView *av.AttributeView, view, group groupKey := view.GetGroupKey(attrView) if nil != groupKey && !filterKeyIDs[groupKey.ID] /* 命中了过滤条件的话就不重复处理了 */ { if keyValues, _ := attrView.GetKeyValues(groupKey.ID); nil != keyValues { - newValue := getNewValueByNearItem(nearItem, groupKey, ast.NewNodeID()) - - newValue.ID = ast.NewNodeID() - newValue.CreatedAt = util.CurrentTimeMillis() - newValue.UpdatedAt = newValue.CreatedAt + 1000 - newValue.KeyID = keyValues.Key.ID - + newValue := getNewValueByNearItem(nearItem, groupKey, addingBlockID) if av.KeyTypeSelect == groupKey.Type || av.KeyTypeMSelect == groupKey.Type { // 因为单选或多选只能按选项分组,并且可能存在空白分组(前面可能找不到临近项) ,所以单选或多选类型的分组字段使用分组值内容对应的选项 if opt := groupKey.GetOption(groupView.GroupValue); nil != opt && groupValueDefault != groupView.GroupValue { @@ -3034,14 +3028,14 @@ func setAttributeViewColumnCalc(operation *Operation) (err error) { } func (tx *Transaction) doInsertAttrViewBlock(operation *Operation) (ret *TxErr) { - err := AddAttributeViewBlock(tx, operation.Srcs, operation.AvID, operation.BlockID, operation.GroupID, operation.PreviousID, operation.IgnoreFillFilterVal) + err := AddAttributeViewBlock(tx, operation.Srcs, operation.AvID, operation.BlockID, operation.GroupID, operation.PreviousID) if err != nil { return &TxErr{code: TxErrHandleAttributeView, id: operation.AvID, msg: err.Error()} } return } -func AddAttributeViewBlock(tx *Transaction, srcs []map[string]interface{}, avID, blockID, groupID, previousBlockID string, ignoreFillFilter bool) (err error) { +func AddAttributeViewBlock(tx *Transaction, srcs []map[string]interface{}, avID, blockID, groupID, previousBlockID string) (err error) { slices.Reverse(srcs) // https://github.com/siyuan-note/siyuan/issues/11286 now := time.Now().UnixMilli() @@ -3070,14 +3064,14 @@ func AddAttributeViewBlock(tx *Transaction, srcs []map[string]interface{}, avID, if nil != src["content"] { srcContent = src["content"].(string) } - if avErr := addAttributeViewBlock(now, avID, blockID, groupID, previousBlockID, srcID, srcContent, isDetached, ignoreFillFilter, tree, tx); nil != avErr { + if avErr := addAttributeViewBlock(now, avID, blockID, groupID, previousBlockID, srcID, srcContent, isDetached, tree, tx); nil != avErr { return avErr } } return } -func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, addingBlockID, addingBlockContent string, isDetached, ignoreFillFilter bool, tree *parse.Tree, tx *Transaction) (err error) { +func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, addingBlockID, addingBlockContent string, isDetached bool, tree *parse.Tree, tx *Transaction) (err error) { var node *ast.Node if !isDetached { node = treenode.GetNodeInTree(tree, addingBlockID) @@ -3131,57 +3125,40 @@ func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, a Block: &av.ValueBlock{ID: addingBlockID, Icon: blockIcon, Content: addingBlockContent, Created: now, Updated: now}} blockValues.Values = append(blockValues.Values, blockValue) - view, _ := getAttrViewViewByBlockID(attrView, blockID) // blockID 可能不传,所以这里的 view 可能为空,后面使用需要判空 - var nearItem av.Item // 临近项 - if nil != view && ((0 < len(view.Filters) && !ignoreFillFilter) || "" != groupID) { - // 存在过滤条件或者指定分组视图时,先获取临近项备用 - targetView := view - if "" != groupID { - if groupView := view.GetGroup(groupID); nil != groupView { - targetView = groupView + view, err := getAttrViewViewByBlockID(attrView, blockID) + if nil != err { + logging.LogErrorf("get view by block ID [%s] failed: %s", blockID, err) + return + } + + groupView := view + if "" != groupID { + groupView = view.GetGroup(groupID) + } + + defaultValues := getAttrViewAddingBlockDefaultValues(attrView, view, groupView, previousBlockID, addingBlockID) + for keyID, newValue := range defaultValues { + keyValues, getErr := attrView.GetKeyValues(keyID) + if nil != getErr { + continue + } + + if av.KeyTypeBlock == newValue.Type { + // 如果是主键的话前面已经添加过了,这里仅修改内容 + blockValue.Block.Content = newValue.Block.Content + continue + } + + if (av.KeyTypeSelect == newValue.Type || av.KeyTypeMSelect == newValue.Type) && 1 > len(newValue.MSelect) { + // 单选或多选类型的值可能需要从分组条件中获取默认值 + if opt := keyValues.Key.GetOption(groupView.GroupValue); nil != opt && groupValueDefault != groupView.GroupValue { + newValue.MSelect = append(newValue.MSelect, &av.ValueSelect{Content: opt.Name, Color: opt.Color}) } } - nearItem = getNearItem(attrView, view, targetView, previousBlockID) - } - - filterKeyIDs := map[string]bool{} - if nil != view { - for _, f := range view.Filters { - filterKeyIDs[f.Column] = true - } - } - - // 如果存在过滤条件,则将过滤条件应用到新添加的块上 - if nil != view && 0 < len(view.Filters) && !ignoreFillFilter { - for _, filter := range view.Filters { - for _, keyValues := range attrView.KeyValues { - if keyValues.Key.ID == filter.Column { - var defaultVal *av.Value - if nil != nearItem { - defaultVal = nearItem.GetValue(filter.Column) - } - - newValue := filter.GetAffectValue(keyValues.Key, defaultVal) - if nil == newValue { - continue - } - - if av.KeyTypeBlock == newValue.Type { - // 如果是主键的话前面已经添加过了,这里仅修改内容 - blockValue.Block.Content = newValue.Block.Content - break - } - - newValue.ID = ast.NewNodeID() - newValue.KeyID = keyValues.Key.ID - newValue.BlockID = addingBlockID - newValue.IsDetached = isDetached - keyValues.Values = append(keyValues.Values, newValue) - break - } - } - } + newValue.BlockID = addingBlockID + newValue.IsDetached = isDetached + keyValues.Values = append(keyValues.Values, newValue) } // 处理日期字段默认填充当前创建时间 @@ -3237,37 +3214,8 @@ func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, a } } - // 如果存在分组条件,则将分组条件应用到新添加的块上 groupKey := view.GetGroupKey(attrView) - if nil != view && nil != groupKey { - if !filterKeyIDs[groupKey.ID] /* 过滤条件应用过的话就不重复处理了 */ && "" != groupID { - if groupView := view.GetGroup(groupID); nil != groupView { - if keyValues, _ := attrView.GetKeyValues(groupKey.ID); nil != keyValues { - newValue := getNewValueByNearItem(nearItem, groupKey, blockID) - if av.KeyTypeBlock == newValue.Type { - // 如果是主键的话前面已经添加过了,这里仅修改内容 - blockValue.Block.Content = newValue.Block.Content - } else { - newValue.ID = ast.NewNodeID() - newValue.CreatedAt = util.CurrentTimeMillis() - newValue.UpdatedAt = newValue.CreatedAt + 1000 - newValue.KeyID = keyValues.Key.ID - newValue.BlockID = addingBlockID - newValue.IsDetached = isDetached - - if av.KeyTypeSelect == groupKey.Type || av.KeyTypeMSelect == groupKey.Type { - // 因为单选或多选只能按选项分组,并且可能存在空白分组(前面可能找不到临近项) ,所以单选或多选类型的分组字段使用分组值内容对应的选项 - if opt := groupKey.GetOption(groupView.GroupValue); nil != opt && groupValueDefault != groupView.GroupValue { - newValue.MSelect = append(newValue.MSelect, &av.ValueSelect{Content: opt.Name, Color: opt.Color}) - } - } - - keyValues.Values = append(keyValues.Values, newValue) - } - } - } - } - + if nil != groupKey { regenAttrViewViewGroups(attrView, groupKey.ID) } @@ -3275,15 +3223,18 @@ func addAttributeViewBlock(now int64, avID, blockID, groupID, previousBlockID, a return } -func getNewValueByNearItem(nearItem av.Item, key *av.Key, blockID string) (ret *av.Value) { +func getNewValueByNearItem(nearItem av.Item, key *av.Key, addingBlockID string) (ret *av.Value) { if nil != nearItem { defaultVal := nearItem.GetValue(key.ID) ret = defaultVal.Clone() + ret.ID = ast.NewNodeID() + ret.KeyID = key.ID + ret.BlockID = addingBlockID + ret.CreatedAt = util.CurrentTimeMillis() + ret.UpdatedAt = ret.CreatedAt + 1000 + return } - if nil == ret { - ret = av.GetAttributeViewDefaultValue(ast.NewNodeID(), key.ID, blockID, key.Type) - } - return + return av.GetAttributeViewDefaultValue(ast.NewNodeID(), key.ID, addingBlockID, key.Type) } func getNearItem(attrView *av.AttributeView, view, groupView *av.View, previousItemID string) (ret av.Item) { diff --git a/kernel/model/file.go b/kernel/model/file.go index 41dcb0a4b..bb6594f9b 100644 --- a/kernel/model/file.go +++ b/kernel/model/file.go @@ -986,7 +986,7 @@ func DuplicateDoc(tree *parse.Tree) { AddAttributeViewBlock(nil, []map[string]interface{}{{ "id": n.ID, "isDetached": false, - }}, avID, "", "", "", false) + }}, avID, "", "", "") ReloadAttrView(avID) } return ast.WalkContinue diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index 483c09c16..75cb71d43 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -1099,7 +1099,7 @@ func (tx *Transaction) doLargeInsert(previousID string) (ret *TxErr) { AddAttributeViewBlock(tx, []map[string]interface{}{{ "id": insertedNode.ID, "isDetached": false, - }}, avID, "", "", previousID, false) + }}, avID, "", "", previousID) ReloadAttrView(avID) } @@ -1284,7 +1284,7 @@ func (tx *Transaction) doInsert(operation *Operation) (ret *TxErr) { AddAttributeViewBlock(tx, []map[string]interface{}{{ "id": insertedNode.ID, "isDetached": false, - }}, avID, "", "", previousID, false) + }}, avID, "", "", previousID) ReloadAttrView(avID) } @@ -1712,22 +1712,21 @@ type Operation struct { DeckID string `json:"deckID"` // 用于添加/删除闪卡 - AvID string `json:"avID"` // 属性视图 ID - SrcIDs []string `json:"srcIDs"` // 用于从属性视图中删除行 - Srcs []map[string]interface{} `json:"srcs"` // 用于添加属性视图行(包括绑定块){id, content, isDetached} - IsDetached bool `json:"isDetached"` // 用于标识是否未绑定块,仅存在于属性视图中 - IgnoreFillFilterVal bool `json:"ignoreFillFilter"` // 用于标识是否忽略填充筛选值 - Name string `json:"name"` // 属性视图列名 - Typ string `json:"type"` // 属性视图列类型 - Format string `json:"format"` // 属性视图列格式化 - KeyID string `json:"keyID"` // 属性视图字段 ID - RowID string `json:"rowID"` // 属性视图行 ID - IsTwoWay bool `json:"isTwoWay"` // 属性视图关联列是否是双向关系 - BackRelationKeyID string `json:"backRelationKeyID"` // 属性视图关联列回链关联列的 ID - RemoveDest bool `json:"removeDest"` // 属性视图删除关联目标 - Layout av.LayoutType `json:"layout"` // 属性视图布局类型 - GroupID string `json:"groupID"` // 属性视图分组视图 ID - TargetGroupID string `json:"targetGroupID"` // 属性视图目标分组视图 ID + AvID string `json:"avID"` // 属性视图 ID + SrcIDs []string `json:"srcIDs"` // 用于从属性视图中删除行 + Srcs []map[string]interface{} `json:"srcs"` // 用于添加属性视图行(包括绑定块){id, content, isDetached} + IsDetached bool `json:"isDetached"` // 用于标识是否未绑定块,仅存在于属性视图中 + Name string `json:"name"` // 属性视图列名 + Typ string `json:"type"` // 属性视图列类型 + Format string `json:"format"` // 属性视图列格式化 + KeyID string `json:"keyID"` // 属性视图字段 ID + RowID string `json:"rowID"` // 属性视图行 ID + IsTwoWay bool `json:"isTwoWay"` // 属性视图关联列是否是双向关系 + BackRelationKeyID string `json:"backRelationKeyID"` // 属性视图关联列回链关联列的 ID + RemoveDest bool `json:"removeDest"` // 属性视图删除关联目标 + Layout av.LayoutType `json:"layout"` // 属性视图布局类型 + GroupID string `json:"groupID"` // 属性视图分组视图 ID + TargetGroupID string `json:"targetGroupID"` // 属性视图目标分组视图 ID } type Transaction struct {