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  }