Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Vanessa 2023-12-30 17:41:46 +08:00
commit 521b9afefd
6 changed files with 251 additions and 23 deletions

View file

@ -267,6 +267,12 @@ func SaveAttributeView(av *AttributeView) (err error) {
}
}
}
for _, v := range kv.Values {
if "" == v.KeyID {
v.KeyID = kv.Key.ID
}
}
}
// 数据订正

View file

@ -16,6 +16,11 @@
package av
import (
"github.com/siyuan-note/siyuan/kernel/util"
"strings"
)
type Filterable interface {
FilterRows()
}
@ -46,3 +51,197 @@ const (
FilterOperatorIsTrue FilterOperator = "Is true"
FilterOperatorIsFalse FilterOperator = "Is false"
)
func (filter *ViewFilter) GetAffectValue(key *Key) (ret *Value) {
// Improve adding rows of the filtered database table view https://github.com/siyuan-note/siyuan/issues/10025
ret = filter.Value.Clone()
switch filter.Value.Type {
case KeyTypeBlock:
switch filter.Operator {
case FilterOperatorIsEqual:
ret.Block = &ValueBlock{ID: filter.Value.Block.ID, Content: filter.Value.Block.Content}
case FilterOperatorIsNotEqual:
ret.Block = &ValueBlock{ID: filter.Value.Block.ID, Content: strings.TrimSpace(filter.Value.Block.Content + " Untitled")}
case FilterOperatorContains:
ret.Block = &ValueBlock{ID: filter.Value.Block.ID, Content: filter.Value.Block.Content}
case FilterOperatorDoesNotContain:
ret.Block = &ValueBlock{ID: filter.Value.Block.ID, Content: strings.ReplaceAll("Untitled", filter.Value.Block.Content, "")}
case FilterOperatorStartsWith:
ret.Block = &ValueBlock{ID: filter.Value.Block.ID, Content: filter.Value.Block.Content}
case FilterOperatorEndsWith:
ret.Block = &ValueBlock{ID: filter.Value.Block.ID, Content: filter.Value.Block.Content}
case FilterOperatorIsEmpty:
ret.Block = &ValueBlock{ID: filter.Value.Block.ID, Content: ""}
case FilterOperatorIsNotEmpty:
ret.Block = &ValueBlock{ID: filter.Value.Block.ID, Content: "Untitled"}
}
case KeyTypeText:
switch filter.Operator {
case FilterOperatorIsEqual:
ret.Text = &ValueText{Content: filter.Value.Text.Content}
case FilterOperatorIsNotEqual:
ret.Text = &ValueText{Content: strings.TrimSpace(filter.Value.Text.Content + " Untitled")}
case FilterOperatorContains:
ret.Text = &ValueText{Content: filter.Value.Text.Content}
case FilterOperatorDoesNotContain:
ret.Text = &ValueText{Content: strings.ReplaceAll("Untitled", filter.Value.Text.Content, "")}
case FilterOperatorStartsWith:
ret.Text = &ValueText{Content: filter.Value.Text.Content}
case FilterOperatorEndsWith:
ret.Text = &ValueText{Content: filter.Value.Text.Content}
case FilterOperatorIsEmpty:
ret.Text = &ValueText{Content: ""}
case FilterOperatorIsNotEmpty:
ret.Text = &ValueText{Content: "Untitled"}
}
case KeyTypeNumber:
switch filter.Operator {
case FilterOperatorIsEqual:
ret.Number = &ValueNumber{Content: filter.Value.Number.Content, IsNotEmpty: false}
case FilterOperatorIsNotEqual:
if 0 == filter.Value.Number.Content {
ret.Number = &ValueNumber{Content: 1, IsNotEmpty: true}
} else {
ret.Number = &ValueNumber{Content: 0, IsNotEmpty: true}
}
case FilterOperatorIsGreater:
ret.Number = &ValueNumber{Content: filter.Value.Number.Content + 1, IsNotEmpty: true}
case FilterOperatorIsGreaterOrEqual:
ret.Number = &ValueNumber{Content: filter.Value.Number.Content, IsNotEmpty: true}
case FilterOperatorIsLess:
ret.Number = &ValueNumber{Content: filter.Value.Number.Content - 1, IsNotEmpty: true}
case FilterOperatorIsLessOrEqual:
ret.Number = &ValueNumber{Content: filter.Value.Number.Content, IsNotEmpty: true}
case FilterOperatorIsEmpty:
ret.Number = &ValueNumber{Content: 0, IsNotEmpty: false}
case FilterOperatorIsNotEmpty:
ret.Number = &ValueNumber{Content: 0, IsNotEmpty: true}
}
case KeyTypeDate:
switch filter.Operator {
case FilterOperatorIsEqual:
ret.Date = &ValueDate{Content: filter.Value.Date.Content, IsNotEmpty: true}
case FilterOperatorIsNotEqual:
ret.Date = &ValueDate{Content: util.CurrentTimeMillis(), IsNotEmpty: true}
case FilterOperatorIsGreater:
ret.Date = &ValueDate{Content: filter.Value.Date.Content + 1000*60, IsNotEmpty: true}
case FilterOperatorIsGreaterOrEqual:
ret.Date = &ValueDate{Content: filter.Value.Date.Content, IsNotEmpty: true}
case FilterOperatorIsLess:
ret.Date = &ValueDate{Content: filter.Value.Date.Content - 1000*60, IsNotEmpty: true}
case FilterOperatorIsLessOrEqual:
ret.Date = &ValueDate{Content: filter.Value.Date.Content, IsNotEmpty: true}
case FilterOperatorIsBetween:
ret.Date = &ValueDate{Content: filter.Value.Date.Content - 1000*60, IsNotEmpty: true}
case FilterOperatorIsEmpty:
ret.Date = &ValueDate{Content: 0, IsNotEmpty: false}
case FilterOperatorIsNotEmpty:
ret.Date = &ValueDate{Content: util.CurrentTimeMillis(), IsNotEmpty: true}
}
case KeyTypeMSelect:
switch filter.Operator {
case FilterOperatorIsEqual, FilterOperatorContains:
if 0 < len(filter.Value.MSelect) {
ret.MSelect = []*ValueSelect{{Content: filter.Value.MSelect[0].Content, Color: filter.Value.MSelect[0].Color}}
}
case FilterOperatorIsNotEqual, FilterOperatorDoesNotContain:
if 0 < len(filter.Value.MSelect) {
ret.MSelect = []*ValueSelect{{Content: filter.Value.MSelect[0].Content + " Untitled", Color: "1"}}
}
case FilterOperatorIsEmpty:
ret.MSelect = []*ValueSelect{}
case FilterOperatorIsNotEmpty:
if 0 < len(key.Options) {
ret.MSelect = []*ValueSelect{{Content: key.Options[0].Name, Color: key.Options[0].Color}}
}
}
case KeyTypeURL:
switch filter.Operator {
case FilterOperatorIsEqual:
ret.URL = &ValueURL{Content: filter.Value.URL.Content}
case FilterOperatorIsNotEqual:
ret.URL = &ValueURL{Content: filter.Value.URL.Content + " Untitled"}
case FilterOperatorContains:
ret.URL = &ValueURL{Content: filter.Value.URL.Content}
case FilterOperatorDoesNotContain:
ret.URL = &ValueURL{Content: strings.ReplaceAll("Untitled", filter.Value.URL.Content, "")}
case FilterOperatorStartsWith:
ret.URL = &ValueURL{Content: filter.Value.URL.Content}
case FilterOperatorEndsWith:
ret.URL = &ValueURL{Content: filter.Value.URL.Content}
case FilterOperatorIsEmpty:
ret.URL = &ValueURL{Content: ""}
case FilterOperatorIsNotEmpty:
ret.URL = &ValueURL{Content: "Untitled"}
}
case KeyTypeEmail:
switch filter.Operator {
case FilterOperatorIsEqual:
ret.Email = &ValueEmail{Content: filter.Value.Email.Content}
case FilterOperatorIsNotEqual:
ret.Email = &ValueEmail{Content: filter.Value.Email.Content + " Untitled"}
case FilterOperatorContains:
ret.Email = &ValueEmail{Content: filter.Value.Email.Content}
case FilterOperatorDoesNotContain:
ret.Email = &ValueEmail{Content: strings.ReplaceAll("Untitled", filter.Value.Email.Content, "")}
case FilterOperatorStartsWith:
ret.Email = &ValueEmail{Content: filter.Value.Email.Content}
case FilterOperatorEndsWith:
ret.Email = &ValueEmail{Content: filter.Value.Email.Content}
case FilterOperatorIsEmpty:
ret.Email = &ValueEmail{Content: ""}
case FilterOperatorIsNotEmpty:
ret.Email = &ValueEmail{Content: "Untitled"}
}
case KeyTypePhone:
switch filter.Operator {
case FilterOperatorIsEqual:
ret.Phone = &ValuePhone{Content: filter.Value.Phone.Content}
case FilterOperatorIsNotEqual:
ret.Phone = &ValuePhone{Content: filter.Value.Phone.Content + " Untitled"}
case FilterOperatorContains:
ret.Phone = &ValuePhone{Content: filter.Value.Phone.Content}
case FilterOperatorDoesNotContain:
ret.Phone = &ValuePhone{Content: strings.ReplaceAll("Untitled", filter.Value.Phone.Content, "")}
case FilterOperatorStartsWith:
ret.Phone = &ValuePhone{Content: filter.Value.Phone.Content}
case FilterOperatorEndsWith:
ret.Phone = &ValuePhone{Content: filter.Value.Phone.Content}
case FilterOperatorIsEmpty:
ret.Phone = &ValuePhone{Content: ""}
case FilterOperatorIsNotEmpty:
ret.Phone = &ValuePhone{Content: "Untitled"}
}
case KeyTypeMAsset:
switch filter.Operator {
case FilterOperatorIsEqual, FilterOperatorContains:
if 0 < len(filter.Value.MAsset) {
ret.MAsset = []*ValueAsset{{Type: filter.Value.MAsset[0].Type, Name: filter.Value.MAsset[0].Name, Content: filter.Value.MAsset[0].Content}}
}
case FilterOperatorIsNotEqual, FilterOperatorDoesNotContain:
case FilterOperatorIsEmpty:
ret.MAsset = []*ValueAsset{}
case FilterOperatorIsNotEmpty:
}
case KeyTypeCheckbox:
switch filter.Operator {
case FilterOperatorIsTrue:
ret.Checkbox = &ValueCheckbox{Checked: true}
case FilterOperatorIsFalse:
ret.Checkbox = &ValueCheckbox{Checked: false}
}
case KeyTypeRelation:
switch filter.Operator {
case FilterOperatorContains:
if 0 < len(filter.Value.Relation.Contents) {
ret.Relation = &ValueRelation{Contents: filter.Value.Relation.Contents}
}
case FilterOperatorDoesNotContain:
case FilterOperatorIsEmpty:
ret.Relation = &ValueRelation{Contents: []string{}}
case FilterOperatorIsNotEmpty:
}
}
return
}

