Skip to content

Commit

Permalink
Enhancement/1416 cyclic dimension (#477)
Browse files Browse the repository at this point in the history
* Send a "GetDimension" request on dimensions with grouping "C" (cyclic dimension) and save to session objects.
* clean up `lint.sh` somewhat
* add new action `stepdimension` to step a cycle in a cyclic dimension.
  • Loading branch information
DnlLrssn authored May 21, 2024
1 parent e22d31a commit 9774275
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 29 deletions.
24 changes: 24 additions & 0 deletions docs/settingup.md
Original file line number Diff line number Diff line change
Expand Up @@ -2261,6 +2261,30 @@ Unsubscribe from all currently subscribed objects.
```
<hr></details>

<details>
<summary>stepdimension</summary>

## StepDimension action

Cycle a step in a cyclic dimension

* `id`: library ID of the cyclic dimension

### Example

Cycle one step in the dimension with library ID `aBc123`.

```json
{
"action": "stepdimension",
"settings":{
"id": "aBc123"
}
}
```

<hr></details>

<hr></details>

<details>
Expand Down
3 changes: 3 additions & 0 deletions generatedocs/data/actions/stepdimension/description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## StepDimension action

Cycle a step in a cyclic dimension
12 changes: 12 additions & 0 deletions generatedocs/data/actions/stepdimension/examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
### Example

Cycle one step in the dimension with library ID `aBc123`.

```json
{
"action": "stepdimension",
"settings":{
"id": "aBc123"
}
}
```
3 changes: 2 additions & 1 deletion generatedocs/data/groups/groups.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"thinktime",
"unpublishbookmark",
"unpublishsheet",
"unsubscribeobjects"
"unsubscribeobjects",
"stepdimension"
]
},
{
Expand Down
3 changes: 3 additions & 0 deletions generatedocs/data/params.json
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,9 @@
"setscriptvar.value": [
"Value to set to variable (supports the use of [session variables](#session_variables))."
],
"stepdimension.id": [
"library ID of the cyclic dimension"
],
"subscribeobjects.clear" : [
"Remove any previously subscribed objects from the subscription list."
],
Expand Down
7 changes: 6 additions & 1 deletion generatedocs/generated/documentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ var (
Description: "## SmartSearch action\n\nPerform a Smart Search in Sense app to find suggested selections.\n",
Examples: "\n### Examples\n\n#### Search with one search term\n```json\n{\n \"action\": \"smartsearch\",\n \"label\": \"one term search\",\n \"settings\": {\n \"searchtextlist\": [\n \"term1\"\n ]\n }\n}\n```\n\n#### Search with two search terms\n```json\n{\n \"action\": \"smartsearch\",\n \"label\": \"two term search\",\n \"settings\": {\n \"searchtextlist\": [\n \"term1 term2\"\n ]\n }\n}\n```\n\n#### Search with random selection of search text from list\n```json\n{\n \"action\": \"smartsearch\",\n \"settings\": {\n \"searchtextlist\": [\n \"text1\",\n \"text2\",\n \"text3\"\n ]\n }\n}\n```\n\n#### Search with random selection of search text from file\n```json\n{\n \"action\": \"smartsearch\",\n \"settings\": {\n \"searchtextsource\": \"searchtextfile\",\n \"searchtextfile\": \"data/searchtexts.txt\"\n }\n}\n```\n##### `data/searchtexts.txt`\n```\nsearch text\n\"quoted search text\"\nanother search text\n```\n\n#### Simulate pasting search text\n\nThe default behavior is to simulate typing at normal speed.\n```json\n{\n \"action\": \"smartsearch\",\n \"settings\": {\n \"pastesearchtext\": true,\n \"searchtextlist\": [\n \"text1\"\n ]\n }\n}\n```\n\n#### Make a random selection from search results\n```json\n{\n \"action\": \"smartsearch\",\n \"settings\": {\n \"searchtextlist\": [\n \"term1\"\n ],\n \"makeselection\": true,\n \"selectionthinktime\": {\n \"type\": \"static\",\n \"delay\": 2\n }\n }\n}\n```\n\n#### Search with one search term including spaces\n```json\n{\n \"action\": \"smartsearch\",\n \"settings\": {\n \"searchtextlist\": [\n \"\\\"word1 word2\\\"\"\n ]\n }\n}\n```\n\n#### Search with two search terms, one of them including spaces\n```json\n{\n \"action\": \"smartsearch\",\n \"label\": \"two term search, one including spaces\",\n \"settings\": {\n \"searchtextlist\": [\n \"\\\"word1 word2\\\" term2\"\n ]\n }\n}\n```\n\n#### Search with one search term including double quote\n```json\n{\n \"action\": \"smartsearch\",\n \"label\": \"one term search including spaces\",\n \"settings\": {\n \"searchtext\":\n \"searchtextlist\": [\n \"\\\\\\\"hello\"\n ]\n }\n}\n```\n",
},
"stepdimension": {
Description: "## StepDimension action\n\nCycle a step in a cyclic dimension\n",
Examples: "### Example\n\nCycle one step in the dimension with library ID `aBc123`.\n\n```json\n{\n \"action\": \"stepdimension\",\n \"settings\":{\n \"id\": \"aBc123\"\n }\n}\n```\n",
},
"subscribeobjects": {
Description: "## Subscribeobjects action\n\nSubscribe to any object in the currently active app.\n",
Examples: "### Example\n\nSubscribe to two objects in the currently active app and remove any previous subscriptions. \n\n```json\n{\n \"action\" : \"subscribeobjects\",\n \"label\" : \"clear subscriptions and subscribe to mBshXB and f2a50cb3-a7e1-40ac-a015-bc4378773312\",\n \"disabled\": false,\n \"settings\" : {\n \"clear\" : true,\n \"ids\" : [\"mBshXB\", \"f2a50cb3-a7e1-40ac-a015-bc4378773312\"]\n }\n}\n```\n\nSubscribe to an additional single object (or a list of objects) in the currently active app, adding the new subscription to any previous subscriptions.\n\n```json\n{\n \"action\" : \"subscribeobjects\",\n \"label\" : \"add c430d8e2-0f05-49f1-aa6f-7234e325dc35 to currently subscribed objects\",\n \"disabled\": false,\n \"settings\" : {\n \"clear\" : false,\n \"ids\" : [\"c430d8e2-0f05-49f1-aa6f-7234e325dc35\"]\n }\n}\n```",
Expand Down Expand Up @@ -349,6 +353,7 @@ var (
"smartsearch.searchtextlist": {"List of of strings used for searching."},
"smartsearch.searchtextsource": {"Source for list of strings used for searching.", "`searchtextlist` (default)", "`searchtextfile`"},
"smartsearch.selectionthinktime": {"Think time before selection if `makeselection` is `true`, defaults to a 1 second delay."},
"stepdimension.id": {"library ID of the cyclic dimension"},
"subscribeobjects.clear": {"Remove any previously subscribed objects from the subscription list."},
"subscribeobjects.ids": {"List of object IDs to subscribe to."},
"thinktime.delay": {"Delay (seconds), used with type `static`."},
Expand Down Expand Up @@ -399,7 +404,7 @@ var (
{
Name: "commonActions",
Title: "Common actions",
Actions: []string{"applybookmark", "askhubadvisor", "changesheet", "clearall", "clearfield", "clickactionbutton", "containertab", "createbookmark", "createsheet", "deletebookmark", "deletesheet", "disconnectapp", "disconnectenvironment", "dosave", "duplicatesheet", "getscript", "iterated", "listboxselect", "objectsearch", "openapp", "productversion", "publishbookmark", "publishsheet", "randomaction", "reload", "select", "setscript", "setscriptvar", "setsensevariable", "sheetchanger", "smartsearch", "subscribeobjects", "thinktime", "unpublishbookmark", "unpublishsheet", "unsubscribeobjects"},
Actions: []string{"applybookmark", "askhubadvisor", "changesheet", "clearall", "clearfield", "clickactionbutton", "containertab", "createbookmark", "createsheet", "deletebookmark", "deletesheet", "disconnectapp", "disconnectenvironment", "dosave", "duplicatesheet", "getscript", "iterated", "listboxselect", "objectsearch", "openapp", "productversion", "publishbookmark", "publishsheet", "randomaction", "reload", "select", "setscript", "setscriptvar", "setsensevariable", "sheetchanger", "smartsearch", "subscribeobjects", "thinktime", "unpublishbookmark", "unpublishsheet", "unsubscribeobjects", "stepdimension"},
DocEntry: common.DocEntry{
Description: "# Common actions\n\nThese actions are applicable for most types of Qlik Sense deployments.\n\n**Note:** It is recommended to prepend the actions listed here with an `openapp` action as most of them perform operations in an app context (such as making selections or changing sheets).\n",
Examples: "",
Expand Down
7 changes: 7 additions & 0 deletions globals/constant/sense.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,10 @@ const (
DataReductionModeClustered = "C"
DataReductionModeStacked = "ST"
)

// NxDimensionInfoGrouping
const (
NxDimensionInfoGroupingNone = "N"
NxDimensionInfoGroupingHiearchy = "H"
NxDimensionInfoGroupingCollection = "C"
)
2 changes: 2 additions & 0 deletions scenario/actionhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ const (
ActionObjectSearch = "objectsearch"
ActionGetScript = "getscript"
ActionChangeSteam = "changestream"
ActionStepDimension = "stepdimension"
)

// Scenario actions needs an entry in actionHandler
Expand Down Expand Up @@ -260,6 +261,7 @@ func ResetDefaultActions() {
ActionObjectSearch: ObjectSearchSettings{},
ActionGetScript: GetscriptSettings{},
ActionChangeSteam: ChangestreamSettings{},
ActionStepDimension: StepDimensionSettings{},
}
}

Expand Down
54 changes: 54 additions & 0 deletions scenario/stepdimension.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package scenario

import (
"context"

"github.com/pkg/errors"
"github.com/qlik-oss/gopherciser/action"
"github.com/qlik-oss/gopherciser/connection"
"github.com/qlik-oss/gopherciser/session"
)

type (
// StepDimensionSettings cycle a step in a cyclic dimension
StepDimensionSettings struct {
Id string `json:"id" doc-key:"stepdimension.id"`
}
)

// Validate StepDimensionSettings action (Implements ActionSettings interface)
func (settings StepDimensionSettings) Validate() ([]string, error) {
if settings.Id == "" {
return nil, errors.Errorf("Id not set for %s", ActionStepDimension)
}
return nil, nil
}

// Execute StepDimensionSettings action (Implements ActionSettings interface)
func (settings StepDimensionSettings) Execute(sessionState *session.State, actionState *action.State, connection *connection.ConnectionSettings, label string, reset func()) {
if sessionState.Connection == nil || sessionState.Connection.Sense() == nil {
actionState.AddErrors(errors.New("Not connected to a Sense environment"))
return
}

app := sessionState.Connection.Sense().CurrentApp
if app == nil {
actionState.AddErrors(errors.New("Not connected to a Sense app"))
return
}

dim, err := app.GetDimension(sessionState, actionState, settings.Id)
if err != nil {
actionState.AddErrors(err)
return
}

err = sessionState.SendRequest(actionState, func(ctx context.Context) error {
return dim.StepCycle(ctx, 1)
})
if err != nil {
actionState.AddErrors(err)
}

sessionState.Wait(actionState) // Await all async requests, e.g. those triggered on changed objects
}
29 changes: 4 additions & 25 deletions scripts/lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,6 @@
# Purpose: This script lints the code.
# Instructions: make lint

# On darwin you can also install with homebrew
# brew install golangci/tap/golangci-lint

# set OS
OS=
if [[ "$OSTYPE" == "linux-gnu" ]]; then
OS=Linux
elif [[ "$OSTYPE" == "darwin"* ]]; then
# Mac OSX
OS=Darwin
elif [[ "$OSTYPE" == "cygwin" ]]; then
# POSIX compatibility layer and Linux environment emulation for Windows
OS=Windows
else
# Unknown, assume Linux
OS=Linux
fi

# set lint level
LINTLEVEL=${1:-DEFAULT}

Expand Down Expand Up @@ -48,15 +30,12 @@ fi
echo Running lint
case $LINTLEVEL in
# minimal amount of linting currently running clean. More linters and and rules will be added as more lint errors are fixed.
# Current status:
# linters currently looked at: govet
# subrules currently disabled:
# * structtag : We override tags in engima, so structtag complains about repeating tags, found no way to tell it this is intended.
# currently no subrules disabled in "min"
MIN)
"$GOPATH"/bin/golangci-lint run -D structcheck --timeout 5m
"$GOPATH"/bin/golangci-lint run --timeout 5m
;;
# Default set of linters
# "full" set of linters
*)
"$GOPATH"/bin/golangci-lint run
"$GOPATH"/bin/golangci-lint run --timeout 5m
;;
esac
33 changes: 33 additions & 0 deletions senseobjects/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type (
loadmodellist *LoadModelList
fieldlist *FieldList
dimensionList *DimensionList
dimensions map[string]*enigma.GenericDimension
appPropsList *AppPropsList
}

Expand Down Expand Up @@ -542,3 +543,35 @@ func (app *App) setDimensionList(SessionState SessionState, dl *DimensionList) {
}
app.dimensionList = dl
}

func (app *App) GetDimension(sessionState SessionState, actionState *action.State, id string) (*enigma.GenericDimension, error) {
dim := app.dimensions[id]
if dim != nil {
return dim, nil
}

err := sessionState.SendRequest(actionState, func(ctx context.Context) error {
var err error
dim, err = app.Doc.GetDimension(ctx, id)
return err
})
if err != nil {
return nil, err
}

app.addDimension(dim)

return dim, nil
}

func (app *App) addDimension(dim *enigma.GenericDimension) {
app.mutex.Lock()
defer app.mutex.Unlock()

if app.dimensions == nil {
app.dimensions = map[string]*enigma.GenericDimension{dim.GenericId: dim}
return
}

app.dimensions[dim.GenericId] = dim
}
25 changes: 23 additions & 2 deletions session/objecthandling.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func SetListObject(rawLayout json.RawMessage, obj *enigmahandlers.Object, path h
return nil
}

func SetHyperCube(rawLayout json.RawMessage, obj *enigmahandlers.Object, path helpers.DataPath) error {
func SetHyperCube(sessionState *State, actionState *action.State, rawLayout json.RawMessage, obj *enigmahandlers.Object, path helpers.DataPath) error {
rawHyperCube, err := path.Lookup(rawLayout)
if err != nil {
return errors.Wrap(err, "error getting hypercube")
Expand All @@ -356,6 +356,27 @@ func SetHyperCube(rawLayout json.RawMessage, obj *enigmahandlers.Object, path he
}

obj.SetHyperCube(hyperCube)

// Look for cyclic dimensions and add to app sessionobjects
if len(hyperCube.DimensionInfo) > 0 {
for i, dim := range hyperCube.DimensionInfo {
if dim != nil && dim.Grouping == constant.NxDimensionInfoGroupingCollection {
app, err := sessionState.CurrentSenseApp()
if err != nil {
return errors.WithStack(err)
}
if dim.LibraryId == "" {
sessionState.LogEntry.Logf(logger.WarningLevel, "object<%s> dim<%d> has grouping<C>, but no library ID", obj.ID, i)
continue
}
// GetDimension (adds it to sessionobjects list)
if _, err = app.GetDimension(sessionState, actionState, dim.LibraryId); err != nil {
actionState.AddErrors(err)
}
}
}
}

return nil
}

Expand Down Expand Up @@ -888,7 +909,7 @@ func SetObjectData(sessionState *State, actionState *action.State, rawLayout jso
return errors.Errorf(
"object<%s> is defined as hypercube carrier, but has not hypercube path definition", enigmaObject.GenericType)
}
if err := SetHyperCube(rawLayout, obj, objectDef.DataDef.Path); err != nil {
if err := SetHyperCube(sessionState, actionState, rawLayout, obj, objectDef.DataDef.Path); err != nil {
return errors.Wrapf(err, "object<%s> type<%s>", obj.ID, enigmaObject.GenericType)
}
default:
Expand Down

0 comments on commit 9774275

Please sign in to comment.