siyuan/kernel/av/attribute_view.go

197 lines
5 KiB
Go
Raw Normal View History

// SiYuan - Refactor your thinking
// Copyright (c) 2020-present, b3log.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// Package av 包含了属性视图Attribute View相关的实现。
package av
import (
2023-07-11 22:11:15 +08:00
"errors"
"os"
"path/filepath"
"github.com/88250/gulu"
"github.com/88250/lute/ast"
"github.com/siyuan-note/filelock"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/util"
)
// AttributeView 描述了属性视图的结构。
type AttributeView struct {
2023-07-11 19:45:27 +08:00
Spec int `json:"spec"` // 格式版本
ID string `json:"id"` // 属性视图 ID
2023-06-10 16:52:54 +08:00
Name string `json:"name"` // 属性视图名称
2023-07-11 19:45:27 +08:00
Columns []*Column `json:"columns"` // 列
Rows []*Row `json:"rows"` // 行
2023-07-12 10:35:17 +08:00
CurrentViewID string `json:"currentViewID"` // 当前视图 ID
2023-07-11 19:45:27 +08:00
Views []*View `json:"views"` // 视图
}
2023-07-11 19:45:27 +08:00
// View 描述了视图的结构。
type View struct {
2023-07-12 10:35:17 +08:00
ID string `json:"id"` // 视图 ID
Name string `json:"name"` // 视图名称
2023-07-11 19:45:27 +08:00
2023-07-12 10:35:17 +08:00
CurrentLayoutID string `json:"CurrentLayoutID"` // 当前布局 ID
CurrentLayoutType LayoutType `json:"type"` // 当前布局类型
Table *LayoutTable `json:"table,omitempty"` // 表格布局
2023-07-11 19:45:27 +08:00
}
2023-07-12 10:35:17 +08:00
// LayoutType 描述了视图布局的类型。
type LayoutType string
const (
2023-07-12 10:35:17 +08:00
LayoutTypeTable LayoutType = "table" // 属性视图类型 - 表格
)
2023-07-11 23:40:05 +08:00
func NewView() *View {
name := "Table"
2023-07-12 10:35:17 +08:00
layoutID := ast.NewNodeID()
2023-07-11 23:40:05 +08:00
return &View{
2023-07-12 10:35:17 +08:00
ID: ast.NewNodeID(),
Name: name,
CurrentLayoutID: layoutID,
CurrentLayoutType: LayoutTypeTable,
Table: &LayoutTable{
2023-07-11 23:40:05 +08:00
Spec: 0,
2023-07-12 10:35:17 +08:00
ID: layoutID,
2023-07-11 23:40:05 +08:00
Filters: []*ViewFilter{},
Sorts: []*ViewSort{},
},
}
}
2023-07-11 19:45:27 +08:00
// Viewable 描述了视图的接口。
type Viewable interface {
Filterable
Sortable
Calculable
2023-07-12 10:35:17 +08:00
GetType() LayoutType
GetID() string
2023-07-11 19:45:27 +08:00
}
func NewAttributeView(id string) *AttributeView {
2023-07-11 23:40:05 +08:00
view := NewView()
2023-07-11 19:45:27 +08:00
return &AttributeView{
Spec: 0,
ID: id,
Columns: []*Column{{ID: ast.NewNodeID(), Name: "Block", Type: ColumnTypeBlock}},
Rows: []*Row{},
CurrentViewID: view.ID,
Views: []*View{view},
}
}
func ParseAttributeView(avID string) (ret *AttributeView, err error) {
avJSONPath := getAttributeViewDataPath(avID)
if !gulu.File.IsExist(avJSONPath) {
ret = NewAttributeView(avID)
return
}
data, err := filelock.ReadFile(avJSONPath)
if nil != err {
logging.LogErrorf("read attribute view [%s] failed: %s", avID, err)
return
}
ret = &AttributeView{}
if err = gulu.JSON.UnmarshalJSON(data, ret); nil != err {
logging.LogErrorf("unmarshal attribute view [%s] failed: %s", avID, err)
return
}
2023-07-11 19:45:27 +08:00
if 1 > len(ret.Views) {
2023-07-11 23:40:05 +08:00
view := NewView()
2023-07-11 19:45:27 +08:00
ret.CurrentViewID = view.ID
ret.Views = []*View{view}
}
return
}
2023-07-03 19:39:00 +08:00
func ParseAttributeViewMap(avID string) (ret map[string]interface{}, err error) {
ret = map[string]interface{}{}
avJSONPath := getAttributeViewDataPath(avID)
if !gulu.File.IsExist(avJSONPath) {
av := NewAttributeView(avID)
var data []byte
data, err = gulu.JSON.MarshalJSON(av)
if nil == err {
return
}
err = gulu.JSON.UnmarshalJSON(data, &ret)
return
}
data, err := filelock.ReadFile(avJSONPath)
if nil != err {
logging.LogErrorf("read attribute view [%s] failed: %s", avID, err)
return
}
if err = gulu.JSON.UnmarshalJSON(data, &ret); nil != err {
logging.LogErrorf("unmarshal attribute view [%s] failed: %s", avID, err)
return
}
return
}
func SaveAttributeView(av *AttributeView) (err error) {
data, err := gulu.JSON.MarshalIndentJSON(av, "", "\t")
if nil != err {
logging.LogErrorf("marshal attribute view [%s] failed: %s", av.ID, err)
return
}
avJSONPath := getAttributeViewDataPath(av.ID)
if err = filelock.WriteFile(avJSONPath, data); nil != err {
logging.LogErrorf("save attribute view [%s] failed: %s", av.ID, err)
return
}
return
}
2023-07-11 23:47:17 +08:00
func (av *AttributeView) GetView(viewID string) (ret *View, err error) {
2023-07-11 22:11:15 +08:00
for _, v := range av.Views {
if v.ID == viewID {
ret = v
return
}
}
2023-07-11 23:47:17 +08:00
err = ErrViewNotFound
2023-07-11 22:11:15 +08:00
return
}
func getAttributeViewDataPath(avID string) (ret string) {
av := filepath.Join(util.DataDir, "storage", "av")
ret = filepath.Join(av, avID+".json")
if !gulu.File.IsDir(av) {
if err := os.MkdirAll(av, 0755); nil != err {
logging.LogErrorf("create attribute view dir failed: %s", err)
return
}
}
return
}
2023-07-11 22:11:15 +08:00
var (
ErrViewNotFound = errors.New("view not found")
)