View file

@ -762,12 +762,6 @@ func (table *Table) FilterRows() {
rows := []*TableRow{}
for _, row := range table.Rows {
block := row.GetBlockValue()
if nil != block && block.NotAffectFilter() {
rows = append(rows, row)
continue
}
pass := true
for j, index := range colIndexes {
operator := table.Filters[j].Operator

View file

@ -30,12 +30,11 @@ import (
)
type Value struct {
ID string `json:"id,omitempty"`
KeyID string `json:"keyID,omitempty"`
BlockID string `json:"blockID,omitempty"`
Type KeyType `json:"type,omitempty"`
IsDetached bool `json:"isDetached,omitempty"`
IsInitialized bool `json:"isInitialized,omitempty"`
ID string `json:"id,omitempty"`
KeyID string `json:"keyID,omitempty"`
BlockID string `json:"blockID,omitempty"`
Type KeyType `json:"type,omitempty"`
IsDetached bool `json:"isDetached,omitempty"`
Block *ValueBlock `json:"block,omitempty"`
Text *ValueText `json:"text,omitempty"`
@ -54,10 +53,6 @@ type Value struct {
Rollup *ValueRollup `json:"rollup,omitempty"`
}
func (value *Value) NotAffectFilter() bool {
return !value.IsInitialized && nil != value.Block && "" == value.Block.Content && value.IsDetached
}
func (value *Value) String() string {
switch value.Type {
case KeyTypeBlock:

View file

@ -742,6 +742,10 @@ func renderAttributeViewTable(attrView *av.AttributeView, view *av.View) (ret *a
tableCell.Value = &av.Value{ID: tableCell.ID, KeyID: col.ID, BlockID: rowID, Type: av.KeyTypeCreated}
case av.KeyTypeUpdated: // 填充更新时间列值,后面再渲染
tableCell.Value = &av.Value{ID: tableCell.ID, KeyID: col.ID, BlockID: rowID, Type: av.KeyTypeUpdated}
case av.KeyTypeRelation: // 清空关联列值,后面再渲染 https://ld246.com/article/1703831044435
if nil != tableCell.Value && nil != tableCell.Value.Relation {
tableCell.Value.Relation.Contents = nil
}
}
treenode.FillAttributeViewTableCellNilValue(tableCell, rowID, col.ID)
@ -897,9 +901,18 @@ func updateAttributeViewColRollup(operation *Operation) (err error) {
KeyID: operation.KeyID,
}
if "" != operation.Data {
if err = gulu.JSON.UnmarshalJSON([]byte(operation.Data.(string)), &rollUpKey.Rollup.Calc); nil != err {
return
if nil != operation.Data && "" != operation.Data.(string) {
data := operation.Data.(map[string]interface{})
if nil != data["calc"] {
calcData, jsonErr := gulu.JSON.MarshalJSON(data["calc"])
if nil != jsonErr {
err = jsonErr
return
}
if jsonErr = gulu.JSON.UnmarshalJSON(calcData, &rollUpKey.Rollup.Calc); nil != jsonErr {
err = jsonErr
return
}
}
}
@ -1485,7 +1498,7 @@ func addAttributeViewBlock(blockID string, operation *Operation, tree *parse.Tre
content = getNodeRefText(node)
}
now := time.Now().UnixMilli()
blockValue := &av.Value{ID: ast.NewNodeID(), KeyID: blockValues.Key.ID, BlockID: blockID, Type: av.KeyTypeBlock, IsDetached: operation.IsDetached, IsInitialized: false, Block: &av.ValueBlock{ID: blockID, Content: content, Created: now, Updated: now}}
blockValue := &av.Value{ID: ast.NewNodeID(), KeyID: blockValues.Key.ID, BlockID: blockID, Type: av.KeyTypeBlock, IsDetached: operation.IsDetached, Block: &av.ValueBlock{ID: blockID, Content: content, Created: now, Updated: now}}
blockValues.Values = append(blockValues.Values, blockValue)
// 如果存在过滤条件,则将过滤条件应用到新添加的块上
@ -1495,6 +1508,7 @@ func addAttributeViewBlock(blockID string, operation *Operation, tree *parse.Tre
viewable.FilterRows()
viewable.SortRows()
addedVal := false
if 0 < len(viewable.Rows) {
row := GetLastSortRow(viewable.Rows)
if nil != row {
@ -1510,12 +1524,29 @@ func addAttributeViewBlock(blockID string, operation *Operation, tree *parse.Tre
newValue.ID = ast.NewNodeID()
newValue.BlockID = blockID
newValue.IsDetached = operation.IsDetached
newValue.IsInitialized = false
values, _ := attrView.GetKeyValues(filter.Column)
values.Values = append(values.Values, newValue)
break
}
}
}
addedVal = true
}
}
if !addedVal {
for _, filter := range view.Table.Filters {
for _, keyValues := range attrView.KeyValues {
if keyValues.Key.ID == filter.Column {
newValue := filter.GetAffectValue(keyValues.Key)
newValue.ID = ast.NewNodeID()
newValue.KeyID = keyValues.Key.ID
newValue.BlockID = blockID
newValue.IsDetached = operation.IsDetached
keyValues.Values = append(keyValues.Values, newValue)
break
}
}
}
}
}
@ -1566,7 +1597,7 @@ func GetLastSortRow(rows []*av.TableRow) *av.TableRow {
for i := len(rows) - 1; i >= 0; i-- {
row := rows[i]
block := row.GetBlockValue()
if nil != block && !block.NotAffectFilter() {
if nil != block {
return row
}
}
@ -2291,7 +2322,6 @@ func UpdateAttributeViewCell(tx *Transaction, avID, keyID, rowID, cellID string,
if nil != blockVal {
blockVal.Block.Updated = time.Now().UnixMilli()
blockVal.IsInitialized = true
if isUpdatingBlockKey {
blockVal.IsDetached = val.IsDetached
}

View file

@ -698,6 +698,10 @@ func renderAttributeViewTable(attrView *av.AttributeView, view *av.View) (ret *a
tableCell.Value = &av.Value{ID: tableCell.ID, KeyID: col.ID, BlockID: rowID, Type: av.KeyTypeCreated}
case av.KeyTypeUpdated: // 填充更新时间列值,后面再渲染
tableCell.Value = &av.Value{ID: tableCell.ID, KeyID: col.ID, BlockID: rowID, Type: av.KeyTypeUpdated}
case av.KeyTypeRelation: // 清空关联列值,后面再渲染 https://ld246.com/article/1703831044435
if nil != tableCell.Value && nil != tableCell.Value.Relation {
tableCell.Value.Relation.Contents = nil
}
}
FillAttributeViewTableCellNilValue(tableCell, rowID, col.ID)