github.com/qlik-oss/gopherciser@v0.18.6/senseobjects/sheetlist.go (about) 1 package senseobjects 2 3 import ( 4 "context" 5 "fmt" 6 "sort" 7 "sync" 8 9 "github.com/goccy/go-json" 10 11 "github.com/pkg/errors" 12 "github.com/qlik-oss/enigma-go/v4" 13 "github.com/qlik-oss/gopherciser/helpers" 14 ) 15 16 type ( 17 // SheetListLayout sheetlist layout 18 SheetListLayout struct { 19 enigma.GenericObjectLayout 20 AppObjectList *SheetListAppObjectList `json:"qAppObjectList,omitempty"` 21 } 22 23 // SheetListAppObjectList sheetlist app object list 24 SheetListAppObjectList struct { 25 enigma.AppObjectList 26 Items []*SheetNxContainerEntry `json:"qItems,omitempty"` 27 } 28 29 // SheetNxContainerEntry container sheet data 30 SheetNxContainerEntry struct { 31 enigma.NxContainerEntry 32 Data *SheetData `json:"qData,omitempty"` 33 Meta SheetMeta `json:"qMeta,omitempty"` 34 } 35 36 SheetMeta struct { 37 enigma.NxMeta 38 Published bool `json:"published,omitempty"` 39 Approved bool `json:"approved,omitempty"` 40 } 41 42 SheetBounds struct { 43 Y float64 `json:"y"` 44 X float64 `json:"x"` 45 Width float64 `json:"width"` 46 Height float64 `json:"height"` 47 } 48 49 // SheetData data for a sheet 50 SheetData struct { 51 Cells []struct { 52 Name string `json:"name"` 53 Type string `json:"type"` 54 Col int `json:"col"` 55 Row int `json:"row"` 56 Colspan int `json:"colspan"` 57 Rowspan int `json:"rowspan"` 58 Bounds SheetBounds `json:"bounds,omitempty"` 59 } `json:"cells,omitempty"` 60 Columns interface{} `json:"columns"` 61 Rows interface{} `json:"rows"` 62 Title string `json:"title"` 63 LabelExpression string `json:"labelExpression"` 64 Description string `json:"description"` 65 DescriptionExpression string `json:"descriptionExpression"` 66 Rank interface{} `json:"rank"` 67 ShowCondition helpers.FuzzyBool `json:"showCondition"` 68 } 69 70 // SheetListPropertiesData properties of sheetlist 71 SheetListPropertiesData struct { 72 Title string `json:"title,omitempty"` 73 Description string `json:"description,omitempty"` 74 Cells string `json:"cells,omitempty"` 75 } 76 77 // SheetListProperties SheetList properties 78 SheetListProperties struct { 79 Info enigma.NxInfo `json:"qInfo,omitempty"` 80 MetaDef enigma.NxMetaDef `json:"qMetaDef,omitempty"` 81 Data *SheetListPropertiesData `json:"qData,omitempty"` 82 } 83 84 // SheetList container with sheet in sense app 85 SheetList struct { 86 enigmaObject *enigma.GenericObject 87 layout *SheetListLayout 88 mutex sync.Mutex 89 } 90 91 // SheetEntryNotFoundError error returned when sheet entry was not found in sheet list 92 SheetEntryNotFoundError string 93 ) 94 95 // Error returned when sheet entry was not found in sheet list 96 func (err SheetEntryNotFoundError) Error() string { 97 return fmt.Sprintf("no sheet entry found for id<%s>", string(err)) 98 } 99 100 func (sheetList *SheetList) setLayout(layout *SheetListLayout) { 101 sheetList.mutex.Lock() 102 defer sheetList.mutex.Unlock() 103 sheetList.layout = layout 104 } 105 106 // UpdateLayout get and set a new layout for sheetlist 107 func (sheetList *SheetList) UpdateLayout(ctx context.Context) error { 108 if sheetList.enigmaObject == nil { 109 return errors.Errorf("sheetlist enigma object is nil") 110 } 111 112 layoutRaw, err := sheetList.enigmaObject.GetLayoutRaw(ctx) 113 if err != nil { 114 return errors.Wrap(err, "Failed to get sheetlist layout") 115 } 116 117 var layout SheetListLayout 118 err = json.Unmarshal(layoutRaw, &layout) 119 if err != nil { 120 return errors.Wrap(err, "Failed to unmarshal sheetlist layout") 121 } 122 123 // sort sheets after rank (same order as shown in app) 124 if layout.AppObjectList != nil || layout.AppObjectList.Items != nil { 125 sheetItems := layout.AppObjectList.Items 126 sort.Slice(sheetItems, func(i, j int) bool { 127 item1, item2 := sheetItems[i], sheetItems[j] 128 if item1 == nil || item2 == nil || item1.Data == nil || item2.Data == nil { 129 return false 130 } 131 iRank, ok := sheetItems[i].Data.Rank.(float64) 132 if !ok { 133 iRank = 0 134 } 135 jRank, ok := sheetItems[j].Data.Rank.(float64) 136 if !ok { 137 jRank = 0 138 } 139 return iRank < jRank 140 }) 141 } 142 143 sheetList.setLayout(&layout) 144 return nil 145 } 146 147 // Layout for sheetlist 148 func (sheetList *SheetList) Layout() *SheetListLayout { 149 return sheetList.layout //TODO DECISION: wait for write lock? 150 } 151 152 // GetSheetEntry Get sheet entry from sheet list 153 func (sheetList *SheetList) GetSheetEntry(sheetid string) (*SheetNxContainerEntry, error) { 154 for _, v := range sheetList.layout.AppObjectList.Items { 155 if v.Info.Id == sheetid { 156 return v, nil 157 } 158 } 159 return nil, SheetEntryNotFoundError(sheetid) 160 } 161 162 // CreateSheetListObject create sheetlist session object 163 func CreateSheetListObject(ctx context.Context, doc *enigma.Doc) (*SheetList, error) { 164 properties := &enigma.GenericObjectProperties{ 165 Info: &enigma.NxInfo{ 166 Id: "SheetList", 167 Type: "SheetList", 168 }, 169 AppObjectListDef: &enigma.AppObjectListDef{ 170 Type: "sheet", 171 Data: json.RawMessage(`{ 172 "title": "/qMetaDef/title", 173 "labelExpression": "/labelExpression", 174 "showCondition": "/showCondition", 175 "description": "/qMetaDef/description", 176 "descriptionExpression": "/descriptionExpression", 177 "thumbnail": "/thumbnail", 178 "cells": "/cells", 179 "rank": "/rank", 180 "columns": "/columns", 181 "rows": "/rows" 182 }`), 183 }, 184 } 185 186 obj, err := doc.CreateSessionObjectRaw(ctx, properties) 187 if err != nil { 188 return nil, errors.Wrapf(err, "Failed to create sheetlist session object in app<%s>", doc.GenericId) 189 } 190 191 return &SheetList{ 192 enigmaObject: obj, 193 }, nil 194 }