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

This commit is contained in:
Vanessa 2023-12-23 18:06:58 +08:00
commit 2c73687083
7 changed files with 243 additions and 19 deletions

View file

@ -26,6 +26,51 @@ import (
"github.com/siyuan-note/siyuan/kernel/util"
)
func getAttributeView(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
arg, _ := util.JsonArg(c, ret)
if nil == arg {
return
}
id := arg["id"].(string)
av := model.GetAttributeView(id)
ret.Data = map[string]interface{}{
"av": av,
}
}
func searchAttributeView(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
arg, _ := util.JsonArg(c, ret)
if nil == arg {
return
}
keyword := arg["keyword"].(string)
page := 1
pageArg := arg["page"]
if nil != pageArg {
page = int(pageArg.(float64))
}
pageSize := 10
pageSizeArg := arg["pageSize"]
if nil != pageSizeArg {
pageSize = int(pageSizeArg.(float64))
}
results, total := model.SearchAttributeView(keyword, page, pageSize)
ret.Data = map[string]interface{}{
"results": results,
"total": total,
}
}
func renderSnapshotAttributeView(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)

View file

@ -386,6 +386,8 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/av/renderSnapshotAttributeView", model.CheckAuth, renderSnapshotAttributeView)
ginServer.Handle("POST", "/api/av/getAttributeViewKeys", model.CheckAuth, getAttributeViewKeys)
ginServer.Handle("POST", "/api/av/setAttributeViewBlockAttr", model.CheckAuth, model.CheckReadonly, setAttributeViewBlockAttr)
ginServer.Handle("POST", "/api/av/searchAttributeView", model.CheckAuth, model.CheckReadonly, searchAttributeView)
ginServer.Handle("POST", "/api/av/getAttributeView", model.CheckAuth, model.CheckReadonly, getAttributeView)
ginServer.Handle("POST", "/api/ai/chatGPT", model.CheckAuth, chatGPT)
ginServer.Handle("POST", "/api/ai/chatGPTWithAction", model.CheckAuth, chatGPTWithAction)

View file

