Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
5db30cdcd9
6 changed files with 264 additions and 1 deletions
46
API.md
46
API.md
|
@ -28,6 +28,8 @@
|
|||
* [Update a block](#Update-a-block)
|
||||
* [Delete a block](#Delete-a-block)
|
||||
* [Move a block](#Move-a-block)
|
||||
* [Fold a block](#Fold-a-block)
|
||||
* [Unfold a block](#Unfold-a-block)
|
||||
* [Get a block kramdown](#Get-a-block-kramdown)
|
||||
* [Get child blocks](#get-child-blocks)
|
||||
* [Transfer block ref](#transfer-block-ref)
|
||||
|
@ -783,6 +785,50 @@ View API token in <kbd>Settings - About</kbd>, request header: `Authorization: T
|
|||
}
|
||||
```
|
||||
|
||||
### Fold a block
|
||||
|
||||
* `/api/block/foldBlock`
|
||||
* Parameters
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "20231224160424-2f5680o"
|
||||
}
|
||||
```
|
||||
|
||||
* `id`: Block ID to fold
|
||||
* Return value
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### Unfold a block
|
||||
|
||||
* `/api/block/unfoldBlock`
|
||||
* Parameters
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "20231224160424-2f5680o"
|
||||
}
|
||||
```
|
||||
|
||||
* `id`: Block ID to unfold
|
||||
* Return value
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### Get a block kramdown
|
||||
|
||||
* `/api/block/getBlockKramdown`
|
||||
|
|
46
API_zh_CN.md
46
API_zh_CN.md
|
@ -29,6 +29,8 @@
|
|||
* [更新块](#更新块)
|
||||
* [删除块](#删除块)
|
||||
* [移动块](#移动块)
|
||||
* [折叠块](#折叠块)
|
||||
* [展开块](#展开块)
|
||||
* [获取块 kramdown 源码](#获取块-kramdown-源码)
|
||||
* [获取子块](#获取子块)
|
||||
* [转移块引用](#转移块引用)
|
||||
|
@ -776,6 +778,50 @@
|
|||
}
|
||||
```
|
||||
|
||||
### 折叠块
|
||||
|
||||
* `/api/block/foldBlock`
|
||||
* 参数
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "20231224160424-2f5680o"
|
||||
}
|
||||
```
|
||||
|
||||
* `id`:待折叠块的 ID
|
||||
* 返回值
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 展开块
|
||||
|
||||
* `/api/block/unfoldBlock`
|
||||
* 参数
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "20231224160424-2f5680o"
|
||||
}
|
||||
```
|
||||
|
||||
* `id`:待展开块的 ID
|
||||
* 返回值
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 获取块 kramdown 源码
|
||||
|
||||
* `/api/block/getBlockKramdown`
|
||||
|
|
|
@ -29,6 +29,126 @@ import (
|
|||
"github.com/siyuan-note/siyuan/kernel/util"
|
||||
)
|
||||
|
||||
func unfoldBlock(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
id := arg["id"].(string)
|
||||
if util.InvalidIDPattern(id, ret) {
|
||||
return
|
||||
}
|
||||
|
||||
bt := treenode.GetBlockTree(id)
|
||||
if nil == bt {
|
||||
ret.Code = -1
|
||||
ret.Msg = "block tree not found [id=" + id + "]"
|
||||
return
|
||||
}
|
||||
|
||||
if bt.Type == "d" {
|
||||
ret.Code = -1
|
||||
ret.Msg = "document can not be unfolded"
|
||||
return
|
||||
}
|
||||
|
||||
var transactions []*model.Transaction
|
||||
if "h" == bt.Type {
|
||||
transactions = []*model.Transaction{
|
||||
{
|
||||
DoOperations: []*model.Operation{
|
||||
{
|
||||
Action: "unfoldHeading",
|
||||
ID: id,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
data, _ := gulu.JSON.MarshalJSON(map[string]interface{}{"unfold": "1"})
|
||||
transactions = []*model.Transaction{
|
||||
{
|
||||
DoOperations: []*model.Operation{
|
||||
{
|
||||
Action: "setAttrs",
|
||||
ID: id,
|
||||
Data: string(data),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
model.PerformTransactions(&transactions)
|
||||
model.WaitForWritingFiles()
|
||||
|
||||
broadcastTransactions(transactions)
|
||||
}
|
||||
|
||||
func foldBlock(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
id := arg["id"].(string)
|
||||
if util.InvalidIDPattern(id, ret) {
|
||||
return
|
||||
}
|
||||
|
||||
bt := treenode.GetBlockTree(id)
|
||||
if nil == bt {
|
||||
ret.Code = -1
|
||||
ret.Msg = "block tree not found [id=" + id + "]"
|
||||
return
|
||||
}
|
||||
|
||||
if bt.Type == "d" {
|
||||
ret.Code = -1
|
||||
ret.Msg = "document can not be folded"
|
||||
return
|
||||
}
|
||||
|
||||
var transactions []*model.Transaction
|
||||
if "h" == bt.Type {
|
||||
transactions = []*model.Transaction{
|
||||
{
|
||||
DoOperations: []*model.Operation{
|
||||
{
|
||||
Action: "foldHeading",
|
||||
ID: id,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
data, _ := gulu.JSON.MarshalJSON(map[string]interface{}{"fold": "1"})
|
||||
transactions = []*model.Transaction{
|
||||
{
|
||||
DoOperations: []*model.Operation{
|
||||
{
|
||||
Action: "setAttrs",
|
||||
ID: id,
|
||||
Data: string(data),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
model.PerformTransactions(&transactions)
|
||||
model.WaitForWritingFiles()
|
||||
|
||||
broadcastTransactions(transactions)
|
||||
}
|
||||
|
||||
func moveBlock(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
|
|
@ -181,6 +181,8 @@ func ServeAPI(ginServer *gin.Engine) {
|
|||
ginServer.Handle("POST", "/api/block/updateBlock", model.CheckAuth, model.CheckReadonly, updateBlock)
|
||||
ginServer.Handle("POST", "/api/block/deleteBlock", model.CheckAuth, model.CheckReadonly, deleteBlock)
|
||||
ginServer.Handle("POST", "/api/block/moveBlock", model.CheckAuth, model.CheckReadonly, moveBlock)
|
||||
ginServer.Handle("POST", "/api/block/foldBlock", model.CheckAuth, model.CheckReadonly, foldBlock)
|
||||
ginServer.Handle("POST", "/api/block/unfoldBlock", model.CheckAuth, model.CheckReadonly, unfoldBlock)
|
||||
ginServer.Handle("POST", "/api/block/setBlockReminder", model.CheckAuth, model.CheckReadonly, setBlockReminder)
|
||||
ginServer.Handle("POST", "/api/block/getHeadingLevelTransaction", model.CheckAuth, getHeadingLevelTransaction)
|
||||
ginServer.Handle("POST", "/api/block/getHeadingDeleteTransaction", model.CheckAuth, getHeadingDeleteTransaction)
|
||||
|
|
|
@ -862,10 +862,15 @@ func updateAttributeViewColRelation(operation *Operation) (err error) {
|
|||
|
||||
if !destAdded {
|
||||
if operation.IsTwoWay {
|
||||
name := strings.TrimSpace(operation.Name)
|
||||
if "" == name {
|
||||
name = srcAv.Name
|
||||
}
|
||||
|
||||
destAv.KeyValues = append(destAv.KeyValues, &av.KeyValues{
|
||||
Key: &av.Key{
|
||||
ID: operation.BackRelationKeyID,
|
||||
Name: operation.Name,
|
||||
Name: name,
|
||||
Type: av.KeyTypeRelation,
|
||||
Relation: &av.Relation{AvID: operation.AvID, IsTwoWay: operation.IsTwoWay, BackKeyID: operation.KeyID},
|
||||
},
|
||||
|
@ -1893,13 +1898,43 @@ func removeAttributeViewColumn(operation *Operation) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
var removedKey *av.Key
|
||||
for i, keyValues := range attrView.KeyValues {
|
||||
if keyValues.Key.ID == operation.ID {
|
||||
attrView.KeyValues = append(attrView.KeyValues[:i], attrView.KeyValues[i+1:]...)
|
||||
removedKey = keyValues.Key
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 删除双向关联的目标列
|
||||
if nil != removedKey && nil != removedKey.Relation && removedKey.Relation.IsTwoWay {
|
||||
destAv, _ := av.ParseAttributeView(removedKey.Relation.AvID)
|
||||
if nil != destAv {
|
||||
for i, keyValues := range destAv.KeyValues {
|
||||
if keyValues.Key.ID == removedKey.Relation.BackKeyID {
|
||||
destAv.KeyValues = append(destAv.KeyValues[:i], destAv.KeyValues[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, view := range destAv.Views {
|
||||
switch view.LayoutType {
|
||||
case av.LayoutTypeTable:
|
||||
for i, column := range view.Table.Columns {
|
||||
if column.ID == removedKey.Relation.BackKeyID {
|
||||
view.Table.Columns = append(view.Table.Columns[:i], view.Table.Columns[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
av.SaveAttributeView(destAv)
|
||||
util.BroadcastByType("protyle", "refreshAttributeView", 0, "", map[string]interface{}{"id": destAv.ID})
|
||||
}
|
||||
}
|
||||
|
||||
for _, view := range attrView.Views {
|
||||
switch view.LayoutType {
|
||||
case av.LayoutTypeTable:
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
@ -168,6 +169,19 @@ func performTx(tx *Transaction) (ret *TxErr) {
|
|||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if e := recover(); nil != e {
|
||||
stack := debug.Stack()
|
||||
msg := fmt.Sprintf("PANIC RECOVERED: %v\n\t%s\n", e, stack)
|
||||
logging.LogErrorf(msg)
|
||||
|
||||
if 0 == tx.state.Load() {
|
||||
tx.rollback()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for _, op := range tx.DoOperations {
|
||||
switch op.Action {
|
||||
case "create":
|
||||
|
|
Loading…
Add table
Reference in a new issue