Skip to content

Commit 3c33184

Browse files
Paolo Calaopolldo
Paolo Calao
authored andcommitted
Add dashboard create command (#50)
This command allows users to create new dashboards starting from templates. Changes: - Dashboard create command has been implemented, it takes a template and a map indicating thing_id to be overridden. - A function to convert the template file into a proper dashboard structure has been implemented. Here, the ids of the variables described in the template are fetched; the widget options are filtered; a uuid is assigned to each widget.
1 parent e6298a3 commit 3c33184

19 files changed

+1010
-15
lines changed

Diff for: README.md

+4
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,7 @@ Delete a dashboard with the following command:
132132
Extract a template from an existing dashboard. The template can be saved in two formats: json or yaml. The default format is yaml:
133133

134134
`$ arduino-cloud-cli dashboard extract --id <dashboardID> --outfile <templateFile> --format <yaml|json>`
135+
136+
Create a dashboard: dashboards can be created only starting from a template. Supported dashboard template formats are JSON and YAML. The name parameter is optional. If it is provided then it overrides the name retrieved from the template. The `override` flag can be used to override the template `thing_id` placeholder with the actual ID of the thing to be used.
137+
138+
`$ arduino-cloud-cli dashboard create --name <dashboardName> --template <template.(json|yaml)> --override <thing-0>=<actualThingID>,<thing-1>=<otherActualThingID>`

Diff for: cli/dashboard/create.go

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// This file is part of arduino-cloud-cli.
2+
//
3+
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU Affero General Public License as published
7+
// by the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU Affero General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU Affero General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
package dashboard
19+
20+
import (
21+
"fmt"
22+
"os"
23+
"strings"
24+
25+
"github.com/arduino/arduino-cli/cli/errorcodes"
26+
"github.com/arduino/arduino-cli/cli/feedback"
27+
"github.com/arduino/arduino-cloud-cli/command/dashboard"
28+
"github.com/sirupsen/logrus"
29+
"github.com/spf13/cobra"
30+
)
31+
32+
var createFlags struct {
33+
name string
34+
template string
35+
override map[string]string
36+
}
37+
38+
func initCreateCommand() *cobra.Command {
39+
createCommand := &cobra.Command{
40+
Use: "create",
41+
Short: "Create a dashboard from a template",
42+
Long: "Create a dashboard from a template for Arduino IoT Cloud",
43+
Run: runCreateCommand,
44+
}
45+
createCommand.Flags().StringVarP(&createFlags.name, "name", "n", "", "Dashboard name")
46+
createCommand.Flags().StringVarP(&createFlags.template, "template", "t", "",
47+
"File containing a dashboard template, JSON and YAML format are supported",
48+
)
49+
createCommand.Flags().StringToStringVarP(&createFlags.override, "override", "o", nil,
50+
"Map stating the items to be overridden. Ex: 'thing-0=xxxxxxxx,thing-1=yyyyyyyy'")
51+
52+
createCommand.MarkFlagRequired("template")
53+
return createCommand
54+
}
55+
56+
func runCreateCommand(cmd *cobra.Command, args []string) {
57+
logrus.Infof("Creating dashboard from template %s\n", createFlags.template)
58+
59+
params := &dashboard.CreateParams{
60+
Template: createFlags.template,
61+
Override: createFlags.override,
62+
}
63+
if createFlags.name != "" {
64+
params.Name = &createFlags.name
65+
}
66+
67+
dashboard, err := dashboard.Create(params)
68+
if err != nil {
69+
feedback.Errorf("Error during dashboard create: %v", err)
70+
os.Exit(errorcodes.ErrGeneric)
71+
}
72+
73+
feedback.PrintResult(createResult{dashboard})
74+
}
75+
76+
type createResult struct {
77+
dashboard *dashboard.DashboardInfo
78+
}
79+
80+
func (r createResult) Data() interface{} {
81+
return r.dashboard
82+
}
83+
84+
func (r createResult) String() string {
85+
return fmt.Sprintf(
86+
"name: %s\nid: %s\nupdated_at: %s\nwidgets: %s",
87+
r.dashboard.Name,
88+
r.dashboard.ID,
89+
r.dashboard.UpdatedAt,
90+
strings.Join(r.dashboard.Widgets, ", "),
91+
)
92+
}

Diff for: cli/dashboard/dashboard.go

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func NewCommand() *cobra.Command {
2828
Long: "Dashboard commands.",
2929
}
3030

31+
dashboardCommand.AddCommand(initCreateCommand())
3132
dashboardCommand.AddCommand(initListCommand())
3233
dashboardCommand.AddCommand(initDeleteCommand())
3334
dashboardCommand.AddCommand(initExtractCommand())

Diff for: command/dashboard/create.go

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// This file is part of arduino-cloud-cli.
2+
//
3+
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU Affero General Public License as published
7+
// by the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// This program is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU Affero General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU Affero General Public License
16+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
package dashboard
19+
20+
import (
21+
"errors"
22+
23+
"github.com/arduino/arduino-cloud-cli/internal/config"
24+
"github.com/arduino/arduino-cloud-cli/internal/iot"
25+
"github.com/arduino/arduino-cloud-cli/internal/template"
26+
)
27+
28+
// CreateParams contains the parameters needed to create a new dashboard.
29+
type CreateParams struct {
30+
Name *string // Name of the new dashboard
31+
Override map[string]string // Template parameters to be overridden
32+
Template string // Path of the template file
33+
}
34+
35+
// Create allows to create a new dashboard
36+
func Create(params *CreateParams) (*DashboardInfo, error) {
37+
conf, err := config.Retrieve()
38+
if err != nil {
39+
return nil, err
40+
}
41+
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
dashboard, err := template.LoadDashboard(params.Template, params.Override, iotClient)
47+
if err != nil {
48+
return nil, err
49+
}
50+
51+
// Name passed as parameter has priority over name from template
52+
if params.Name != nil {
53+
dashboard.Name = *params.Name
54+
}
55+
// If name is not specified in the template, it should be passed as parameter
56+
if dashboard.Name == "" {
57+
return nil, errors.New("dashboard name not specified")
58+
}
59+
60+
newDashboard, err := iotClient.DashboardCreate(dashboard)
61+
if err != nil {
62+
return nil, err
63+
}
64+
65+
return getDashboardInfo(newDashboard), nil
66+
}

Diff for: go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ require (
77
github.com/arduino/arduino-cli v0.0.0-20210607095659-16f41352eac3
88
github.com/arduino/go-paths-helper v1.6.1
99
github.com/arduino/iot-client-go v1.3.4-0.20210930122852-04551f4cb061
10+
github.com/gofrs/uuid v4.0.0+incompatible
11+
github.com/google/go-cmp v0.5.6
1012
github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6
1113
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5
1214
github.com/sirupsen/logrus v1.8.1

Diff for: go.sum

+4-1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
137137
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
138138
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
139139
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
140+
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
141+
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
140142
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
141143
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
142144
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -177,8 +179,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
177179
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
178180
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
179181
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
180-
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
181182
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
183+
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
184+
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
182185
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
183186
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
184187
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=

Diff for: internal/iot/client.go

+10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type Client interface {
3939
ThingDelete(id string) error
4040
ThingShow(id string) (*iotclient.ArduinoThing, error)
4141
ThingList(ids []string, device *string, props bool) ([]iotclient.ArduinoThing, error)
42+
DashboardCreate(dashboard *iotclient.Dashboardv2) (*iotclient.ArduinoDashboardv2, error)
4243
DashboardShow(id string) (*iotclient.ArduinoDashboardv2, error)
4344
DashboardDelete(id string) error
4445
DashboardList() ([]iotclient.ArduinoDashboardv2, error)
@@ -205,6 +206,15 @@ func (cl *client) ThingList(ids []string, device *string, props bool) ([]iotclie
205206
return things, nil
206207
}
207208

209+
// DashboardCreate adds a new dashboard on Arduino IoT Cloud.
210+
func (cl *client) DashboardCreate(dashboard *iotclient.Dashboardv2) (*iotclient.ArduinoDashboardv2, error) {
211+
newDashboard, _, err := cl.api.DashboardsV2Api.DashboardsV2Create(cl.ctx, *dashboard)
212+
if err != nil {
213+
return nil, fmt.Errorf("%s: %w", "adding new dashboard", errorDetail(err))
214+
}
215+
return &newDashboard, nil
216+
}
217+
208218
// DashboardShow allows to retrieve a specific dashboard, given its id,
209219
// from Arduino IoT Cloud.
210220
func (cl *client) DashboardShow(id string) (*iotclient.ArduinoDashboardv2, error) {

0 commit comments

Comments
 (0)