diff --git a/app/src/assets/scss/component/_snackbar.scss b/app/src/assets/scss/component/_snackbar.scss index b4edf4028..cf2e75803 100644 --- a/app/src/assets/scss/component/_snackbar.scss +++ b/app/src/assets/scss/component/_snackbar.scss @@ -3,6 +3,7 @@ position: relative; transition: transform 256ms cubic-bezier(.45, .05, .55, .95) 0ms; text-align: right; + justify-self: end; font-size: var(--b3-font-size); &--hide { diff --git a/app/src/dialog/message.ts b/app/src/dialog/message.ts index c931c30ca..6d17e7dcd 100644 --- a/app/src/dialog/message.ts +++ b/app/src/dialog/message.ts @@ -32,10 +32,21 @@ export const initMessage = () => { target = target.parentElement; } }); - const tempMessageElement = document.getElementById("tempMessage"); - if (tempMessageElement) { - showMessage(tempMessageElement.innerHTML); - tempMessageElement.remove(); + + const tempMessages = document.getElementById("tempMessages"); + if (tempMessages) { + const items = tempMessages.querySelectorAll("[temp-message]"); + items.forEach((item) => { + const timeoutString = item.getAttribute("data-timeout"); + let timeout; + if (timeoutString) { + timeout = parseInt(timeoutString); + } + const type = item.getAttribute("data-type"); + const messageId = item.getAttribute("data-message-id"); + showMessage(item.innerHTML, timeout, type, messageId); + }); + tempMessages.remove(); } }; @@ -43,14 +54,25 @@ export const initMessage = () => { export const showMessage = (message: string, timeout = 6000, type = "info", messageId?: string) => { const messagesElement = document.getElementById("message").firstElementChild; if (!messagesElement) { - document.body.insertAdjacentHTML("beforeend", `
${message}
`); + let tempMessages = document.getElementById("tempMessages"); + if (!tempMessages) { + document.body.insertAdjacentHTML("beforeend", "
"); + tempMessages = document.getElementById("tempMessages"); + } + + tempMessages.insertAdjacentHTML("beforeend", `
${message}
`); return; } const id = messageId || genUUID(); diff --git a/kernel/api/av.go b/kernel/api/av.go index 84e1344d9..f981e98c3 100644 --- a/kernel/api/av.go +++ b/kernel/api/av.go @@ -735,3 +735,24 @@ func setAttributeViewBlockAttr(c *gin.Context) { model.ReloadAttrView(avID) } + +func batchSetAttributeViewBlockAttrs(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + avID := arg["avID"].(string) + values := arg["values"].([]interface{}) + err := model.BatchUpdateAttributeViewCells(nil, avID, values) + if err != nil { + ret.Code = -1 + ret.Msg = err.Error() + return + } + + model.ReloadAttrView(avID) +} diff --git a/kernel/api/router.go b/kernel/api/router.go index 91f68bc27..628859b2b 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -436,6 +436,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/av/renderSnapshotAttributeView", model.CheckAuth, model.CheckAdminRole, renderSnapshotAttributeView) ginServer.Handle("POST", "/api/av/getAttributeViewKeys", model.CheckAuth, getAttributeViewKeys) ginServer.Handle("POST", "/api/av/setAttributeViewBlockAttr", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setAttributeViewBlockAttr) + ginServer.Handle("POST", "/api/av/batchSetAttributeViewBlockAttrs", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, batchSetAttributeViewBlockAttrs) 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/av/searchAttributeViewRelationKey", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, searchAttributeViewRelationKey) diff --git a/kernel/av/sort.go b/kernel/av/sort.go index 56ca2eaa2..1dac261fc 100644 --- a/kernel/av/sort.go +++ b/kernel/av/sort.go @@ -397,7 +397,7 @@ func (value *Value) Compare(other *Value, attrView *AttributeView) int { } case KeyTypeRelation: if nil != value.Relation && nil != other.Relation { - if 1 < len(value.Relation.Contents) && 1 < len(other.Relation.Contents) && KeyTypeNumber == value.Relation.Contents[0].Type && KeyTypeNumber == other.Relation.Contents[0].Type { + if 0 < len(value.Relation.Contents) && 0 < len(other.Relation.Contents) && KeyTypeNumber == value.Relation.Contents[0].Type && KeyTypeNumber == other.Relation.Contents[0].Type { v1, ok1 := util.Convert2Float(value.Relation.Contents[0].String(false)) v2, ok2 := util.Convert2Float(other.Relation.Contents[0].String(false)) if ok1 && ok2 { @@ -435,7 +435,7 @@ func (value *Value) Compare(other *Value, attrView *AttributeView) int { } case KeyTypeRollup: if nil != value.Rollup && nil != other.Rollup { - if 1 < len(value.Rollup.Contents) && 1 < len(other.Rollup.Contents) && KeyTypeNumber == value.Rollup.Contents[0].Type && KeyTypeNumber == other.Rollup.Contents[0].Type { + if 0 < len(value.Rollup.Contents) && 0 < len(other.Rollup.Contents) && KeyTypeNumber == value.Rollup.Contents[0].Type && KeyTypeNumber == other.Rollup.Contents[0].Type { v1, ok1 := util.Convert2Float(value.Rollup.Contents[0].String(false)) v2, ok2 := util.Convert2Float(other.Rollup.Contents[0].String(false)) if ok1 && ok2 { diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index 4d20613dc..327fa0561 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -3955,12 +3955,58 @@ func updateAttributeViewCell(operation *Operation, tx *Transaction) (err error) return } +func BatchUpdateAttributeViewCells(tx *Transaction, avID string, values []interface{}) (err error) { + attrView, err := av.ParseAttributeView(avID) + if err != nil { + return + } + + for _, value := range values { + v := value.(map[string]interface{}) + keyID := v["keyID"].(string) + rowID := v["rowID"].(string) + valueData := v["value"] + _, err = updateAttributeViewValue(tx, attrView, keyID, rowID, valueData) + if err != nil { + return + } + } + + if err = av.SaveAttributeView(attrView); err != nil { + return + } + + relatedAvIDs := av.GetSrcAvIDs(avID) + for _, relatedAvID := range relatedAvIDs { + ReloadAttrView(relatedAvID) + } + return +} + func UpdateAttributeViewCell(tx *Transaction, avID, keyID, rowID string, valueData interface{}) (val *av.Value, err error) { attrView, err := av.ParseAttributeView(avID) if err != nil { return } + val, err = updateAttributeViewValue(tx, attrView, keyID, rowID, valueData) + if nil != err { + return + } + + if err = av.SaveAttributeView(attrView); err != nil { + return + } + + relatedAvIDs := av.GetSrcAvIDs(avID) + for _, relatedAvID := range relatedAvIDs { + ReloadAttrView(relatedAvID) + } + return +} + +func updateAttributeViewValue(tx *Transaction, attrView *av.AttributeView, keyID, rowID string, valueData interface{}) (val *av.Value, err error) { + avID := attrView.ID var blockVal *av.Value for _, kv := range attrView.KeyValues { if av.KeyTypeBlock == kv.Key.Type { @@ -4203,15 +4249,6 @@ func UpdateAttributeViewCell(tx *Transaction, avID, keyID, rowID string, valueDa } } } - - relatedAvIDs := av.GetSrcAvIDs(avID) - for _, relatedAvID := range relatedAvIDs { - ReloadAttrView(relatedAvID) - } - - if err = av.SaveAttributeView(attrView); err != nil { - return - } return }