Skip to content

Commit

Permalink
fix(cli) pillars and separators as map (#484)
Browse files Browse the repository at this point in the history
* fix(cli) pillars and separators as map

* fix(cli,app) test and vconfig input
  • Loading branch information
helderbetiol authored Jun 24, 2024
1 parent 77ce4a9 commit 6bf309f
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 63 deletions.
18 changes: 11 additions & 7 deletions API/models/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,18 @@ func updateOldObjWithPatch(old map[string]interface{}, patch map[string]interfac
for k, v := range patch {
switch patchValueCasted := v.(type) {
case map[string]interface{}:
switch oldValueCasted := old[k].(type) {
case map[string]interface{}:
err := updateOldObjWithPatch(oldValueCasted, patchValueCasted)
if err != nil {
return err
if k == "pillars" || k == "separators" {
old[k] = v
} else {
switch oldValueCasted := old[k].(type) {
case map[string]interface{}:
err := updateOldObjWithPatch(oldValueCasted, patchValueCasted)
if err != nil {
return err
}
default:
old[k] = v
}
default:
return errors.New("Wrong format for property " + k)
}
default:
if k == "filter" && strings.HasPrefix(v.(string), "&") {
Expand Down
4 changes: 3 additions & 1 deletion APP/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -215,5 +215,7 @@
"viewAlerts": "View alerts",
"temperatureAlert1": "The temperature of the device ",
"temperatureAlert2": " is higher than usual. This could impact performance for your applications: \"my-frontend-app\" and \"my-backend-app\".",
"oneAlert": "1 minor alert"
"oneAlert": "1 minor alert",

"virtualConfigTitle" : "Virtual Configuration:"
}
4 changes: 3 additions & 1 deletion APP/lib/l10n/app_es.arb
Original file line number Diff line number Diff line change
Expand Up @@ -215,5 +215,7 @@
"viewAlerts": "Ver alertas",
"temperatureAlert1": "La temperatura del dispositivo ",
"temperatureAlert2": " es más alta de lo usual. Esto podría impactar el rendimiento de sus aplicaciones: \"my-frontend-app\" y \"my-backend-app\".",
"oneAlert": "1 alerta menor"
"oneAlert": "1 alerta menor",

"virtualConfigTitle" : "Virtual Config:"
}
4 changes: 3 additions & 1 deletion APP/lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@
"viewAlerts": "Voir les alertes",
"temperatureAlert1": "La temperature du device ",
"temperatureAlert2": " est plus élevée que d'habitude. Cela peut avoir un impact sur les performances de vos applications : \"my-frontend-app\" et \"my-backend-app\".",
"oneAlert": "1 alerte mineur"
"oneAlert": "1 alerte mineur",

"virtualConfigTitle" : "Virtual Config :"

}
4 changes: 3 additions & 1 deletion APP/lib/l10n/app_pt.arb
Original file line number Diff line number Diff line change
Expand Up @@ -215,5 +215,7 @@
"viewAlerts": "Ver alertas",
"temperatureAlert1": "A temperature do device ",
"temperatureAlert2": " está acima do normal. Isso pode impactar a performance de suas aplicações: \"my-frontend-app\" e \"my-backend-app\"",
"oneAlert": "1 alerta menor"
"oneAlert": "1 alerta menor",

"virtualConfigTitle" : "Virtual Config:"
}
4 changes: 2 additions & 2 deletions APP/lib/widgets/object_graph_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ class _ObjectGraphViewState extends State<ObjectGraphView> {
final node = Node.Id(value["id"]);
graph.addNode(node);
idCategory[value["id"]] = value["category"];
if (value["attributes"] != null && value["attributes"]["vlink"] != null) {
for (var vlink in List<String>.from(value["attributes"]["vlink"])) {
if (value["attributes"] != null && value["attributes"]["vlinks"] != null) {
for (var vlink in List<String>.from(value["attributes"]["vlinks"])) {
graph.addEdge(node, Node.Id(vlink),
paint: Paint()..color = Colors.purple);
}
Expand Down
67 changes: 63 additions & 4 deletions APP/lib/widgets/select_objects/object_popup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,10 @@ class _ObjectPopupState extends State<ObjectPopup> {
case 3:
categories = [PhyCategories.device.name, PhyCategories.group.name];
default:
categories = [PhyCategories.device.name];
categories = [
PhyCategories.device.name,
PhyCategories.virtual_obj.name
];
}
}
return categories.map<DropdownMenuItem<String>>((String value) {
Expand Down Expand Up @@ -398,6 +401,7 @@ class _ObjectPopupState extends State<ObjectPopup> {
var attrs = Map<String, dynamic>.from(
jsonResult["properties"]["attributes"]["properties"]);
categoryAttrs[obj] = attrs.keys.toList();
categoryAttrs[obj]!.remove("virtual_config");
if (jsonResult["properties"]["attributes"]["required"] != null) {
// Get required ones
var requiredAttrs = List<String>.from(
Expand Down Expand Up @@ -526,7 +530,8 @@ class _ObjectPopupState extends State<ObjectPopup> {
for (var attr in objDataAttrs.entries) {
if (!categoryAttrs[_objCategory]!.contains(attr.key) &&
!categoryAttrs[_objCategory]!
.contains(starSymbol + attr.key)) {
.contains(starSymbol + attr.key) &&
attr.key != "virtual_config") {
// add custom attribute
customAttributesRows.add(CustomAttrRow(
customAttributesRows.length,
Expand All @@ -545,7 +550,8 @@ class _ObjectPopupState extends State<ObjectPopup> {
for (var attr in objDataAttrs.entries) {
if (!categoryAttrs[_objCategory]!.contains(attr.key) &&
!categoryAttrs[_objCategory]!
.contains(starSymbol + attr.key)) {
.contains(starSymbol + attr.key) &&
attr.key != "virtual_config") {
// add custom attribute
customAttributesRows.add(CustomAttrRow(
customAttributesRows.length,
Expand Down Expand Up @@ -807,7 +813,9 @@ class _ObjectPopupState extends State<ObjectPopup> {
if (newValue != null && newValue.isNotEmpty) {
// check type
var numValue = num.tryParse(newValue);
if (numValue != null) {
if (attrKey == "virtual_config") {
objDataAttrs[attrKey] = json.decode(newValue);
} else if (numValue != null) {
// is number
objDataAttrs[attrKey] = numValue.toDouble();
} else if (newValue.length >= 2 &&
Expand Down Expand Up @@ -870,6 +878,57 @@ class _ObjectPopupState extends State<ObjectPopup> {
label: Text(localeMsg.attribute)),
),
),
virtualConfigInput(),
],
);
}

virtualConfigInput() {
if (_objCategory != "virtual_obj" && _objCategory != "device") {
return Container();
}
Map<String, String> virtualAttrs = {
"clusterId": "string (e.g. kube-cluster)",
"type": "string (e.g. node)",
"role": "string (e.g. master)"
};
List<String> virtualAttrsKeys = virtualAttrs.keys.toList();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 8.0, left: 6, bottom: 6),
child: Text(AppLocalizations.of(context)!.virtualConfigTitle),
),
SizedBox(
height:
(virtualAttrsKeys.length ~/ 2 + virtualAttrsKeys.length % 2) * 60,
child: GridView.count(
physics: const NeverScrollableScrollPhysics(),
childAspectRatio: 3.5,
shrinkWrap: true,
padding: const EdgeInsets.only(left: 4),
crossAxisCount: 2,
children: List.generate(virtualAttrsKeys.length, (index) {
return CustomFormField(
tipStr: virtualAttrs[virtualAttrsKeys[index]] ?? "string",
save: (newValue) {
if (objDataAttrs["virtual_config"] == null) {
objDataAttrs["virtual_config"] = {};
}
objDataAttrs["virtual_config"][virtualAttrsKeys[index]] =
newValue;
},
label: virtualAttrsKeys[index],
icon: Icons.tag_sharp,
isCompact: true,
shouldValidate: false,
initialValue: objDataAttrs["virtual_config"]
?[virtualAttrsKeys[index]]
?.toString());
}),
),
),
],
);
}
Expand Down
13 changes: 6 additions & 7 deletions APP/lib/widgets/select_objects/view_object_popup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,15 @@ class _ViewObjectPopupState extends State<ViewObjectPopup> {
}

List<DropdownMenuItem<String>> getCategoryMenuItems() {
List<String> categories = objsByNamespace[widget.namespace]!;
return categories.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
return [
DropdownMenuItem<String>(
value: _objCategory,
child: Text(
value,
_objCategory,
overflow: TextOverflow.ellipsis,
),
);
}).toList();
)
];
}

getObject() async {
Expand Down
38 changes: 13 additions & 25 deletions CLI/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,15 +546,14 @@ func setLabelBackground(path string, values []any) (map[string]any, error) {
return nil, cmd.C.InteractObject(path, "labelBackground", c, false)
}

func addToStringMap[T any](stringMap string, key string, val T) (string, bool) {
m := map[string]T{}
if stringMap != "" {
json.Unmarshal([]byte(stringMap), &m)
func addToMap[T any](mapToAdd any, key string, val T) (map[string]any, bool) {
attrMap, ok := mapToAdd.(map[string]any)
if !ok {
attrMap = map[string]any{}
}
_, keyExist := m[key]
m[key] = val
mBytes, _ := json.Marshal(m)
return string(mBytes), keyExist
_, keyExist := attrMap[key]
attrMap[key] = val
return attrMap, keyExist
}

func removeFromStringMap[T any](stringMap string, key string) (string, bool) {
Expand Down Expand Up @@ -602,10 +601,9 @@ func addRoomSeparator(path string, values []any) (map[string]any, error) {
return nil, err
}
attr := obj["attributes"].(map[string]any)
separators, _ := attr["separators"].(string)
newSeparator := Separator{startPos, endPos, sepType}
var keyExist bool
attr["separators"], keyExist = addToStringMap[Separator](separators, name, newSeparator)
attr["separators"], keyExist = addToMap[Separator](attr["separators"], name, newSeparator)
obj, err = cmd.C.UpdateObj(path, map[string]any{"attributes": attr}, false)
if err != nil {
return nil, err
Expand Down Expand Up @@ -647,10 +645,9 @@ func addRoomPillar(path string, values []any) (map[string]any, error) {
return nil, err
}
attr := obj["attributes"].(map[string]any)
pillars, _ := attr["pillars"].(string)
newPillar := Pillar{centerXY, sizeXY, rotation}
var keyExist bool
attr["pillars"], keyExist = addToStringMap[Pillar](pillars, name, newPillar)
attr["pillars"], keyExist = addToMap[Pillar](attr["pillars"], name, newPillar)
obj, err = cmd.C.UpdateObj(path, map[string]any{"attributes": attr}, false)
if err != nil {
return nil, err
Expand All @@ -668,21 +665,12 @@ func deleteRoomPillarOrSeparator(path, attribute, name string) (map[string]any,
return nil, err
}
attributes := obj["attributes"].(map[string]any)
stringMap, _ := attributes[attribute+"s"].(string)
var ok bool
switch attribute {
case "pillar":
stringMap, ok = removeFromStringMap[Pillar](stringMap, name)
case "separator":
stringMap, ok = removeFromStringMap[Separator](stringMap, name)
default:
return nil, errors.New("\"separator\" or \"pillar\" expected")
}

if !ok {
attrMap, ok := attributes[attribute+"s"].(map[string]any)
if !ok || attrMap[name] == nil {
return nil, fmt.Errorf("%s %s does not exist", attribute, name)
}
attributes[attribute+"s"] = stringMap
delete(attrMap, name)
attributes[attribute+"s"] = attrMap
return cmd.C.UpdateObj(path, map[string]any{"attributes": attributes}, false)
}

Expand Down
28 changes: 14 additions & 14 deletions CLI/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,14 +387,14 @@ func TestSetLabel(t *testing.T) {
assert.Nil(t, value)
}

func TestAddToStringMap(t *testing.T) {
newMap, replaced := addToStringMap[int]("{\"a\":3}", "b", 10)
func TestAddToMap(t *testing.T) {
newMap, replaced := addToMap[int](map[string]any{"a": 3}, "b", 10)

assert.Equal(t, "{\"a\":3,\"b\":10}", newMap)
assert.Equal(t, map[string]any{"a": 3, "b": 10}, newMap)
assert.False(t, replaced)

newMap, replaced = addToStringMap[int](newMap, "b", 15)
assert.Equal(t, "{\"a\":3,\"b\":15}", newMap)
newMap, replaced = addToMap[int](newMap, "b", 15)
assert.Equal(t, map[string]any{"a": 3, "b": 15}, newMap)
assert.True(t, replaced)
}

Expand Down Expand Up @@ -438,8 +438,8 @@ func TestAddRoomSeparatorOrPillarWorks(t *testing.T) {
values []any
newAttributes map[string]any
}{
{"AddRoomSeparator", addRoomSeparator, []any{"mySeparator", []float64{1., 2.}, []float64{1., 2.}, "wireframe"}, map[string]interface{}{"separators": "{\"mySeparator\":{\"startPosXYm\":[1,2],\"endPosXYm\":[1,2],\"type\":\"wireframe\"}}"}},
{"AddRoomPillar", addRoomPillar, []any{"myPillar", []float64{1., 2.}, []float64{1., 2.}, 2.5}, map[string]interface{}{"pillars": "{\"myPillar\":{\"centerXY\":[1,2],\"sizeXY\":[1,2],\"rotation\":2.5}}"}},
{"AddRoomSeparator", addRoomSeparator, []any{"mySeparator", []float64{1., 2.}, []float64{1., 2.}, "wireframe"}, map[string]interface{}{"separators": map[string]interface{}{"mySeparator": Separator{StartPos: []float64{1, 2}, EndPos: []float64{1, 2}, Type: "wireframe"}}}},
{"AddRoomPillar", addRoomPillar, []any{"myPillar", []float64{1., 2.}, []float64{1., 2.}, 2.5}, map[string]interface{}{"pillars": map[string]interface{}{"myPillar": Pillar{CenterXY: []float64{1, 2}, SizeXY: []float64{1, 2}, Rotation: 2.5}}}},
}

for _, tt := range tests {
Expand Down Expand Up @@ -467,7 +467,7 @@ func TestDeleteRoomPillarOrSeparatorWithError(t *testing.T) {
separatorName string
errorMessage string
}{
{"InvalidArgument", "other", "separator", "\"separator\" or \"pillar\" expected"},
{"InvalidArgument", "other", "separator", "other separator does not exist"},
{"SeparatorDoesNotExist", "separator", "mySeparator", "separator mySeparator does not exist"},
}

Expand All @@ -490,15 +490,15 @@ func TestDeleteRoomPillarOrSeparatorSeparator(t *testing.T) {
_, mockAPI, _, _ := test_utils.SetMainEnvironmentMock(t)

room := test_utils.GetEntity("room", "room", "site.building", "domain")
room["attributes"].(map[string]any)["separators"] = "{\"mySeparator\":{\"startPosXYm\":[1,2],\"endPosXYm\":[1,2],\"type\":\"wireframe\"}}"
room["attributes"].(map[string]any)["separators"] = map[string]interface{}{"mySeparator": Separator{StartPos: []float64{1, 2}, EndPos: []float64{1, 2}, Type: "wireframe"}}

updatedRoom := test_utils.GetEntity("room", "room", "site.building", "domain")
updatedRoom["attributes"] = map[string]any{"separators": "{}"}
updatedRoom["attributes"] = map[string]any{"separators": map[string]interface{}{}}

test_utils.MockGetObject(mockAPI, room)
test_utils.MockGetObject(mockAPI, room)

test_utils.MockUpdateObject(mockAPI, map[string]interface{}{"attributes": map[string]interface{}{"separators": "{}"}}, updatedRoom)
test_utils.MockUpdateObject(mockAPI, map[string]interface{}{"attributes": map[string]interface{}{"separators": map[string]interface{}{}}}, updatedRoom)
obj, err := deleteRoomPillarOrSeparator("/Physical/site/building/room", "separator", "mySeparator")

assert.Nil(t, err)
Expand All @@ -509,14 +509,14 @@ func TestDeleteRoomPillarOrSeparatorPillar(t *testing.T) {
_, mockAPI, _, _ := test_utils.SetMainEnvironmentMock(t)

room := test_utils.GetEntity("room", "room", "site.building", "domain")
room["attributes"].(map[string]any)["pillars"] = "{\"myPillar\":{\"centerXY\":[1,2],\"sizeXY\":[1,2],\"rotation\":\"2.5\"}}"
room["attributes"].(map[string]any)["pillars"] = map[string]interface{}{"myPillar": Pillar{CenterXY: []float64{1, 2}, SizeXY: []float64{1, 2}, Rotation: 2.5}}

updatedRoom := maps.Clone(room)
updatedRoom["attributes"] = map[string]any{"pillars": "{}"}
updatedRoom["attributes"] = map[string]any{"pillars": map[string]interface{}{}}

test_utils.MockGetObject(mockAPI, room)
test_utils.MockGetObject(mockAPI, room)
test_utils.MockUpdateObject(mockAPI, map[string]interface{}{"attributes": map[string]interface{}{"pillars": "{}"}}, updatedRoom)
test_utils.MockUpdateObject(mockAPI, map[string]interface{}{"attributes": map[string]interface{}{"pillars": map[string]interface{}{}}}, updatedRoom)
obj, err := deleteRoomPillarOrSeparator("/Physical/site/building/room", "pillar", "myPillar")

assert.Nil(t, err)
Expand Down

0 comments on commit 6bf309f

Please sign in to comment.