@ -80,7 +80,7 @@ type Key struct {
// 以下是某些列类型的特有属性
// 单选/多选列
Options []*KeySelectOption `json:"options,omitempty"` // 选项列表
Options []*SelectOption `json:"options,omitempty"` // 选项列表
// 数字列
NumberFormat NumberFormat `json:"numberFormat"` // 列数字格式化
@ -89,13 +89,10 @@ type Key struct {
Template string `json:"template"` // 模板内容
// 关联列
RelationAvID string `json:"relationAvID"` // 关联的属性视图 ID
RelationKeyID string `json:"relationKeyID"` // 关联列 ID
IsBiRelation bool `json:"isBiRelation"` // 是否双向关联
BackRelationKeyID string `json:"backRelationKeyID"` // 双向关联时回链关联列的 ID
Relation *Relation `json:"relation,omitempty"` // 关联信息
// 汇总列
RollupKeyID string `json:"rollupKeyID"` // 汇总列 ID
Rollup *Rollup `json:"rollup,omitempty"` // 汇总信息
}
func NewKey(id, name, icon string, keyType KeyType) *Key {
@ -107,7 +104,17 @@ func NewKey(id, name, icon string, keyType KeyType) *Key {
}
}
type KeySelectOption struct {
type Rollup struct {
KeyID string `json:"keyID"` // 汇总列 ID
}
type Relation struct {
AvID string `json:"avID"` // 关联的属性视图 ID
IsTwoWay bool `json:"isTwoWay"` // 是否双向关联
BackKeyID string `json:"backKeyID"` // 双向关联时回链关联列的 ID
}
type SelectOption struct {
Name string `json:"name"`
Color string `json:"color"`
}

View file

@ -651,9 +651,11 @@ type TableColumn struct {
// 以下是某些列类型的特有属性
Options []*KeySelectOption `json:"options,omitempty"` // 选项列表
NumberFormat NumberFormat `json:"numberFormat"` // 列数字格式化
Template string `json:"template"` // 模板内容
Options []*SelectOption `json:"options,omitempty"` // 选项列表
NumberFormat NumberFormat `json:"numberFormat"` // 列数字格式化
Template string `json:"template"` // 模板内容
Relation *Relation `json:"relation,omitempty"` // 关联列
Rollup *Rollup `json:"rollup,omitempty"` // 汇总列
}
type TableCell struct {

View file

@ -37,6 +37,70 @@ import (
"github.com/siyuan-note/siyuan/kernel/util"
)
func GetAttributeView(avID string) (ret *av.AttributeView) {
waitForSyncingStorages()
ret, _ = av.ParseAttributeView(avID)
return
}
type SearchAttributeViewResult struct {
AvID string `json:"avID"`
AvName string `json:"avName"`
BlockID string `json:"blockID"`
}
func SearchAttributeView(keyword string, page int, pageSize int) (ret []*SearchAttributeViewResult, pageCount int) {
waitForSyncingStorages()
ret = []*SearchAttributeViewResult{}
blocks, _, _, pageCount := FullTextSearchBlock(keyword, nil, nil, map[string]bool{"databaseBlock": true}, 0, 7, 0, page, pageSize)
trees := map[string]*parse.Tree{}
for _, block := range blocks {
tree := trees[block.RootID]
if nil == tree {
tree, _ = loadTreeByBlockID(block.ID)
if nil != tree {
trees[block.RootID] = tree
}
}
if nil == tree {
continue
}
node := treenode.GetNodeInTree(tree, block.ID)
if nil == node {
continue
}
if "" == node.AttributeViewID {
continue
}
avID := node.AttributeViewID
attrView, _ := av.ParseAttributeView(avID)
if nil == attrView {
continue
}
exist := false
for _, result := range ret {
if result.AvID == avID {
exist = true
break
}
}
if !exist {
ret = append(ret, &SearchAttributeViewResult{
AvID: avID,
AvName: attrView.Name,
BlockID: block.ID,
})
}
}
return
}
type BlockAttributeViewKeys struct {
AvID string `json:"avID"`
AvName string `json:"avName"`
@ -489,6 +553,8 @@ func renderAttributeViewTable(attrView *av.AttributeView, view *av.View) (ret *a
Options: key.Options,
NumberFormat: key.NumberFormat,
Template: key.Template,
Relation: key.Relation,
Rollup: key.Rollup,
Wrap: col.Wrap,
Hidden: col.Hidden,
Width: col.Width,
@ -655,6 +721,102 @@ func getRowBlockValue(keyValues []*av.KeyValues) (ret *av.Value) {
return
}
func (tx *Transaction) doUpdateAttrViewColRelation(operation *Operation) (ret *TxErr) {
err := updateAttributeViewColRelation(operation)
if nil != err {
return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
}
return
}
func updateAttributeViewColRelation(operation *Operation) (err error) {
// operation.AvID 源 avID
// operation.ID 目标 avID
// operation.KeyID 源 av 关联列 ID
// operation.IsTwoWay 是否双向关联
// operation.BackRelationKeyID 双向关联的目标关联列 ID
// operation.Name 双向关联的目标关联列名称
srcAv, err := av.ParseAttributeView(operation.AvID)
if nil != err {
return
}
destAv, err := av.ParseAttributeView(operation.ID)
if nil != err {
return
}
isSameAv := srcAv.ID == destAv.ID
for _, keyValues := range srcAv.KeyValues {
if keyValues.Key.ID == operation.KeyID {
// 已经设置过双向关联的话需要先断开双向关联
if nil != keyValues.Key.Relation && keyValues.Key.Relation.IsTwoWay {
oldDestAv, parseErr := av.ParseAttributeView(keyValues.Key.Relation.AvID)
if nil == parseErr {
isOldSameAv := oldDestAv.ID == destAv.ID
if isOldSameAv {
oldDestAv = destAv
}
oldDestKey, _ := oldDestAv.GetKey(keyValues.Key.Relation.BackKeyID)
if nil != oldDestKey && nil != oldDestKey.Relation && oldDestKey.Relation.AvID == srcAv.ID && oldDestKey.Relation.IsTwoWay {
oldDestKey.Relation.IsTwoWay = false
oldDestKey.Relation.BackKeyID = ""
}
if !isOldSameAv {
err = av.SaveAttributeView(oldDestAv)
if nil != err {
return
}
}
}
}
keyValues.Key.Relation = &av.Relation{
AvID: operation.ID,
IsTwoWay: operation.IsTwoWay,
BackKeyID: operation.BackRelationKeyID,
}
break
}
}
destAdded := false
for _, keyValues := range destAv.KeyValues {
if keyValues.Key.ID == operation.BackRelationKeyID {
keyValues.Key.Relation = &av.Relation{
AvID: operation.AvID,
IsTwoWay: operation.IsTwoWay,
BackKeyID: operation.KeyID,
}
destAdded = true
break
}
}
if !destAdded {
destAv.KeyValues = append(destAv.KeyValues, &av.KeyValues{
Key: &av.Key{
ID: operation.BackRelationKeyID,
Name: operation.Name,
Type: av.KeyTypeRelation,
Relation: &av.Relation{AvID: operation.AvID, IsTwoWay: operation.IsTwoWay, BackKeyID: operation.KeyID},
},
})
}
err = av.SaveAttributeView(srcAv)
if nil != err {
return
}
if !isSameAv {
err = av.SaveAttributeView(destAv)
}
return
}
func (tx *Transaction) doSortAttrViewView(operation *Operation) (ret *TxErr) {
avID := operation.AvID
attrView, err := av.ParseAttributeView(avID)
@ -1948,7 +2110,7 @@ func updateAttributeViewColumnOptions(operation *Operation) (err error) {
return
}
options := []*av.KeySelectOption{}
options := []*av.SelectOption{}
if err = gulu.JSON.UnmarshalJSON(jsonData, &options); nil != err {
return
}

View file

@ -258,6 +258,8 @@ func performTx(tx *Transaction) (ret *TxErr) {
ret = tx.doDuplicateAttrViewView(op)
case "sortAttrViewView":
ret = tx.doSortAttrViewView(op)
case "updateAttrViewColRelation":
ret = tx.doUpdateAttrViewColRelation(op)
}
if nil != ret {
@ -1181,14 +1183,16 @@ type Operation struct {
DeckID string `json:"deckID"` // 用于添加/删除闪卡
AvID string `json:"avID"` // 属性视图 ID
SrcIDs []string `json:"srcIDs"` // 用于将块拖拽到属性视图中
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
AvID string `json:"avID"` // 属性视图 ID
SrcIDs []string `json:"srcIDs"` // 用于将块拖拽到属性视图中
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
}
type Transaction struct {

View file

@ -614,6 +614,8 @@ func renderAttributeViewTable(attrView *av.AttributeView, view *av.View) (ret *a
Options: key.Options,
NumberFormat: key.NumberFormat,
Template: key.Template,
Relation: key.Relation,
Rollup: key.Rollup,
Wrap: col.Wrap,
Hidden: col.Hidden,
Width: col.Width,