attribute_view.go 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526
  1. // SiYuan - Refactor your thinking
  2. // Copyright (c) 2020-present, b3log.org
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. package model
  17. import (
  18. "bytes"
  19. "os"
  20. "path/filepath"
  21. "sort"
  22. "strconv"
  23. "strings"
  24. "text/template"
  25. "time"
  26. "github.com/88250/gulu"
  27. "github.com/88250/lute/ast"
  28. "github.com/88250/lute/parse"
  29. "github.com/siyuan-note/dejavu/entity"
  30. "github.com/siyuan-note/filelock"
  31. "github.com/siyuan-note/logging"
  32. "github.com/siyuan-note/siyuan/kernel/av"
  33. "github.com/siyuan-note/siyuan/kernel/sql"
  34. "github.com/siyuan-note/siyuan/kernel/treenode"
  35. "github.com/siyuan-note/siyuan/kernel/util"
  36. )
  37. func GetAttributeView(avID string) (ret *av.AttributeView) {
  38. waitForSyncingStorages()
  39. ret, _ = av.ParseAttributeView(avID)
  40. return
  41. }
  42. type SearchAttributeViewResult struct {
  43. AvID string `json:"avID"`
  44. AvName string `json:"avName"`
  45. BlockID string `json:"blockID"`
  46. HPath string `json:"hPath"`
  47. }
  48. func SearchAttributeView(keyword string, page int, pageSize int) (ret []*SearchAttributeViewResult, pageCount int) {
  49. waitForSyncingStorages()
  50. ret = []*SearchAttributeViewResult{}
  51. var blocks []*Block
  52. keyword = strings.TrimSpace(keyword)
  53. if "" == keyword {
  54. sqlBlocks := sql.SelectBlocksRawStmt("SELECT * FROM blocks WHERE type = 'av' ORDER BY updated DESC LIMIT 10", page, pageSize)
  55. blocks = fromSQLBlocks(&sqlBlocks, "", 36)
  56. pageCount = 1
  57. } else {
  58. var matchedBlockCount int
  59. blocks, matchedBlockCount, _ = fullTextSearchByKeyword(keyword, "", "", "('av')", "", 36, page, pageSize)
  60. pageCount = (matchedBlockCount + pageSize - 1) / pageSize
  61. }
  62. trees := map[string]*parse.Tree{}
  63. for _, block := range blocks {
  64. tree := trees[block.RootID]
  65. if nil == tree {
  66. tree, _ = loadTreeByBlockID(block.ID)
  67. if nil != tree {
  68. trees[block.RootID] = tree
  69. }
  70. }
  71. if nil == tree {
  72. continue
  73. }
  74. node := treenode.GetNodeInTree(tree, block.ID)
  75. if nil == node {
  76. continue
  77. }
  78. if "" == node.AttributeViewID {
  79. continue
  80. }
  81. avID := node.AttributeViewID
  82. attrView, _ := av.ParseAttributeView(avID)
  83. if nil == attrView {
  84. continue
  85. }
  86. exist := false
  87. for _, result := range ret {
  88. if result.AvID == avID {
  89. exist = true
  90. break
  91. }
  92. }
  93. var hPath string
  94. baseBlock := treenode.GetBlockTreeRootByPath(node.Box, node.Path)
  95. if nil != baseBlock {
  96. hPath = baseBlock.HPath
  97. }
  98. box := Conf.Box(node.Box)
  99. if nil != box {
  100. hPath = box.Name + hPath
  101. }
  102. if !exist {
  103. ret = append(ret, &SearchAttributeViewResult{
  104. AvID: avID,
  105. AvName: attrView.Name,
  106. BlockID: block.ID,
  107. HPath: hPath,
  108. })
  109. }
  110. }
  111. return
  112. }
  113. type BlockAttributeViewKeys struct {
  114. AvID string `json:"avID"`
  115. AvName string `json:"avName"`
  116. BlockIDs []string `json:"blockIDs"`
  117. KeyValues []*av.KeyValues `json:"keyValues"`
  118. }
  119. func GetBlockAttributeViewKeys(blockID string) (ret []*BlockAttributeViewKeys) {
  120. waitForSyncingStorages()
  121. ret = []*BlockAttributeViewKeys{}
  122. attrs := GetBlockAttrsWithoutWaitWriting(blockID)
  123. avs := attrs[av.NodeAttrNameAvs]
  124. if "" == avs {
  125. return
  126. }
  127. avIDs := strings.Split(avs, ",")
  128. for _, avID := range avIDs {
  129. attrView, err := av.ParseAttributeView(avID)
  130. if nil != err {
  131. logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
  132. return
  133. }
  134. if 1 > len(attrView.Views) {
  135. err = av.ErrViewNotFound
  136. return
  137. }
  138. var keyValues []*av.KeyValues
  139. for _, kv := range attrView.KeyValues {
  140. kValues := &av.KeyValues{Key: kv.Key}
  141. for _, v := range kv.Values {
  142. if v.BlockID == blockID {
  143. kValues.Values = append(kValues.Values, v)
  144. }
  145. }
  146. switch kValues.Key.Type {
  147. case av.KeyTypeTemplate:
  148. kValues.Values = append(kValues.Values, &av.Value{ID: ast.NewNodeID(), KeyID: kValues.Key.ID, BlockID: blockID, Type: av.KeyTypeTemplate, Template: &av.ValueTemplate{Content: ""}})
  149. case av.KeyTypeCreated:
  150. kValues.Values = append(kValues.Values, &av.Value{ID: ast.NewNodeID(), KeyID: kValues.Key.ID, BlockID: blockID, Type: av.KeyTypeCreated})
  151. case av.KeyTypeUpdated:
  152. kValues.Values = append(kValues.Values, &av.Value{ID: ast.NewNodeID(), KeyID: kValues.Key.ID, BlockID: blockID, Type: av.KeyTypeUpdated})
  153. }
  154. if 0 < len(kValues.Values) {
  155. keyValues = append(keyValues, kValues)
  156. }
  157. }
  158. // 渲染自动生成的列值,比如模板列、关联列、汇总列、创建时间列和更新时间列
  159. // 先处理关联列、汇总列、创建时间列和更新时间列
  160. for _, kv := range keyValues {
  161. switch kv.Key.Type {
  162. case av.KeyTypeRollup:
  163. if nil == kv.Key.Rollup {
  164. break
  165. }
  166. relKey, _ := attrView.GetKey(kv.Key.Rollup.RelationKeyID)
  167. if nil == relKey {
  168. break
  169. }
  170. var blockIDs []string
  171. relVal := attrView.GetValue(kv.Key.Rollup.RelationKeyID, kv.Values[0].BlockID)
  172. if nil != relVal && nil != relVal.Relation {
  173. blockIDs = relVal.Relation.BlockIDs
  174. }
  175. destAv, _ := av.ParseAttributeView(relKey.Relation.AvID)
  176. if nil != destAv {
  177. for _, bID := range blockIDs {
  178. kv.Values[0].Rollup.Contents = append(kv.Values[0].Rollup.Contents, destAv.GetValue(kv.Key.Rollup.KeyID, bID).String())
  179. }
  180. }
  181. case av.KeyTypeRelation:
  182. if nil == kv.Key.Relation {
  183. break
  184. }
  185. destAv, _ := av.ParseAttributeView(kv.Key.Relation.AvID)
  186. if nil == destAv {
  187. break
  188. }
  189. blocks := map[string]string{}
  190. for _, blockValue := range destAv.GetBlockKeyValues().Values {
  191. blocks[blockValue.BlockID] = blockValue.Block.Content
  192. }
  193. for _, bID := range kv.Values[0].Relation.BlockIDs {
  194. kv.Values[0].Relation.Contents = append(kv.Values[0].Relation.Contents, blocks[bID])
  195. }
  196. case av.KeyTypeCreated:
  197. createdStr := blockID[:len("20060102150405")]
  198. created, parseErr := time.ParseInLocation("20060102150405", createdStr, time.Local)
  199. if nil == parseErr {
  200. kv.Values[0].Created = av.NewFormattedValueCreated(created.UnixMilli(), 0, av.CreatedFormatNone)
  201. kv.Values[0].Created.IsNotEmpty = true
  202. } else {
  203. logging.LogWarnf("parse created [%s] failed: %s", createdStr, parseErr)
  204. kv.Values[0].Created = av.NewFormattedValueCreated(time.Now().UnixMilli(), 0, av.CreatedFormatNone)
  205. }
  206. case av.KeyTypeUpdated:
  207. ial := GetBlockAttrsWithoutWaitWriting(blockID)
  208. updatedStr := ial["updated"]
  209. updated, parseErr := time.ParseInLocation("20060102150405", updatedStr, time.Local)
  210. if nil == parseErr {
  211. kv.Values[0].Updated = av.NewFormattedValueUpdated(updated.UnixMilli(), 0, av.UpdatedFormatNone)
  212. kv.Values[0].Updated.IsNotEmpty = true
  213. } else {
  214. logging.LogWarnf("parse updated [%s] failed: %s", updatedStr, parseErr)
  215. kv.Values[0].Updated = av.NewFormattedValueUpdated(time.Now().UnixMilli(), 0, av.UpdatedFormatNone)
  216. }
  217. }
  218. }
  219. // 再处理模板列
  220. for _, kv := range keyValues {
  221. switch kv.Key.Type {
  222. case av.KeyTypeTemplate:
  223. if 0 < len(kv.Values) {
  224. ial := map[string]string{}
  225. block := getRowBlockValue(keyValues)
  226. if !block.IsDetached {
  227. ial = GetBlockAttrsWithoutWaitWriting(blockID)
  228. }
  229. kv.Values[0].Template.Content = renderTemplateCol(ial, kv.Key.Template, keyValues)
  230. }
  231. }
  232. }
  233. // Attribute Panel - Database sort attributes by view column order https://github.com/siyuan-note/siyuan/issues/9319
  234. view, _ := attrView.GetCurrentView()
  235. if nil != view {
  236. sorts := map[string]int{}
  237. for i, col := range view.Table.Columns {
  238. sorts[col.ID] = i
  239. }
  240. sort.Slice(keyValues, func(i, j int) bool {
  241. return sorts[keyValues[i].Key.ID] < sorts[keyValues[j].Key.ID]
  242. })
  243. }
  244. blockIDs := av.GetMirrorBlockIDs(avID)
  245. if 1 > len(blockIDs) {
  246. // 老数据兼容处理
  247. avBts := treenode.GetBlockTreesByType("av")
  248. for _, avBt := range avBts {
  249. if nil == avBt {
  250. continue
  251. }
  252. tree, _ := loadTreeByBlockID(avBt.ID)
  253. if nil == tree {
  254. continue
  255. }
  256. node := treenode.GetNodeInTree(tree, avBt.ID)
  257. if nil == node {
  258. continue
  259. }
  260. if avID == node.AttributeViewID {
  261. blockIDs = append(blockIDs, avBt.ID)
  262. }
  263. }
  264. if 1 > len(blockIDs) {
  265. continue
  266. }
  267. blockIDs = gulu.Str.RemoveDuplicatedElem(blockIDs)
  268. for _, blockID := range blockIDs {
  269. av.UpsertBlockRel(avID, blockID)
  270. }
  271. }
  272. ret = append(ret, &BlockAttributeViewKeys{
  273. AvID: avID,
  274. AvName: attrView.Name,
  275. BlockIDs: blockIDs,
  276. KeyValues: keyValues,
  277. })
  278. }
  279. return
  280. }
  281. func RenderRepoSnapshotAttributeView(indexID, avID string) (viewable av.Viewable, attrView *av.AttributeView, err error) {
  282. repo, err := newRepository()
  283. if nil != err {
  284. return
  285. }
  286. index, err := repo.GetIndex(indexID)
  287. if nil != err {
  288. return
  289. }
  290. files, err := repo.GetFiles(index)
  291. if nil != err {
  292. return
  293. }
  294. var avFile *entity.File
  295. for _, f := range files {
  296. if "/storage/av/"+avID+".json" == f.Path {
  297. avFile = f
  298. break
  299. }
  300. }
  301. if nil == avFile {
  302. attrView = av.NewAttributeView(avID)
  303. } else {
  304. data, readErr := repo.OpenFile(avFile)
  305. if nil != readErr {
  306. logging.LogErrorf("read attribute view [%s] failed: %s", avID, readErr)
  307. return
  308. }
  309. attrView = &av.AttributeView{}
  310. if err = gulu.JSON.UnmarshalJSON(data, attrView); nil != err {
  311. logging.LogErrorf("unmarshal attribute view [%s] failed: %s", avID, err)
  312. return
  313. }
  314. }
  315. viewable, err = renderAttributeView(attrView, "", 1, -1)
  316. return
  317. }
  318. func RenderHistoryAttributeView(avID, created string) (viewable av.Viewable, attrView *av.AttributeView, err error) {
  319. createdUnix, parseErr := strconv.ParseInt(created, 10, 64)
  320. if nil != parseErr {
  321. logging.LogErrorf("parse created [%s] failed: %s", created, parseErr)
  322. return
  323. }
  324. dirPrefix := time.Unix(createdUnix, 0).Format("2006-01-02-150405")
  325. globPath := filepath.Join(util.HistoryDir, dirPrefix+"*")
  326. matches, err := filepath.Glob(globPath)
  327. if nil != err {
  328. logging.LogErrorf("glob [%s] failed: %s", globPath, err)
  329. return
  330. }
  331. if 1 > len(matches) {
  332. return
  333. }
  334. historyDir := matches[0]
  335. avJSONPath := filepath.Join(historyDir, "storage", "av", avID+".json")
  336. if !gulu.File.IsExist(avJSONPath) {
  337. avJSONPath = filepath.Join(util.DataDir, "storage", "av", avID+".json")
  338. }
  339. if !gulu.File.IsExist(avJSONPath) {
  340. attrView = av.NewAttributeView(avID)
  341. } else {
  342. data, readErr := os.ReadFile(avJSONPath)
  343. if nil != readErr {
  344. logging.LogErrorf("read attribute view [%s] failed: %s", avID, readErr)
  345. return
  346. }
  347. attrView = &av.AttributeView{}
  348. if err = gulu.JSON.UnmarshalJSON(data, attrView); nil != err {
  349. logging.LogErrorf("unmarshal attribute view [%s] failed: %s", avID, err)
  350. return
  351. }
  352. }
  353. viewable, err = renderAttributeView(attrView, "", 1, -1)
  354. return
  355. }
  356. func RenderAttributeView(avID, viewID string, page, pageSize int) (viewable av.Viewable, attrView *av.AttributeView, err error) {
  357. waitForSyncingStorages()
  358. if avJSONPath := av.GetAttributeViewDataPath(avID); !filelock.IsExist(avJSONPath) {
  359. attrView = av.NewAttributeView(avID)
  360. if err = av.SaveAttributeView(attrView); nil != err {
  361. logging.LogErrorf("save attribute view [%s] failed: %s", avID, err)
  362. return
  363. }
  364. }
  365. attrView, err = av.ParseAttributeView(avID)
  366. if nil != err {
  367. logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
  368. return
  369. }
  370. viewable, err = renderAttributeView(attrView, viewID, page, pageSize)
  371. return
  372. }
  373. func renderAttributeView(attrView *av.AttributeView, viewID string, page, pageSize int) (viewable av.Viewable, err error) {
  374. if 1 > len(attrView.Views) {
  375. view, _ := av.NewTableViewWithBlockKey(ast.NewNodeID())
  376. attrView.Views = append(attrView.Views, view)
  377. attrView.ViewID = view.ID
  378. if err = av.SaveAttributeView(attrView); nil != err {
  379. logging.LogErrorf("save attribute view [%s] failed: %s", attrView.ID, err)
  380. return
  381. }
  382. }
  383. var view *av.View
  384. if "" != viewID {
  385. view = attrView.GetView(viewID)
  386. if nil != view && viewID != attrView.ViewID {
  387. attrView.ViewID = viewID
  388. if err = av.SaveAttributeView(attrView); nil != err {
  389. logging.LogErrorf("save attribute view [%s] failed: %s", attrView.ID, err)
  390. return
  391. }
  392. }
  393. } else {
  394. if "" != attrView.ViewID {
  395. view, _ = attrView.GetCurrentView()
  396. }
  397. }
  398. if nil == view {
  399. view = attrView.Views[0]
  400. }
  401. // 做一些数据兼容和订正处理,保存的时候也会做 av.SaveAttributeView()
  402. currentTimeMillis := util.CurrentTimeMillis()
  403. for _, kv := range attrView.KeyValues {
  404. switch kv.Key.Type {
  405. case av.KeyTypeBlock: // 补全 block 的创建时间和更新时间
  406. for _, v := range kv.Values {
  407. if 0 == v.Block.Created {
  408. if "" == v.Block.ID {
  409. v.Block.ID = v.BlockID
  410. if "" == v.Block.ID {
  411. v.Block.ID = ast.NewNodeID()
  412. v.BlockID = v.Block.ID
  413. }
  414. }
  415. createdStr := v.Block.ID[:len("20060102150405")]
  416. created, parseErr := time.ParseInLocation("20060102150405", createdStr, time.Local)
  417. if nil == parseErr {
  418. v.Block.Created = created.UnixMilli()
  419. } else {
  420. v.Block.Created = currentTimeMillis
  421. }
  422. }
  423. if 0 == v.Block.Updated {
  424. v.Block.Updated = currentTimeMillis
  425. }
  426. }
  427. }
  428. }
  429. switch view.LayoutType {
  430. case av.LayoutTypeTable:
  431. // 列删除以后需要删除设置的过滤和排序
  432. tmpFilters := []*av.ViewFilter{}
  433. for _, f := range view.Table.Filters {
  434. if k, _ := attrView.GetKey(f.Column); nil != k {
  435. tmpFilters = append(tmpFilters, f)
  436. }
  437. }
  438. view.Table.Filters = tmpFilters
  439. tmpSorts := []*av.ViewSort{}
  440. for _, s := range view.Table.Sorts {
  441. if k, _ := attrView.GetKey(s.Column); nil != k {
  442. tmpSorts = append(tmpSorts, s)
  443. }
  444. }
  445. view.Table.Sorts = tmpSorts
  446. viewable, err = renderAttributeViewTable(attrView, view)
  447. }
  448. viewable.FilterRows()
  449. viewable.SortRows()
  450. viewable.CalcCols()
  451. // 分页
  452. switch viewable.GetType() {
  453. case av.LayoutTypeTable:
  454. table := viewable.(*av.Table)
  455. table.RowCount = len(table.Rows)
  456. if 1 > view.Table.PageSize {
  457. view.Table.PageSize = 50
  458. }
  459. table.PageSize = view.Table.PageSize
  460. if 1 > pageSize {
  461. pageSize = table.PageSize
  462. }
  463. start := (page - 1) * pageSize
  464. end := start + pageSize
  465. if len(table.Rows) < end {
  466. end = len(table.Rows)
  467. }
  468. table.Rows = table.Rows[start:end]
  469. }
  470. return
  471. }
  472. func renderTemplateCol(ial map[string]string, tplContent string, rowValues []*av.KeyValues) string {
  473. if "" == ial["id"] {
  474. block := getRowBlockValue(rowValues)
  475. ial["id"] = block.Block.ID
  476. }
  477. if "" == ial["updated"] {
  478. block := getRowBlockValue(rowValues)
  479. ial["updated"] = time.UnixMilli(block.Block.Updated).Format("20060102150405")
  480. }
  481. goTpl := template.New("").Delims(".action{", "}")
  482. goTpl = goTpl.Funcs(util.BuiltInTemplateFuncs())
  483. tpl, tplErr := goTpl.Parse(tplContent)
  484. if nil != tplErr {
  485. logging.LogWarnf("parse template [%s] failed: %s", tplContent, tplErr)
  486. return ""
  487. }
  488. buf := &bytes.Buffer{}
  489. dataModel := map[string]interface{}{} // 复制一份 IAL 以避免修改原始数据
  490. for k, v := range ial {
  491. dataModel[k] = v
  492. // Database template column supports `created` and `updated` built-in variables https://github.com/siyuan-note/siyuan/issues/9364
  493. createdStr := ial["id"]
  494. if "" != createdStr {
  495. createdStr = createdStr[:len("20060102150405")]
  496. }
  497. created, parseErr := time.ParseInLocation("20060102150405", createdStr, time.Local)
  498. if nil == parseErr {
  499. dataModel["created"] = created
  500. } else {
  501. logging.LogWarnf("parse created [%s] failed: %s", createdStr, parseErr)
  502. dataModel["created"] = time.Now()
  503. }
  504. updatedStr := ial["updated"]
  505. updated, parseErr := time.ParseInLocation("20060102150405", updatedStr, time.Local)
  506. if nil == parseErr {
  507. dataModel["updated"] = updated
  508. } else {
  509. dataModel["updated"] = time.Now()
  510. }
  511. }
  512. for _, rowValue := range rowValues {
  513. if 0 < len(rowValue.Values) {
  514. v := rowValue.Values[0]
  515. if av.KeyTypeNumber == v.Type {
  516. dataModel[rowValue.Key.Name] = v.Number.Content
  517. } else if av.KeyTypeDate == v.Type {
  518. dataModel[rowValue.Key.Name] = time.UnixMilli(v.Date.Content)
  519. } else {
  520. dataModel[rowValue.Key.Name] = v.String()
  521. }
  522. }
  523. }
  524. if err := tpl.Execute(buf, dataModel); nil != err {
  525. logging.LogWarnf("execute template [%s] failed: %s", tplContent, err)
  526. }
  527. return buf.String()
  528. }
  529. func renderAttributeViewTable(attrView *av.AttributeView, view *av.View) (ret *av.Table, err error) {
  530. ret = &av.Table{
  531. ID: view.ID,
  532. Icon: view.Icon,
  533. Name: view.Name,
  534. Columns: []*av.TableColumn{},
  535. Rows: []*av.TableRow{},
  536. Filters: view.Table.Filters,
  537. Sorts: view.Table.Sorts,
  538. }
  539. // 组装列
  540. for _, col := range view.Table.Columns {
  541. key, getErr := attrView.GetKey(col.ID)
  542. if nil != getErr {
  543. err = getErr
  544. return
  545. }
  546. ret.Columns = append(ret.Columns, &av.TableColumn{
  547. ID: key.ID,
  548. Name: key.Name,
  549. Type: key.Type,
  550. Icon: key.Icon,
  551. Options: key.Options,
  552. NumberFormat: key.NumberFormat,
  553. Template: key.Template,
  554. Relation: key.Relation,
  555. Rollup: key.Rollup,
  556. Wrap: col.Wrap,
  557. Hidden: col.Hidden,
  558. Width: col.Width,
  559. Pin: col.Pin,
  560. Calc: col.Calc,
  561. })
  562. }
  563. // 生成行
  564. rows := map[string][]*av.KeyValues{}
  565. for _, keyValues := range attrView.KeyValues {
  566. for _, val := range keyValues.Values {
  567. values := rows[val.BlockID]
  568. if nil == values {
  569. values = []*av.KeyValues{{Key: keyValues.Key, Values: []*av.Value{val}}}
  570. } else {
  571. values = append(values, &av.KeyValues{Key: keyValues.Key, Values: []*av.Value{val}})
  572. }
  573. rows[val.BlockID] = values
  574. }
  575. }
  576. // 过滤掉不存在的行
  577. var notFound []string
  578. for blockID, keyValues := range rows {
  579. blockValue := getRowBlockValue(keyValues)
  580. if nil == blockValue {
  581. notFound = append(notFound, blockID)
  582. continue
  583. }
  584. if blockValue.IsDetached {
  585. continue
  586. }
  587. if nil != blockValue.Block && "" == blockValue.Block.ID {
  588. notFound = append(notFound, blockID)
  589. continue
  590. }
  591. if treenode.GetBlockTree(blockID) == nil {
  592. notFound = append(notFound, blockID)
  593. }
  594. }
  595. for _, blockID := range notFound {
  596. delete(rows, blockID)
  597. }
  598. // 生成行单元格
  599. for rowID, row := range rows {
  600. var tableRow av.TableRow
  601. for _, col := range ret.Columns {
  602. var tableCell *av.TableCell
  603. for _, keyValues := range row {
  604. if keyValues.Key.ID == col.ID {
  605. tableCell = &av.TableCell{
  606. ID: keyValues.Values[0].ID,
  607. Value: keyValues.Values[0],
  608. ValueType: col.Type,
  609. }
  610. break
  611. }
  612. }
  613. if nil == tableCell {
  614. tableCell = &av.TableCell{
  615. ID: ast.NewNodeID(),
  616. ValueType: col.Type,
  617. }
  618. }
  619. tableRow.ID = rowID
  620. switch tableCell.ValueType {
  621. case av.KeyTypeNumber: // 格式化数字
  622. if nil != tableCell.Value && nil != tableCell.Value.Number && tableCell.Value.Number.IsNotEmpty {
  623. tableCell.Value.Number.Format = col.NumberFormat
  624. tableCell.Value.Number.FormatNumber()
  625. }
  626. case av.KeyTypeTemplate: // 渲染模板列
  627. tableCell.Value = &av.Value{ID: tableCell.ID, KeyID: col.ID, BlockID: rowID, Type: av.KeyTypeTemplate, Template: &av.ValueTemplate{Content: col.Template}}
  628. case av.KeyTypeCreated: // 填充创建时间列值,后面再渲染
  629. tableCell.Value = &av.Value{ID: tableCell.ID, KeyID: col.ID, BlockID: rowID, Type: av.KeyTypeCreated}
  630. case av.KeyTypeUpdated: // 填充更新时间列值,后面再渲染
  631. tableCell.Value = &av.Value{ID: tableCell.ID, KeyID: col.ID, BlockID: rowID, Type: av.KeyTypeUpdated}
  632. }
  633. treenode.FillAttributeViewTableCellNilValue(tableCell, rowID, col.ID)
  634. tableRow.Cells = append(tableRow.Cells, tableCell)
  635. }
  636. ret.Rows = append(ret.Rows, &tableRow)
  637. }
  638. // 渲染自动生成的列值,比如模板列、关联列、汇总列、创建时间列和更新时间列
  639. for _, row := range ret.Rows {
  640. for _, cell := range row.Cells {
  641. switch cell.ValueType {
  642. case av.KeyTypeTemplate: // 渲染模板列
  643. keyValues := rows[row.ID]
  644. ial := map[string]string{}
  645. block := row.GetBlockValue()
  646. if nil != block && !block.IsDetached {
  647. ial = GetBlockAttrsWithoutWaitWriting(row.ID)
  648. }
  649. content := renderTemplateCol(ial, cell.Value.Template.Content, keyValues)
  650. cell.Value.Template.Content = content
  651. case av.KeyTypeRollup: // 渲染汇总列
  652. rollupKey, _ := attrView.GetKey(cell.Value.KeyID)
  653. if nil == rollupKey || nil == rollupKey.Rollup {
  654. break
  655. }
  656. relKey, _ := attrView.GetKey(rollupKey.Rollup.RelationKeyID)
  657. if nil == relKey || nil == relKey.Relation {
  658. break
  659. }
  660. relVal := attrView.GetValue(relKey.ID, row.ID)
  661. if nil == relVal || nil == relVal.Relation {
  662. break
  663. }
  664. destAv, _ := av.ParseAttributeView(relKey.Relation.AvID)
  665. if nil == destAv {
  666. break
  667. }
  668. for _, blockID := range relVal.Relation.BlockIDs {
  669. cell.Value.Rollup.Contents = append(cell.Value.Rollup.Contents, destAv.GetValue(rollupKey.Rollup.KeyID, blockID).String())
  670. }
  671. case av.KeyTypeRelation: // 渲染关联列
  672. relKey, _ := attrView.GetKey(cell.Value.KeyID)
  673. if nil != relKey && nil != relKey.Relation {
  674. destAv, _ := av.ParseAttributeView(relKey.Relation.AvID)
  675. if nil != destAv {
  676. blocks := map[string]string{}
  677. for _, blockValue := range destAv.GetBlockKeyValues().Values {
  678. blocks[blockValue.BlockID] = blockValue.Block.Content
  679. }
  680. for _, blockID := range cell.Value.Relation.BlockIDs {
  681. cell.Value.Relation.Contents = append(cell.Value.Relation.Contents, blocks[blockID])
  682. }
  683. }
  684. }
  685. case av.KeyTypeCreated: // 渲染创建时间
  686. createdStr := row.ID[:len("20060102150405")]
  687. created, parseErr := time.ParseInLocation("20060102150405", createdStr, time.Local)
  688. if nil == parseErr {
  689. cell.Value.Created = av.NewFormattedValueCreated(created.UnixMilli(), 0, av.CreatedFormatNone)
  690. cell.Value.Created.IsNotEmpty = true
  691. } else {
  692. cell.Value.Created = av.NewFormattedValueCreated(time.Now().UnixMilli(), 0, av.CreatedFormatNone)
  693. }
  694. case av.KeyTypeUpdated: // 渲染更新时间
  695. ial := map[string]string{}
  696. block := row.GetBlockValue()
  697. if nil != block && !block.IsDetached {
  698. ial = GetBlockAttrsWithoutWaitWriting(row.ID)
  699. }
  700. updatedStr := ial["updated"]
  701. if "" == updatedStr && nil != block {
  702. cell.Value.Updated = av.NewFormattedValueUpdated(block.Block.Updated, 0, av.UpdatedFormatNone)
  703. cell.Value.Updated.IsNotEmpty = true
  704. } else {
  705. updated, parseErr := time.ParseInLocation("20060102150405", updatedStr, time.Local)
  706. if nil == parseErr {
  707. cell.Value.Updated = av.NewFormattedValueUpdated(updated.UnixMilli(), 0, av.UpdatedFormatNone)
  708. cell.Value.Updated.IsNotEmpty = true
  709. } else {
  710. cell.Value.Updated = av.NewFormattedValueUpdated(time.Now().UnixMilli(), 0, av.UpdatedFormatNone)
  711. }
  712. }
  713. }
  714. }
  715. }
  716. // 自定义排序
  717. sortRowIDs := map[string]int{}
  718. if 0 < len(view.Table.RowIDs) {
  719. for i, rowID := range view.Table.RowIDs {
  720. sortRowIDs[rowID] = i
  721. }
  722. }
  723. sort.Slice(ret.Rows, func(i, j int) bool {
  724. iv := sortRowIDs[ret.Rows[i].ID]
  725. jv := sortRowIDs[ret.Rows[j].ID]
  726. if iv == jv {
  727. return ret.Rows[i].ID < ret.Rows[j].ID
  728. }
  729. return iv < jv
  730. })
  731. return
  732. }
  733. func getRowBlockValue(keyValues []*av.KeyValues) (ret *av.Value) {
  734. for _, kv := range keyValues {
  735. if av.KeyTypeBlock == kv.Key.Type && 0 < len(kv.Values) {
  736. ret = kv.Values[0]
  737. break
  738. }
  739. }
  740. return
  741. }
  742. func (tx *Transaction) doUpdateAttrViewColRollup(operation *Operation) (ret *TxErr) {
  743. err := updateAttributeViewColRollup(operation)
  744. if nil != err {
  745. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  746. }
  747. return
  748. }
  749. func updateAttributeViewColRollup(operation *Operation) (err error) {
  750. // operation.AvID 汇总列所在 av
  751. // operation.ID 汇总列 ID
  752. // operation.ParentID 汇总列基于的关联列 ID
  753. // operation.KeyID 目标列 ID
  754. // operation.Data 计算方式
  755. attrView, err := av.ParseAttributeView(operation.AvID)
  756. if nil != err {
  757. return
  758. }
  759. rollUpKey, _ := attrView.GetKey(operation.ID)
  760. if nil == rollUpKey {
  761. return
  762. }
  763. rollUpKey.Rollup = &av.Rollup{
  764. RelationKeyID: operation.ParentID,
  765. KeyID: operation.KeyID,
  766. }
  767. if "" != operation.Data {
  768. if err = gulu.JSON.UnmarshalJSON([]byte(operation.Data.(string)), &rollUpKey.Rollup.Calc); nil != err {
  769. return
  770. }
  771. }
  772. err = av.SaveAttributeView(attrView)
  773. return
  774. }
  775. func (tx *Transaction) doUpdateAttrViewColRelation(operation *Operation) (ret *TxErr) {
  776. err := updateAttributeViewColRelation(operation)
  777. if nil != err {
  778. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  779. }
  780. return
  781. }
  782. func updateAttributeViewColRelation(operation *Operation) (err error) {
  783. // operation.AvID 源 avID
  784. // operation.ID 目标 avID
  785. // operation.KeyID 源 av 关联列 ID
  786. // operation.IsTwoWay 是否双向关联
  787. // operation.BackRelationKeyID 双向关联的目标关联列 ID
  788. // operation.Name 双向关联的目标关联列名称
  789. // operation.Format 源 av 关联列名称
  790. srcAv, err := av.ParseAttributeView(operation.AvID)
  791. if nil != err {
  792. return
  793. }
  794. destAv, err := av.ParseAttributeView(operation.ID)
  795. if nil != err {
  796. return
  797. }
  798. isSameAv := srcAv.ID == destAv.ID
  799. if isSameAv {
  800. destAv = srcAv
  801. }
  802. for _, keyValues := range srcAv.KeyValues {
  803. if keyValues.Key.ID != operation.KeyID {
  804. continue
  805. }
  806. srcRel := keyValues.Key.Relation
  807. // 已经设置过双向关联的话需要先断开双向关联
  808. if nil != srcRel && srcRel.IsTwoWay {
  809. oldDestAv, _ := av.ParseAttributeView(srcRel.AvID)
  810. if nil != oldDestAv {
  811. isOldSameAv := oldDestAv.ID == destAv.ID
  812. if isOldSameAv {
  813. oldDestAv = destAv
  814. }
  815. oldDestKey, _ := oldDestAv.GetKey(srcRel.BackKeyID)
  816. if nil != oldDestKey && nil != oldDestKey.Relation && oldDestKey.Relation.AvID == srcAv.ID && oldDestKey.Relation.IsTwoWay {
  817. oldDestKey.Relation.IsTwoWay = false
  818. oldDestKey.Relation.BackKeyID = ""
  819. }
  820. if !isOldSameAv {
  821. err = av.SaveAttributeView(oldDestAv)
  822. if nil != err {
  823. return
  824. }
  825. }
  826. }
  827. }
  828. srcRel = &av.Relation{
  829. AvID: operation.ID,
  830. IsTwoWay: operation.IsTwoWay,
  831. }
  832. if operation.IsTwoWay {
  833. srcRel.BackKeyID = operation.BackRelationKeyID
  834. } else {
  835. srcRel.BackKeyID = ""
  836. }
  837. keyValues.Key.Relation = srcRel
  838. keyValues.Key.Name = operation.Format
  839. break
  840. }
  841. destAdded := false
  842. backRelKey, _ := destAv.GetKey(operation.BackRelationKeyID)
  843. if nil != backRelKey {
  844. backRelKey.Relation = &av.Relation{
  845. AvID: operation.AvID,
  846. IsTwoWay: operation.IsTwoWay,
  847. BackKeyID: operation.KeyID,
  848. }
  849. destAdded = true
  850. if operation.IsTwoWay {
  851. name := strings.TrimSpace(operation.Name)
  852. if "" == name {
  853. name = srcAv.Name + " " + operation.Format
  854. }
  855. backRelKey.Name = strings.TrimSpace(name)
  856. }
  857. }
  858. if !destAdded {
  859. if operation.IsTwoWay {
  860. name := strings.TrimSpace(operation.Name)
  861. if "" == name {
  862. name = srcAv.Name + " " + operation.Format
  863. }
  864. destAv.KeyValues = append(destAv.KeyValues, &av.KeyValues{
  865. Key: &av.Key{
  866. ID: operation.BackRelationKeyID,
  867. Name: name,
  868. Type: av.KeyTypeRelation,
  869. Relation: &av.Relation{AvID: operation.AvID, IsTwoWay: operation.IsTwoWay, BackKeyID: operation.KeyID},
  870. },
  871. })
  872. for _, v := range destAv.Views {
  873. switch v.LayoutType {
  874. case av.LayoutTypeTable:
  875. v.Table.Columns = append(v.Table.Columns, &av.ViewTableColumn{ID: operation.BackRelationKeyID})
  876. }
  877. }
  878. }
  879. }
  880. err = av.SaveAttributeView(srcAv)
  881. if nil != err {
  882. return
  883. }
  884. if !isSameAv {
  885. err = av.SaveAttributeView(destAv)
  886. util.BroadcastByType("protyle", "refreshAttributeView", 0, "", map[string]interface{}{"id": destAv.ID})
  887. }
  888. return
  889. }
  890. func (tx *Transaction) doSortAttrViewView(operation *Operation) (ret *TxErr) {
  891. avID := operation.AvID
  892. attrView, err := av.ParseAttributeView(avID)
  893. if nil != err {
  894. logging.LogErrorf("parse attribute view [%s] failed: %s", operation.AvID, err)
  895. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  896. }
  897. viewID := operation.ID
  898. previewViewID := operation.PreviousID
  899. if viewID == previewViewID {
  900. return
  901. }
  902. var view *av.View
  903. var index, previousIndex int
  904. for i, v := range attrView.Views {
  905. if v.ID == viewID {
  906. view = v
  907. index = i
  908. break
  909. }
  910. }
  911. if nil == view {
  912. return
  913. }
  914. attrView.Views = append(attrView.Views[:index], attrView.Views[index+1:]...)
  915. for i, v := range attrView.Views {
  916. if v.ID == previewViewID {
  917. previousIndex = i + 1
  918. break
  919. }
  920. }
  921. attrView.Views = util.InsertElem(attrView.Views, previousIndex, view)
  922. if err = av.SaveAttributeView(attrView); nil != err {
  923. logging.LogErrorf("save attribute view [%s] failed: %s", avID, err)
  924. return &TxErr{code: TxErrCodeWriteTree, msg: err.Error(), id: avID}
  925. }
  926. return
  927. }
  928. func (tx *Transaction) doRemoveAttrViewView(operation *Operation) (ret *TxErr) {
  929. var err error
  930. avID := operation.AvID
  931. attrView, err := av.ParseAttributeView(avID)
  932. if nil != err {
  933. logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
  934. return &TxErr{code: TxErrCodeBlockNotFound, id: avID}
  935. }
  936. if 1 >= len(attrView.Views) {
  937. logging.LogWarnf("can't remove last view [%s] of attribute view [%s]", operation.ID, avID)
  938. return
  939. }
  940. viewID := operation.ID
  941. var index int
  942. for i, view := range attrView.Views {
  943. if viewID == view.ID {
  944. attrView.Views = append(attrView.Views[:i], attrView.Views[i+1:]...)
  945. index = i - 1
  946. break
  947. }
  948. }
  949. if 0 > index {
  950. index = 0
  951. }
  952. attrView.ViewID = attrView.Views[index].ID
  953. if err = av.SaveAttributeView(attrView); nil != err {
  954. logging.LogErrorf("save attribute view [%s] failed: %s", avID, err)
  955. return &TxErr{code: TxErrCodeWriteTree, msg: err.Error(), id: avID}
  956. }
  957. return
  958. }
  959. func (tx *Transaction) doDuplicateAttrViewView(operation *Operation) (ret *TxErr) {
  960. var err error
  961. avID := operation.AvID
  962. attrView, err := av.ParseAttributeView(avID)
  963. if nil != err {
  964. logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
  965. return &TxErr{code: TxErrWriteAttributeView, id: avID}
  966. }
  967. masterView := attrView.GetView(operation.PreviousID)
  968. if nil == masterView {
  969. logging.LogErrorf("get master view failed: %s", avID)
  970. return &TxErr{code: TxErrWriteAttributeView, id: avID}
  971. }
  972. view := av.NewTableView()
  973. view.ID = operation.ID
  974. attrView.Views = append(attrView.Views, view)
  975. attrView.ViewID = view.ID
  976. view.Icon = masterView.Icon
  977. view.Name = attrView.GetDuplicateViewName(masterView.Name)
  978. view.LayoutType = masterView.LayoutType
  979. for _, col := range masterView.Table.Columns {
  980. view.Table.Columns = append(view.Table.Columns, &av.ViewTableColumn{
  981. ID: col.ID,
  982. Wrap: col.Wrap,
  983. Hidden: col.Hidden,
  984. Pin: col.Pin,
  985. Width: col.Width,
  986. Calc: col.Calc,
  987. })
  988. }
  989. for _, filter := range masterView.Table.Filters {
  990. view.Table.Filters = append(view.Table.Filters, &av.ViewFilter{
  991. Column: filter.Column,
  992. Operator: filter.Operator,
  993. Value: filter.Value,
  994. })
  995. }
  996. for _, s := range masterView.Table.Sorts {
  997. view.Table.Sorts = append(view.Table.Sorts, &av.ViewSort{
  998. Column: s.Column,
  999. Order: s.Order,
  1000. })
  1001. }
  1002. view.Table.PageSize = masterView.Table.PageSize
  1003. view.Table.RowIDs = masterView.Table.RowIDs
  1004. if err = av.SaveAttributeView(attrView); nil != err {
  1005. logging.LogErrorf("save attribute view [%s] failed: %s", avID, err)
  1006. return &TxErr{code: TxErrWriteAttributeView, msg: err.Error(), id: avID}
  1007. }
  1008. return
  1009. }
  1010. func (tx *Transaction) doAddAttrViewView(operation *Operation) (ret *TxErr) {
  1011. var err error
  1012. avID := operation.AvID
  1013. attrView, err := av.ParseAttributeView(avID)
  1014. if nil != err {
  1015. logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
  1016. return &TxErr{code: TxErrWriteAttributeView, id: avID}
  1017. }
  1018. firstView := attrView.Views[0]
  1019. if nil == firstView {
  1020. logging.LogErrorf("get first view failed: %s", avID)
  1021. return &TxErr{code: TxErrWriteAttributeView, id: avID}
  1022. }
  1023. view := av.NewTableView()
  1024. view.ID = operation.ID
  1025. attrView.Views = append(attrView.Views, view)
  1026. attrView.ViewID = view.ID
  1027. for _, col := range firstView.Table.Columns {
  1028. view.Table.Columns = append(view.Table.Columns, &av.ViewTableColumn{ID: col.ID})
  1029. }
  1030. view.Table.RowIDs = firstView.Table.RowIDs
  1031. if err = av.SaveAttributeView(attrView); nil != err {
  1032. logging.LogErrorf("save attribute view [%s] failed: %s", avID, err)
  1033. return &TxErr{code: TxErrWriteAttributeView, msg: err.Error(), id: avID}
  1034. }
  1035. return
  1036. }
  1037. func (tx *Transaction) doSetAttrViewViewName(operation *Operation) (ret *TxErr) {
  1038. var err error
  1039. avID := operation.AvID
  1040. attrView, err := av.ParseAttributeView(avID)
  1041. if nil != err {
  1042. logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
  1043. return &TxErr{code: TxErrWriteAttributeView, id: avID}
  1044. }
  1045. viewID := operation.ID
  1046. view := attrView.GetView(viewID)
  1047. if nil == view {
  1048. logging.LogErrorf("get view [%s] failed: %s", viewID, err)
  1049. return &TxErr{code: TxErrWriteAttributeView, id: viewID}
  1050. }
  1051. view.Name = strings.TrimSpace(operation.Data.(string))
  1052. if err = av.SaveAttributeView(attrView); nil != err {
  1053. logging.LogErrorf("save attribute view [%s] failed: %s", avID, err)
  1054. return &TxErr{code: TxErrWriteAttributeView, msg: err.Error(), id: avID}
  1055. }
  1056. return
  1057. }
  1058. func (tx *Transaction) doSetAttrViewViewIcon(operation *Operation) (ret *TxErr) {
  1059. var err error
  1060. avID := operation.AvID
  1061. attrView, err := av.ParseAttributeView(avID)
  1062. if nil != err {
  1063. logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
  1064. return &TxErr{code: TxErrWriteAttributeView, id: avID}
  1065. }
  1066. viewID := operation.ID
  1067. view := attrView.GetView(viewID)
  1068. if nil == view {
  1069. logging.LogErrorf("get view [%s] failed: %s", viewID, err)
  1070. return &TxErr{code: TxErrWriteAttributeView, id: viewID}
  1071. }
  1072. view.Icon = operation.Data.(string)
  1073. if err = av.SaveAttributeView(attrView); nil != err {
  1074. logging.LogErrorf("save attribute view [%s] failed: %s", avID, err)
  1075. return &TxErr{code: TxErrWriteAttributeView, msg: err.Error(), id: avID}
  1076. }
  1077. return
  1078. }
  1079. func (tx *Transaction) doSetAttrViewName(operation *Operation) (ret *TxErr) {
  1080. err := setAttributeViewName(operation)
  1081. if nil != err {
  1082. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1083. }
  1084. return
  1085. }
  1086. func setAttributeViewName(operation *Operation) (err error) {
  1087. attrView, err := av.ParseAttributeView(operation.ID)
  1088. if nil != err {
  1089. return
  1090. }
  1091. attrView.Name = strings.TrimSpace(operation.Data.(string))
  1092. err = av.SaveAttributeView(attrView)
  1093. return
  1094. }
  1095. func (tx *Transaction) doSetAttrViewFilters(operation *Operation) (ret *TxErr) {
  1096. err := setAttributeViewFilters(operation)
  1097. if nil != err {
  1098. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1099. }
  1100. return
  1101. }
  1102. func setAttributeViewFilters(operation *Operation) (err error) {
  1103. attrView, err := av.ParseAttributeView(operation.AvID)
  1104. if nil != err {
  1105. return
  1106. }
  1107. view, err := attrView.GetCurrentView()
  1108. if nil != err {
  1109. return
  1110. }
  1111. operationData := operation.Data.([]interface{})
  1112. data, err := gulu.JSON.MarshalJSON(operationData)
  1113. if nil != err {
  1114. return
  1115. }
  1116. switch view.LayoutType {
  1117. case av.LayoutTypeTable:
  1118. if err = gulu.JSON.UnmarshalJSON(data, &view.Table.Filters); nil != err {
  1119. return
  1120. }
  1121. }
  1122. for _, filter := range view.Table.Filters {
  1123. var key *av.Key
  1124. key, err = attrView.GetKey(filter.Column)
  1125. if nil != err {
  1126. return
  1127. }
  1128. filter.Value.Type = key.Type
  1129. }
  1130. err = av.SaveAttributeView(attrView)
  1131. return
  1132. }
  1133. func (tx *Transaction) doSetAttrViewSorts(operation *Operation) (ret *TxErr) {
  1134. err := setAttributeViewSorts(operation)
  1135. if nil != err {
  1136. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1137. }
  1138. return
  1139. }
  1140. func setAttributeViewSorts(operation *Operation) (err error) {
  1141. attrView, err := av.ParseAttributeView(operation.AvID)
  1142. if nil != err {
  1143. return
  1144. }
  1145. view, err := attrView.GetCurrentView()
  1146. if nil != err {
  1147. return
  1148. }
  1149. operationData := operation.Data.([]interface{})
  1150. data, err := gulu.JSON.MarshalJSON(operationData)
  1151. if nil != err {
  1152. return
  1153. }
  1154. switch view.LayoutType {
  1155. case av.LayoutTypeTable:
  1156. if err = gulu.JSON.UnmarshalJSON(data, &view.Table.Sorts); nil != err {
  1157. return
  1158. }
  1159. }
  1160. err = av.SaveAttributeView(attrView)
  1161. return
  1162. }
  1163. func (tx *Transaction) doSetAttrViewPageSize(operation *Operation) (ret *TxErr) {
  1164. err := setAttributeViewPageSize(operation)
  1165. if nil != err {
  1166. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1167. }
  1168. return
  1169. }
  1170. func setAttributeViewPageSize(operation *Operation) (err error) {
  1171. attrView, err := av.ParseAttributeView(operation.AvID)
  1172. if nil != err {
  1173. return
  1174. }
  1175. view, err := attrView.GetCurrentView()
  1176. if nil != err {
  1177. return
  1178. }
  1179. switch view.LayoutType {
  1180. case av.LayoutTypeTable:
  1181. view.Table.PageSize = int(operation.Data.(float64))
  1182. }
  1183. err = av.SaveAttributeView(attrView)
  1184. return
  1185. }
  1186. func (tx *Transaction) doSetAttrViewColCalc(operation *Operation) (ret *TxErr) {
  1187. err := setAttributeViewColumnCalc(operation)
  1188. if nil != err {
  1189. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1190. }
  1191. return
  1192. }
  1193. func setAttributeViewColumnCalc(operation *Operation) (err error) {
  1194. attrView, err := av.ParseAttributeView(operation.AvID)
  1195. if nil != err {
  1196. return
  1197. }
  1198. view, err := attrView.GetCurrentView()
  1199. if nil != err {
  1200. return
  1201. }
  1202. operationData := operation.Data.(interface{})
  1203. data, err := gulu.JSON.MarshalJSON(operationData)
  1204. if nil != err {
  1205. return
  1206. }
  1207. calc := &av.ColumnCalc{}
  1208. switch view.LayoutType {
  1209. case av.LayoutTypeTable:
  1210. if err = gulu.JSON.UnmarshalJSON(data, calc); nil != err {
  1211. return
  1212. }
  1213. for _, column := range view.Table.Columns {
  1214. if column.ID == operation.ID {
  1215. column.Calc = calc
  1216. break
  1217. }
  1218. }
  1219. }
  1220. err = av.SaveAttributeView(attrView)
  1221. return
  1222. }
  1223. func (tx *Transaction) doInsertAttrViewBlock(operation *Operation) (ret *TxErr) {
  1224. for _, id := range operation.SrcIDs {
  1225. tree, err := tx.loadTree(id)
  1226. if nil != err && !operation.IsDetached {
  1227. logging.LogErrorf("load tree [%s] failed: %s", id, err)
  1228. return &TxErr{code: TxErrCodeBlockNotFound, id: id, msg: err.Error()}
  1229. }
  1230. var avErr error
  1231. if avErr = addAttributeViewBlock(id, operation, tree, tx); nil != avErr {
  1232. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: avErr.Error()}
  1233. }
  1234. }
  1235. return
  1236. }
  1237. func addAttributeViewBlock(blockID string, operation *Operation, tree *parse.Tree, tx *Transaction) (err error) {
  1238. var node *ast.Node
  1239. if !operation.IsDetached {
  1240. node = treenode.GetNodeInTree(tree, blockID)
  1241. if nil == node {
  1242. err = ErrBlockNotFound
  1243. return
  1244. }
  1245. if ast.NodeAttributeView == node.Type {
  1246. // 不能将一个属性视图拖拽到另一个属性视图中
  1247. return
  1248. }
  1249. } else {
  1250. if "" == blockID {
  1251. blockID = ast.NewNodeID()
  1252. logging.LogWarnf("detached block id is empty, generate a new one [%s]", blockID)
  1253. }
  1254. }
  1255. attrView, err := av.ParseAttributeView(operation.AvID)
  1256. if nil != err {
  1257. return
  1258. }
  1259. // 不允许重复添加相同的块到属性视图中
  1260. blockValues := attrView.GetBlockKeyValues()
  1261. for _, blockValue := range blockValues.Values {
  1262. if blockValue.Block.ID == blockID {
  1263. return
  1264. }
  1265. }
  1266. var content string
  1267. if !operation.IsDetached {
  1268. content = getNodeRefText(node)
  1269. }
  1270. now := time.Now().UnixMilli()
  1271. 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}}
  1272. blockValues.Values = append(blockValues.Values, blockValue)
  1273. // 如果存在过滤条件,则将过滤条件应用到新添加的块上
  1274. view, _ := attrView.GetCurrentView()
  1275. if nil != view && 0 < len(view.Table.Filters) {
  1276. viewable, _ := renderAttributeViewTable(attrView, view)
  1277. viewable.FilterRows()
  1278. viewable.SortRows()
  1279. if 0 < len(viewable.Rows) {
  1280. row := GetLastSortRow(viewable.Rows)
  1281. if nil != row {
  1282. for _, filter := range view.Table.Filters {
  1283. for _, cell := range row.Cells {
  1284. if nil != cell.Value && cell.Value.KeyID == filter.Column {
  1285. if av.KeyTypeBlock == cell.ValueType {
  1286. blockValue.Block.Content = cell.Value.Block.Content
  1287. continue
  1288. }
  1289. newValue := cell.Value.Clone()
  1290. newValue.ID = ast.NewNodeID()
  1291. newValue.BlockID = blockID
  1292. newValue.IsDetached = operation.IsDetached
  1293. newValue.IsInitialized = false
  1294. values, _ := attrView.GetKeyValues(filter.Column)
  1295. values.Values = append(values.Values, newValue)
  1296. }
  1297. }
  1298. }
  1299. }
  1300. }
  1301. }
  1302. if !operation.IsDetached {
  1303. attrs := parse.IAL2Map(node.KramdownIAL)
  1304. if "" == attrs[av.NodeAttrNameAvs] {
  1305. attrs[av.NodeAttrNameAvs] = operation.AvID
  1306. } else {
  1307. avIDs := strings.Split(attrs[av.NodeAttrNameAvs], ",")
  1308. avIDs = append(avIDs, operation.AvID)
  1309. avIDs = gulu.Str.RemoveDuplicatedElem(avIDs)
  1310. attrs[av.NodeAttrNameAvs] = strings.Join(avIDs, ",")
  1311. }
  1312. if err = setNodeAttrsWithTx(tx, node, tree, attrs); nil != err {
  1313. return
  1314. }
  1315. }
  1316. for _, view := range attrView.Views {
  1317. switch view.LayoutType {
  1318. case av.LayoutTypeTable:
  1319. if "" != operation.PreviousID {
  1320. changed := false
  1321. for i, id := range view.Table.RowIDs {
  1322. if id == operation.PreviousID {
  1323. view.Table.RowIDs = append(view.Table.RowIDs[:i+1], append([]string{blockID}, view.Table.RowIDs[i+1:]...)...)
  1324. changed = true
  1325. break
  1326. }
  1327. }
  1328. if !changed {
  1329. view.Table.RowIDs = append(view.Table.RowIDs, blockID)
  1330. }
  1331. } else {
  1332. view.Table.RowIDs = append([]string{blockID}, view.Table.RowIDs...)
  1333. }
  1334. }
  1335. }
  1336. err = av.SaveAttributeView(attrView)
  1337. return
  1338. }
  1339. func GetLastSortRow(rows []*av.TableRow) *av.TableRow {
  1340. for i := len(rows) - 1; i >= 0; i-- {
  1341. row := rows[i]
  1342. block := row.GetBlockValue()
  1343. if nil != block && !block.NotAffectFilter() {
  1344. return row
  1345. }
  1346. }
  1347. return nil
  1348. }
  1349. func (tx *Transaction) doRemoveAttrViewBlock(operation *Operation) (ret *TxErr) {
  1350. err := tx.removeAttributeViewBlock(operation)
  1351. if nil != err {
  1352. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID}
  1353. }
  1354. return
  1355. }
  1356. func (tx *Transaction) removeAttributeViewBlock(operation *Operation) (err error) {
  1357. attrView, err := av.ParseAttributeView(operation.AvID)
  1358. if nil != err {
  1359. return
  1360. }
  1361. trees := map[string]*parse.Tree{}
  1362. for _, keyValues := range attrView.KeyValues {
  1363. tmp := keyValues.Values[:0]
  1364. for i, values := range keyValues.Values {
  1365. if !gulu.Str.Contains(values.BlockID, operation.SrcIDs) {
  1366. tmp = append(tmp, keyValues.Values[i])
  1367. } else {
  1368. // Remove av block also remove node attr https://github.com/siyuan-note/siyuan/issues/9091#issuecomment-1709824006
  1369. if bt := treenode.GetBlockTree(values.BlockID); nil != bt {
  1370. tree := trees[bt.RootID]
  1371. if nil == tree {
  1372. tree, _ = loadTreeByBlockID(values.BlockID)
  1373. }
  1374. if nil != tree {
  1375. trees[bt.RootID] = tree
  1376. if node := treenode.GetNodeInTree(tree, values.BlockID); nil != node {
  1377. attrs := parse.IAL2Map(node.KramdownIAL)
  1378. if ast.NodeDocument == node.Type {
  1379. delete(attrs, "custom-hidden")
  1380. node.RemoveIALAttr("custom-hidden")
  1381. }
  1382. if avs := attrs[av.NodeAttrNameAvs]; "" != avs {
  1383. avIDs := strings.Split(avs, ",")
  1384. avIDs = gulu.Str.RemoveElem(avIDs, operation.AvID)
  1385. if 0 == len(avIDs) {
  1386. delete(attrs, av.NodeAttrNameAvs)
  1387. node.RemoveIALAttr(av.NodeAttrNameAvs)
  1388. } else {
  1389. attrs[av.NodeAttrNameAvs] = strings.Join(avIDs, ",")
  1390. node.SetIALAttr(av.NodeAttrNameAvs, strings.Join(avIDs, ","))
  1391. }
  1392. }
  1393. if err = setNodeAttrsWithTx(tx, node, tree, attrs); nil != err {
  1394. return
  1395. }
  1396. }
  1397. }
  1398. }
  1399. }
  1400. }
  1401. keyValues.Values = tmp
  1402. }
  1403. for _, view := range attrView.Views {
  1404. for _, blockID := range operation.SrcIDs {
  1405. view.Table.RowIDs = gulu.Str.RemoveElem(view.Table.RowIDs, blockID)
  1406. }
  1407. }
  1408. err = av.SaveAttributeView(attrView)
  1409. return
  1410. }
  1411. func (tx *Transaction) doSetAttrViewColumnWidth(operation *Operation) (ret *TxErr) {
  1412. err := setAttributeViewColWidth(operation)
  1413. if nil != err {
  1414. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1415. }
  1416. return
  1417. }
  1418. func setAttributeViewColWidth(operation *Operation) (err error) {
  1419. attrView, err := av.ParseAttributeView(operation.AvID)
  1420. if nil != err {
  1421. return
  1422. }
  1423. view, err := attrView.GetCurrentView()
  1424. if nil != err {
  1425. return
  1426. }
  1427. switch view.LayoutType {
  1428. case av.LayoutTypeTable:
  1429. for _, column := range view.Table.Columns {
  1430. if column.ID == operation.ID {
  1431. column.Width = operation.Data.(string)
  1432. break
  1433. }
  1434. }
  1435. }
  1436. err = av.SaveAttributeView(attrView)
  1437. return
  1438. }
  1439. func (tx *Transaction) doSetAttrViewColumnWrap(operation *Operation) (ret *TxErr) {
  1440. err := setAttributeViewColWrap(operation)
  1441. if nil != err {
  1442. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1443. }
  1444. return
  1445. }
  1446. func setAttributeViewColWrap(operation *Operation) (err error) {
  1447. attrView, err := av.ParseAttributeView(operation.AvID)
  1448. if nil != err {
  1449. return
  1450. }
  1451. view, err := attrView.GetCurrentView()
  1452. if nil != err {
  1453. return
  1454. }
  1455. switch view.LayoutType {
  1456. case av.LayoutTypeTable:
  1457. for _, column := range view.Table.Columns {
  1458. if column.ID == operation.ID {
  1459. column.Wrap = operation.Data.(bool)
  1460. break
  1461. }
  1462. }
  1463. }
  1464. err = av.SaveAttributeView(attrView)
  1465. return
  1466. }
  1467. func (tx *Transaction) doSetAttrViewColumnHidden(operation *Operation) (ret *TxErr) {
  1468. err := setAttributeViewColHidden(operation)
  1469. if nil != err {
  1470. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1471. }
  1472. return
  1473. }
  1474. func setAttributeViewColHidden(operation *Operation) (err error) {
  1475. attrView, err := av.ParseAttributeView(operation.AvID)
  1476. if nil != err {
  1477. return
  1478. }
  1479. view, err := attrView.GetCurrentView()
  1480. if nil != err {
  1481. return
  1482. }
  1483. switch view.LayoutType {
  1484. case av.LayoutTypeTable:
  1485. for _, column := range view.Table.Columns {
  1486. if column.ID == operation.ID {
  1487. column.Hidden = operation.Data.(bool)
  1488. break
  1489. }
  1490. }
  1491. }
  1492. err = av.SaveAttributeView(attrView)
  1493. return
  1494. }
  1495. func (tx *Transaction) doSetAttrViewColumnPin(operation *Operation) (ret *TxErr) {
  1496. err := setAttributeViewColPin(operation)
  1497. if nil != err {
  1498. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1499. }
  1500. return
  1501. }
  1502. func setAttributeViewColPin(operation *Operation) (err error) {
  1503. attrView, err := av.ParseAttributeView(operation.AvID)
  1504. if nil != err {
  1505. return
  1506. }
  1507. view, err := attrView.GetCurrentView()
  1508. if nil != err {
  1509. return
  1510. }
  1511. switch view.LayoutType {
  1512. case av.LayoutTypeTable:
  1513. for _, column := range view.Table.Columns {
  1514. if column.ID == operation.ID {
  1515. column.Pin = operation.Data.(bool)
  1516. break
  1517. }
  1518. }
  1519. }
  1520. err = av.SaveAttributeView(attrView)
  1521. return
  1522. }
  1523. func (tx *Transaction) doSetAttrViewColumnIcon(operation *Operation) (ret *TxErr) {
  1524. err := setAttributeViewColIcon(operation)
  1525. if nil != err {
  1526. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1527. }
  1528. return
  1529. }
  1530. func setAttributeViewColIcon(operation *Operation) (err error) {
  1531. attrView, err := av.ParseAttributeView(operation.AvID)
  1532. if nil != err {
  1533. return
  1534. }
  1535. for _, keyValues := range attrView.KeyValues {
  1536. if keyValues.Key.ID == operation.ID {
  1537. keyValues.Key.Icon = operation.Data.(string)
  1538. break
  1539. }
  1540. }
  1541. err = av.SaveAttributeView(attrView)
  1542. return
  1543. }
  1544. func (tx *Transaction) doSortAttrViewRow(operation *Operation) (ret *TxErr) {
  1545. err := sortAttributeViewRow(operation)
  1546. if nil != err {
  1547. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1548. }
  1549. return
  1550. }
  1551. func sortAttributeViewRow(operation *Operation) (err error) {
  1552. attrView, err := av.ParseAttributeView(operation.AvID)
  1553. if nil != err {
  1554. return
  1555. }
  1556. view, err := attrView.GetCurrentView()
  1557. if nil != err {
  1558. return
  1559. }
  1560. var rowID string
  1561. var index, previousIndex int
  1562. for i, r := range view.Table.RowIDs {
  1563. if r == operation.ID {
  1564. rowID = r
  1565. index = i
  1566. break
  1567. }
  1568. }
  1569. if "" == rowID {
  1570. rowID = operation.ID
  1571. view.Table.RowIDs = append(view.Table.RowIDs, rowID)
  1572. index = len(view.Table.RowIDs) - 1
  1573. }
  1574. switch view.LayoutType {
  1575. case av.LayoutTypeTable:
  1576. view.Table.RowIDs = append(view.Table.RowIDs[:index], view.Table.RowIDs[index+1:]...)
  1577. for i, r := range view.Table.RowIDs {
  1578. if r == operation.PreviousID {
  1579. previousIndex = i + 1
  1580. break
  1581. }
  1582. }
  1583. view.Table.RowIDs = util.InsertElem(view.Table.RowIDs, previousIndex, rowID)
  1584. }
  1585. err = av.SaveAttributeView(attrView)
  1586. return
  1587. }
  1588. func (tx *Transaction) doSortAttrViewColumn(operation *Operation) (ret *TxErr) {
  1589. err := sortAttributeViewColumn(operation)
  1590. if nil != err {
  1591. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1592. }
  1593. return
  1594. }
  1595. func sortAttributeViewColumn(operation *Operation) (err error) {
  1596. attrView, err := av.ParseAttributeView(operation.AvID)
  1597. if nil != err {
  1598. return
  1599. }
  1600. view, err := attrView.GetCurrentView()
  1601. if nil != err {
  1602. return
  1603. }
  1604. switch view.LayoutType {
  1605. case av.LayoutTypeTable:
  1606. var col *av.ViewTableColumn
  1607. var index, previousIndex int
  1608. for i, column := range view.Table.Columns {
  1609. if column.ID == operation.ID {
  1610. col = column
  1611. index = i
  1612. break
  1613. }
  1614. }
  1615. if nil == col {
  1616. return
  1617. }
  1618. view.Table.Columns = append(view.Table.Columns[:index], view.Table.Columns[index+1:]...)
  1619. for i, column := range view.Table.Columns {
  1620. if column.ID == operation.PreviousID {
  1621. previousIndex = i + 1
  1622. break
  1623. }
  1624. }
  1625. view.Table.Columns = util.InsertElem(view.Table.Columns, previousIndex, col)
  1626. }
  1627. err = av.SaveAttributeView(attrView)
  1628. return
  1629. }
  1630. func (tx *Transaction) doAddAttrViewColumn(operation *Operation) (ret *TxErr) {
  1631. err := addAttributeViewColumn(operation)
  1632. if nil != err {
  1633. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1634. }
  1635. return
  1636. }
  1637. func addAttributeViewColumn(operation *Operation) (err error) {
  1638. attrView, err := av.ParseAttributeView(operation.AvID)
  1639. if nil != err {
  1640. return
  1641. }
  1642. keyType := av.KeyType(operation.Typ)
  1643. switch keyType {
  1644. case av.KeyTypeText, av.KeyTypeNumber, av.KeyTypeDate, av.KeyTypeSelect, av.KeyTypeMSelect, av.KeyTypeURL, av.KeyTypeEmail,
  1645. av.KeyTypePhone, av.KeyTypeMAsset, av.KeyTypeTemplate, av.KeyTypeCreated, av.KeyTypeUpdated, av.KeyTypeCheckbox,
  1646. av.KeyTypeRelation, av.KeyTypeRollup:
  1647. var icon string
  1648. if nil != operation.Data {
  1649. icon = operation.Data.(string)
  1650. }
  1651. key := av.NewKey(operation.ID, operation.Name, icon, keyType)
  1652. attrView.KeyValues = append(attrView.KeyValues, &av.KeyValues{Key: key})
  1653. for _, v := range attrView.Views {
  1654. switch v.LayoutType {
  1655. case av.LayoutTypeTable:
  1656. v.Table.Columns = append(v.Table.Columns, &av.ViewTableColumn{ID: key.ID})
  1657. }
  1658. }
  1659. }
  1660. err = av.SaveAttributeView(attrView)
  1661. return
  1662. }
  1663. func (tx *Transaction) doUpdateAttrViewColTemplate(operation *Operation) (ret *TxErr) {
  1664. err := updateAttributeViewColTemplate(operation)
  1665. if nil != err {
  1666. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1667. }
  1668. return
  1669. }
  1670. func updateAttributeViewColTemplate(operation *Operation) (err error) {
  1671. attrView, err := av.ParseAttributeView(operation.AvID)
  1672. if nil != err {
  1673. return
  1674. }
  1675. colType := av.KeyType(operation.Typ)
  1676. switch colType {
  1677. case av.KeyTypeTemplate:
  1678. for _, keyValues := range attrView.KeyValues {
  1679. if keyValues.Key.ID == operation.ID && av.KeyTypeTemplate == keyValues.Key.Type {
  1680. keyValues.Key.Template = operation.Data.(string)
  1681. break
  1682. }
  1683. }
  1684. }
  1685. err = av.SaveAttributeView(attrView)
  1686. return
  1687. }
  1688. func (tx *Transaction) doUpdateAttrViewColNumberFormat(operation *Operation) (ret *TxErr) {
  1689. err := updateAttributeViewColNumberFormat(operation)
  1690. if nil != err {
  1691. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1692. }
  1693. return
  1694. }
  1695. func updateAttributeViewColNumberFormat(operation *Operation) (err error) {
  1696. attrView, err := av.ParseAttributeView(operation.AvID)
  1697. if nil != err {
  1698. return
  1699. }
  1700. colType := av.KeyType(operation.Typ)
  1701. switch colType {
  1702. case av.KeyTypeNumber:
  1703. for _, keyValues := range attrView.KeyValues {
  1704. if keyValues.Key.ID == operation.ID && av.KeyTypeNumber == keyValues.Key.Type {
  1705. keyValues.Key.NumberFormat = av.NumberFormat(operation.Format)
  1706. break
  1707. }
  1708. }
  1709. }
  1710. err = av.SaveAttributeView(attrView)
  1711. return
  1712. }
  1713. func (tx *Transaction) doUpdateAttrViewColumn(operation *Operation) (ret *TxErr) {
  1714. err := updateAttributeViewColumn(operation)
  1715. if nil != err {
  1716. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1717. }
  1718. return
  1719. }
  1720. func updateAttributeViewColumn(operation *Operation) (err error) {
  1721. attrView, err := av.ParseAttributeView(operation.AvID)
  1722. if nil != err {
  1723. return
  1724. }
  1725. colType := av.KeyType(operation.Typ)
  1726. switch colType {
  1727. case av.KeyTypeBlock, av.KeyTypeText, av.KeyTypeNumber, av.KeyTypeDate, av.KeyTypeSelect, av.KeyTypeMSelect, av.KeyTypeURL, av.KeyTypeEmail,
  1728. av.KeyTypePhone, av.KeyTypeMAsset, av.KeyTypeTemplate, av.KeyTypeCreated, av.KeyTypeUpdated, av.KeyTypeCheckbox,
  1729. av.KeyTypeRelation, av.KeyTypeRollup:
  1730. for _, keyValues := range attrView.KeyValues {
  1731. if keyValues.Key.ID == operation.ID {
  1732. keyValues.Key.Name = strings.TrimSpace(operation.Name)
  1733. keyValues.Key.Type = colType
  1734. break
  1735. }
  1736. }
  1737. }
  1738. err = av.SaveAttributeView(attrView)
  1739. return
  1740. }
  1741. func (tx *Transaction) doRemoveAttrViewColumn(operation *Operation) (ret *TxErr) {
  1742. err := removeAttributeViewColumn(operation)
  1743. if nil != err {
  1744. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1745. }
  1746. return
  1747. }
  1748. func removeAttributeViewColumn(operation *Operation) (err error) {
  1749. attrView, err := av.ParseAttributeView(operation.AvID)
  1750. if nil != err {
  1751. return
  1752. }
  1753. var removedKey *av.Key
  1754. for i, keyValues := range attrView.KeyValues {
  1755. if keyValues.Key.ID == operation.ID {
  1756. attrView.KeyValues = append(attrView.KeyValues[:i], attrView.KeyValues[i+1:]...)
  1757. removedKey = keyValues.Key
  1758. break
  1759. }
  1760. }
  1761. // 删除双向关联的目标列
  1762. if nil != removedKey && nil != removedKey.Relation && removedKey.Relation.IsTwoWay {
  1763. destAv, _ := av.ParseAttributeView(removedKey.Relation.AvID)
  1764. if nil != destAv {
  1765. for i, keyValues := range destAv.KeyValues {
  1766. if keyValues.Key.ID == removedKey.Relation.BackKeyID {
  1767. destAv.KeyValues = append(destAv.KeyValues[:i], destAv.KeyValues[i+1:]...)
  1768. break
  1769. }
  1770. }
  1771. for _, view := range destAv.Views {
  1772. switch view.LayoutType {
  1773. case av.LayoutTypeTable:
  1774. for i, column := range view.Table.Columns {
  1775. if column.ID == removedKey.Relation.BackKeyID {
  1776. view.Table.Columns = append(view.Table.Columns[:i], view.Table.Columns[i+1:]...)
  1777. break
  1778. }
  1779. }
  1780. }
  1781. }
  1782. av.SaveAttributeView(destAv)
  1783. util.BroadcastByType("protyle", "refreshAttributeView", 0, "", map[string]interface{}{"id": destAv.ID})
  1784. }
  1785. }
  1786. for _, view := range attrView.Views {
  1787. switch view.LayoutType {
  1788. case av.LayoutTypeTable:
  1789. for i, column := range view.Table.Columns {
  1790. if column.ID == operation.ID {
  1791. view.Table.Columns = append(view.Table.Columns[:i], view.Table.Columns[i+1:]...)
  1792. break
  1793. }
  1794. }
  1795. }
  1796. }
  1797. err = av.SaveAttributeView(attrView)
  1798. return
  1799. }
  1800. func (tx *Transaction) doReplaceAttrViewBlock(operation *Operation) (ret *TxErr) {
  1801. err := replaceAttributeViewBlock(operation, tx)
  1802. if nil != err {
  1803. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID}
  1804. }
  1805. return
  1806. }
  1807. func replaceAttributeViewBlock(operation *Operation, tx *Transaction) (err error) {
  1808. attrView, err := av.ParseAttributeView(operation.AvID)
  1809. if nil != err {
  1810. return
  1811. }
  1812. var node *ast.Node
  1813. if !operation.IsDetached {
  1814. node, _, _ = getNodeByBlockID(tx, operation.NextID)
  1815. }
  1816. for _, keyValues := range attrView.KeyValues {
  1817. for _, value := range keyValues.Values {
  1818. if value.BlockID == operation.PreviousID {
  1819. if value.BlockID != operation.NextID {
  1820. // 换绑
  1821. unbindBlockAv(tx, operation.AvID, value.BlockID)
  1822. }
  1823. value.BlockID = operation.NextID
  1824. if nil != value.Block {
  1825. value.Block.ID = operation.NextID
  1826. value.IsDetached = operation.IsDetached
  1827. if !operation.IsDetached {
  1828. value.Block.Content = getNodeRefText(node)
  1829. }
  1830. }
  1831. if !operation.IsDetached {
  1832. bindBlockAv(tx, operation.AvID, operation.NextID)
  1833. }
  1834. }
  1835. }
  1836. }
  1837. replacedRowID := false
  1838. for _, v := range attrView.Views {
  1839. switch v.LayoutType {
  1840. case av.LayoutTypeTable:
  1841. for i, rowID := range v.Table.RowIDs {
  1842. if rowID == operation.PreviousID {
  1843. v.Table.RowIDs[i] = operation.NextID
  1844. replacedRowID = true
  1845. break
  1846. }
  1847. }
  1848. if !replacedRowID {
  1849. v.Table.RowIDs = append(v.Table.RowIDs, operation.NextID)
  1850. }
  1851. }
  1852. }
  1853. err = av.SaveAttributeView(attrView)
  1854. return
  1855. }
  1856. func (tx *Transaction) doUpdateAttrViewCell(operation *Operation) (ret *TxErr) {
  1857. err := updateAttributeViewCell(operation, tx)
  1858. if nil != err {
  1859. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  1860. }
  1861. return
  1862. }
  1863. func updateAttributeViewCell(operation *Operation, tx *Transaction) (err error) {
  1864. err = UpdateAttributeViewCell(tx, operation.AvID, operation.KeyID, operation.RowID, operation.ID, operation.Data)
  1865. return
  1866. }
  1867. func UpdateAttributeViewCell(tx *Transaction, avID, keyID, rowID, cellID string, valueData interface{}) (err error) {
  1868. attrView, err := av.ParseAttributeView(avID)
  1869. if nil != err {
  1870. return
  1871. }
  1872. var blockVal *av.Value
  1873. for _, kv := range attrView.KeyValues {
  1874. if av.KeyTypeBlock == kv.Key.Type {
  1875. for _, v := range kv.Values {
  1876. if rowID == v.Block.ID {
  1877. blockVal = v
  1878. break
  1879. }
  1880. }
  1881. break
  1882. }
  1883. }
  1884. var val *av.Value
  1885. oldIsDetached := true
  1886. if nil != blockVal {
  1887. oldIsDetached = blockVal.IsDetached
  1888. }
  1889. for _, keyValues := range attrView.KeyValues {
  1890. if keyID != keyValues.Key.ID {
  1891. continue
  1892. }
  1893. for _, value := range keyValues.Values {
  1894. if cellID == value.ID {
  1895. val = value
  1896. val.Type = keyValues.Key.Type
  1897. break
  1898. }
  1899. }
  1900. if nil == val {
  1901. val = &av.Value{ID: cellID, KeyID: keyValues.Key.ID, BlockID: rowID, Type: keyValues.Key.Type}
  1902. keyValues.Values = append(keyValues.Values, val)
  1903. }
  1904. break
  1905. }
  1906. isUpdatingBlockKey := av.KeyTypeBlock == val.Type
  1907. oldBoundBlockID := val.BlockID
  1908. var oldRelationBlockIDs []string
  1909. if av.KeyTypeRelation == val.Type {
  1910. if nil != val.Relation {
  1911. for _, bID := range val.Relation.BlockIDs {
  1912. oldRelationBlockIDs = append(oldRelationBlockIDs, bID)
  1913. }
  1914. }
  1915. }
  1916. data, err := gulu.JSON.MarshalJSON(valueData)
  1917. if nil != err {
  1918. return
  1919. }
  1920. if err = gulu.JSON.UnmarshalJSON(data, &val); nil != err {
  1921. return
  1922. }
  1923. relationChangeMode := 0 // 0:不变(仅排序),1:增加,2:减少
  1924. if av.KeyTypeRelation == val.Type {
  1925. // 关联列得 content 是自动渲染的,所以不需要保存
  1926. val.Relation.Contents = nil
  1927. // 计算关联排序模式
  1928. if len(oldRelationBlockIDs) == len(val.Relation.BlockIDs) {
  1929. relationChangeMode = 0
  1930. } else {
  1931. if len(oldRelationBlockIDs) > len(val.Relation.BlockIDs) {
  1932. relationChangeMode = 2
  1933. } else {
  1934. relationChangeMode = 1
  1935. }
  1936. }
  1937. }
  1938. // val.IsDetached 只有更新主键的时候才会传入,所以下面需要结合 isUpdatingBlockKey 来判断
  1939. if oldIsDetached { // 之前是游离行
  1940. if !val.IsDetached { // 现在绑定了块
  1941. // 将游离行绑定到新建的块上
  1942. bindBlockAv(tx, avID, rowID)
  1943. }
  1944. } else { // 之前绑定了块
  1945. if isUpdatingBlockKey { // 正在更新主键
  1946. if val.IsDetached { // 现在是游离行
  1947. // 将绑定的块从属性视图中移除
  1948. unbindBlockAv(tx, avID, rowID)
  1949. } else { // 现在绑定了块
  1950. if oldBoundBlockID != val.BlockID { // 之前绑定的块和现在绑定的块不一样
  1951. // 换绑块
  1952. unbindBlockAv(tx, avID, oldBoundBlockID)
  1953. bindBlockAv(tx, avID, val.BlockID)
  1954. } else { // 之前绑定的块和现在绑定的块一样
  1955. // 直接返回,因为锚文本不允许更改
  1956. return
  1957. }
  1958. }
  1959. }
  1960. }
  1961. if nil != blockVal {
  1962. blockVal.Block.Updated = time.Now().UnixMilli()
  1963. blockVal.IsInitialized = true
  1964. if isUpdatingBlockKey {
  1965. blockVal.IsDetached = val.IsDetached
  1966. }
  1967. }
  1968. key, _ := attrView.GetKey(val.KeyID)
  1969. if nil != key && av.KeyTypeRelation == key.Type && nil != key.Relation && key.Relation.IsTwoWay {
  1970. destAv, _ := av.ParseAttributeView(key.Relation.AvID)
  1971. if nil != destAv {
  1972. // relationChangeMode
  1973. // 0:关联列值不变(仅排序),不影响目标值
  1974. // 1:关联列值增加,增加目标值
  1975. // 2:关联列值减少,减少目标值
  1976. if 1 == relationChangeMode {
  1977. addBlockIDs := val.Relation.BlockIDs
  1978. for _, bID := range oldRelationBlockIDs {
  1979. addBlockIDs = gulu.Str.RemoveElem(addBlockIDs, bID)
  1980. }
  1981. for _, blockID := range addBlockIDs {
  1982. for _, keyValues := range destAv.KeyValues {
  1983. if keyValues.Key.ID != key.Relation.BackKeyID {
  1984. continue
  1985. }
  1986. destVal := keyValues.GetValue(blockID)
  1987. if nil == destVal {
  1988. destVal = &av.Value{ID: ast.NewNodeID(), KeyID: keyValues.Key.ID, BlockID: blockID, Type: keyValues.Key.Type, Relation: &av.ValueRelation{}}
  1989. keyValues.Values = append(keyValues.Values, destVal)
  1990. }
  1991. destVal.Relation.BlockIDs = append(destVal.Relation.BlockIDs, rowID)
  1992. destVal.Relation.BlockIDs = gulu.Str.RemoveDuplicatedElem(destVal.Relation.BlockIDs)
  1993. break
  1994. }
  1995. }
  1996. } else if 2 == relationChangeMode {
  1997. removeBlockIDs := oldRelationBlockIDs
  1998. for _, bID := range val.Relation.BlockIDs {
  1999. removeBlockIDs = gulu.Str.RemoveElem(removeBlockIDs, bID)
  2000. }
  2001. for _, blockID := range removeBlockIDs {
  2002. for _, keyValues := range destAv.KeyValues {
  2003. if keyValues.Key.ID != key.Relation.BackKeyID {
  2004. continue
  2005. }
  2006. for _, value := range keyValues.Values {
  2007. if value.BlockID == blockID {
  2008. value.Relation.BlockIDs = gulu.Str.RemoveElem(value.Relation.BlockIDs, rowID)
  2009. break
  2010. }
  2011. }
  2012. }
  2013. }
  2014. }
  2015. av.SaveAttributeView(destAv)
  2016. util.BroadcastByType("protyle", "refreshAttributeView", 0, "", map[string]interface{}{"id": destAv.ID})
  2017. }
  2018. }
  2019. if err = av.SaveAttributeView(attrView); nil != err {
  2020. return
  2021. }
  2022. return
  2023. }
  2024. func unbindBlockAv(tx *Transaction, avID, blockID string) {
  2025. node, tree, err := getNodeByBlockID(tx, blockID)
  2026. if nil != err {
  2027. return
  2028. }
  2029. attrs := parse.IAL2Map(node.KramdownIAL)
  2030. if "" == attrs[av.NodeAttrNameAvs] {
  2031. return
  2032. }
  2033. avIDs := strings.Split(attrs[av.NodeAttrNameAvs], ",")
  2034. avIDs = gulu.Str.RemoveElem(avIDs, avID)
  2035. if 0 == len(avIDs) {
  2036. delete(attrs, av.NodeAttrNameAvs)
  2037. node.RemoveIALAttr(av.NodeAttrNameAvs)
  2038. } else {
  2039. attrs[av.NodeAttrNameAvs] = strings.Join(avIDs, ",")
  2040. node.SetIALAttr(av.NodeAttrNameAvs, strings.Join(avIDs, ","))
  2041. }
  2042. if nil != tx {
  2043. err = setNodeAttrsWithTx(tx, node, tree, attrs)
  2044. } else {
  2045. err = setNodeAttrs(node, tree, attrs)
  2046. }
  2047. if nil != err {
  2048. logging.LogWarnf("set node [%s] attrs failed: %s", blockID, err)
  2049. return
  2050. }
  2051. return
  2052. }
  2053. func bindBlockAv(tx *Transaction, avID, blockID string) {
  2054. node, tree, err := getNodeByBlockID(tx, blockID)
  2055. if nil != err {
  2056. return
  2057. }
  2058. attrs := parse.IAL2Map(node.KramdownIAL)
  2059. if "" == attrs[av.NodeAttrNameAvs] {
  2060. attrs[av.NodeAttrNameAvs] = avID
  2061. } else {
  2062. avIDs := strings.Split(attrs[av.NodeAttrNameAvs], ",")
  2063. avIDs = append(avIDs, avID)
  2064. avIDs = gulu.Str.RemoveDuplicatedElem(avIDs)
  2065. attrs[av.NodeAttrNameAvs] = strings.Join(avIDs, ",")
  2066. }
  2067. if nil != tx {
  2068. err = setNodeAttrsWithTx(tx, node, tree, attrs)
  2069. } else {
  2070. err = setNodeAttrs(node, tree, attrs)
  2071. }
  2072. if nil != err {
  2073. logging.LogWarnf("set node [%s] attrs failed: %s", blockID, err)
  2074. return
  2075. }
  2076. return
  2077. }
  2078. func getNodeByBlockID(tx *Transaction, blockID string) (node *ast.Node, tree *parse.Tree, err error) {
  2079. if nil != tx {
  2080. tree, err = tx.loadTree(blockID)
  2081. } else {
  2082. tree, err = loadTreeByBlockID(blockID)
  2083. }
  2084. if nil != err {
  2085. return
  2086. }
  2087. node = treenode.GetNodeInTree(tree, blockID)
  2088. if nil == node {
  2089. logging.LogWarnf("node [%s] not found in tree [%s]", blockID, tree.ID)
  2090. return
  2091. }
  2092. return
  2093. }
  2094. func (tx *Transaction) doUpdateAttrViewColOptions(operation *Operation) (ret *TxErr) {
  2095. err := updateAttributeViewColumnOptions(operation)
  2096. if nil != err {
  2097. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  2098. }
  2099. return
  2100. }
  2101. func updateAttributeViewColumnOptions(operation *Operation) (err error) {
  2102. attrView, err := av.ParseAttributeView(operation.AvID)
  2103. if nil != err {
  2104. return
  2105. }
  2106. jsonData, err := gulu.JSON.MarshalJSON(operation.Data)
  2107. if nil != err {
  2108. return
  2109. }
  2110. options := []*av.SelectOption{}
  2111. if err = gulu.JSON.UnmarshalJSON(jsonData, &options); nil != err {
  2112. return
  2113. }
  2114. for _, keyValues := range attrView.KeyValues {
  2115. if keyValues.Key.ID == operation.ID {
  2116. keyValues.Key.Options = options
  2117. err = av.SaveAttributeView(attrView)
  2118. return
  2119. }
  2120. }
  2121. return
  2122. }
  2123. func (tx *Transaction) doRemoveAttrViewColOption(operation *Operation) (ret *TxErr) {
  2124. err := removeAttributeViewColumnOption(operation)
  2125. if nil != err {
  2126. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  2127. }
  2128. return
  2129. }
  2130. func removeAttributeViewColumnOption(operation *Operation) (err error) {
  2131. attrView, err := av.ParseAttributeView(operation.AvID)
  2132. if nil != err {
  2133. return
  2134. }
  2135. optName := operation.Data.(string)
  2136. key, err := attrView.GetKey(operation.ID)
  2137. if nil != err {
  2138. return
  2139. }
  2140. for i, opt := range key.Options {
  2141. if optName == opt.Name {
  2142. key.Options = append(key.Options[:i], key.Options[i+1:]...)
  2143. break
  2144. }
  2145. }
  2146. for _, keyValues := range attrView.KeyValues {
  2147. if keyValues.Key.ID != operation.ID {
  2148. continue
  2149. }
  2150. for _, value := range keyValues.Values {
  2151. if nil == value || nil == value.MSelect {
  2152. continue
  2153. }
  2154. for i, opt := range value.MSelect {
  2155. if optName == opt.Content {
  2156. value.MSelect = append(value.MSelect[:i], value.MSelect[i+1:]...)
  2157. break
  2158. }
  2159. }
  2160. }
  2161. break
  2162. }
  2163. err = av.SaveAttributeView(attrView)
  2164. return
  2165. }
  2166. func (tx *Transaction) doUpdateAttrViewColOption(operation *Operation) (ret *TxErr) {
  2167. err := updateAttributeViewColumnOption(operation)
  2168. if nil != err {
  2169. return &TxErr{code: TxErrWriteAttributeView, id: operation.AvID, msg: err.Error()}
  2170. }
  2171. return
  2172. }
  2173. func updateAttributeViewColumnOption(operation *Operation) (err error) {
  2174. attrView, err := av.ParseAttributeView(operation.AvID)
  2175. if nil != err {
  2176. return
  2177. }
  2178. key, err := attrView.GetKey(operation.ID)
  2179. if nil != err {
  2180. return
  2181. }
  2182. data := operation.Data.(map[string]interface{})
  2183. oldName := data["oldName"].(string)
  2184. newName := data["newName"].(string)
  2185. newColor := data["newColor"].(string)
  2186. for i, opt := range key.Options {
  2187. if oldName == opt.Name {
  2188. key.Options[i].Name = newName
  2189. key.Options[i].Color = newColor
  2190. break
  2191. }
  2192. }
  2193. for _, keyValues := range attrView.KeyValues {
  2194. if keyValues.Key.ID != operation.ID {
  2195. continue
  2196. }
  2197. for _, value := range keyValues.Values {
  2198. if nil == value || nil == value.MSelect {
  2199. continue
  2200. }
  2201. for i, opt := range value.MSelect {
  2202. if oldName == opt.Content {
  2203. value.MSelect[i].Content = newName
  2204. value.MSelect[i].Color = newColor
  2205. break
  2206. }
  2207. }
  2208. }
  2209. break
  2210. }
  2211. err = av.SaveAttributeView(attrView)
  2212. return
  2213. }