mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-17 07:00:12 +01:00
🎨 Improve adding rows of the filtered database table view https://github.com/siyuan-note/siyuan/issues/10025
This commit is contained in:
parent
2db7c5167d
commit
76dd5a2d28
4 changed files with 228 additions and 24 deletions
|
|
@ -16,6 +16,11 @@
|
||||||
|
|
||||||
package av
|
package av
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/siyuan-note/siyuan/kernel/util"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type Filterable interface {
|
type Filterable interface {
|
||||||
FilterRows()
|
FilterRows()
|
||||||
}
|
}
|
||||||
|
|
@ -46,3 +51,195 @@ const (
|
||||||
FilterOperatorIsTrue FilterOperator = "Is true"
|
FilterOperatorIsTrue FilterOperator = "Is true"
|
||||||
FilterOperatorIsFalse FilterOperator = "Is false"
|
FilterOperatorIsFalse FilterOperator = "Is false"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (filter *ViewFilter) GetAffectValue(key *Key) (ret *Value) {
|
||||||
|
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.TrimSpace(filter.Value.Block.Content + " Untitled")}
|
||||||
|
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.TrimSpace(filter.Value.Text.Content + " Untitled")}
|
||||||
|
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}}
|
||||||
|
}
|
||||||
|
case FilterOperatorIsNotEqual, FilterOperatorDoesNotContain:
|
||||||
|
if 0 < len(filter.Value.MSelect) {
|
||||||
|
ret.MSelect = []*ValueSelect{{Content: filter.Value.MSelect[0].Content + " Untitled"}}
|
||||||
|
}
|
||||||
|
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: filter.Value.URL.Content + " Untitled"}
|
||||||
|
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: filter.Value.Email.Content + " Untitled"}
|
||||||
|
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: filter.Value.Phone.Content + " Untitled"}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -762,12 +762,6 @@ func (table *Table) FilterRows() {
|
||||||
|
|
||||||
rows := []*TableRow{}
|
rows := []*TableRow{}
|
||||||
for _, row := range table.Rows {
|
for _, row := range table.Rows {
|
||||||
block := row.GetBlockValue()
|
|
||||||
if nil != block && block.NotAffectFilter() {
|
|
||||||
rows = append(rows, row)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pass := true
|
pass := true
|
||||||
for j, index := range colIndexes {
|
for j, index := range colIndexes {
|
||||||
operator := table.Filters[j].Operator
|
operator := table.Filters[j].Operator
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Value struct {
|
type Value struct {
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
KeyID string `json:"keyID,omitempty"`
|
KeyID string `json:"keyID,omitempty"`
|
||||||
BlockID string `json:"blockID,omitempty"`
|
BlockID string `json:"blockID,omitempty"`
|
||||||
Type KeyType `json:"type,omitempty"`
|
Type KeyType `json:"type,omitempty"`
|
||||||
IsDetached bool `json:"isDetached,omitempty"`
|
IsDetached bool `json:"isDetached,omitempty"`
|
||||||
IsInitialized bool `json:"isInitialized,omitempty"`
|
|
||||||
|
|
||||||
Block *ValueBlock `json:"block,omitempty"`
|
Block *ValueBlock `json:"block,omitempty"`
|
||||||
Text *ValueText `json:"text,omitempty"`
|
Text *ValueText `json:"text,omitempty"`
|
||||||
|
|
@ -54,10 +53,6 @@ type Value struct {
|
||||||
Rollup *ValueRollup `json:"rollup,omitempty"`
|
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 {
|
func (value *Value) String() string {
|
||||||
switch value.Type {
|
switch value.Type {
|
||||||
case KeyTypeBlock:
|
case KeyTypeBlock:
|
||||||
|
|
|
||||||
|
|
@ -901,10 +901,13 @@ func updateAttributeViewColRollup(operation *Operation) (err error) {
|
||||||
KeyID: operation.KeyID,
|
KeyID: operation.KeyID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if "" != operation.Data {
|
data := operation.Data.(map[string]interface{})
|
||||||
if err = gulu.JSON.UnmarshalJSON([]byte(operation.Data.(string)), &rollUpKey.Rollup.Calc); nil != err {
|
calcData, err := gulu.JSON.MarshalJSON(data["calc"])
|
||||||
return
|
if nil != err {
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
if err = gulu.JSON.UnmarshalJSON(calcData, &rollUpKey.Rollup.Calc); nil != err {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = av.SaveAttributeView(attrView)
|
err = av.SaveAttributeView(attrView)
|
||||||
|
|
@ -1489,7 +1492,7 @@ func addAttributeViewBlock(blockID string, operation *Operation, tree *parse.Tre
|
||||||
content = getNodeRefText(node)
|
content = getNodeRefText(node)
|
||||||
}
|
}
|
||||||
now := time.Now().UnixMilli()
|
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)
|
blockValues.Values = append(blockValues.Values, blockValue)
|
||||||
|
|
||||||
// 如果存在过滤条件,则将过滤条件应用到新添加的块上
|
// 如果存在过滤条件,则将过滤条件应用到新添加的块上
|
||||||
|
|
@ -1499,6 +1502,7 @@ func addAttributeViewBlock(blockID string, operation *Operation, tree *parse.Tre
|
||||||
viewable.FilterRows()
|
viewable.FilterRows()
|
||||||
viewable.SortRows()
|
viewable.SortRows()
|
||||||
|
|
||||||
|
addedVal := false
|
||||||
if 0 < len(viewable.Rows) {
|
if 0 < len(viewable.Rows) {
|
||||||
row := GetLastSortRow(viewable.Rows)
|
row := GetLastSortRow(viewable.Rows)
|
||||||
if nil != row {
|
if nil != row {
|
||||||
|
|
@ -1514,12 +1518,27 @@ func addAttributeViewBlock(blockID string, operation *Operation, tree *parse.Tre
|
||||||
newValue.ID = ast.NewNodeID()
|
newValue.ID = ast.NewNodeID()
|
||||||
newValue.BlockID = blockID
|
newValue.BlockID = blockID
|
||||||
newValue.IsDetached = operation.IsDetached
|
newValue.IsDetached = operation.IsDetached
|
||||||
newValue.IsInitialized = false
|
|
||||||
values, _ := attrView.GetKeyValues(filter.Column)
|
values, _ := attrView.GetKeyValues(filter.Column)
|
||||||
values.Values = append(values.Values, newValue)
|
values.Values = append(values.Values, newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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.BlockID = blockID
|
||||||
|
newValue.IsDetached = operation.IsDetached
|
||||||
|
values, _ := attrView.GetKeyValues(filter.Column)
|
||||||
|
values.Values = append(values.Values, newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1570,7 +1589,7 @@ func GetLastSortRow(rows []*av.TableRow) *av.TableRow {
|
||||||
for i := len(rows) - 1; i >= 0; i-- {
|
for i := len(rows) - 1; i >= 0; i-- {
|
||||||
row := rows[i]
|
row := rows[i]
|
||||||
block := row.GetBlockValue()
|
block := row.GetBlockValue()
|
||||||
if nil != block && !block.NotAffectFilter() {
|
if nil != block {
|
||||||
return row
|
return row
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2295,7 +2314,6 @@ func UpdateAttributeViewCell(tx *Transaction, avID, keyID, rowID, cellID string,
|
||||||
|
|
||||||
if nil != blockVal {
|
if nil != blockVal {
|
||||||
blockVal.Block.Updated = time.Now().UnixMilli()
|
blockVal.Block.Updated = time.Now().UnixMilli()
|
||||||
blockVal.IsInitialized = true
|
|
||||||
if isUpdatingBlockKey {
|
if isUpdatingBlockKey {
|
||||||
blockVal.IsDetached = val.IsDetached
|
blockVal.IsDetached = val.IsDetached
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue