Skip to content

Commit

Permalink
feat(app) add graph view
Browse files Browse the repository at this point in the history
  • Loading branch information
helderbetiol committed Jun 18, 2024
1 parent 7d68044 commit bf9cffc
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 93 deletions.
2 changes: 1 addition & 1 deletion APP/lib/common/appbar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:ogree_app/models/netbox.dart';
import 'package:ogree_app/pages/login_page.dart';
import 'package:ogree_app/pages/projects_page.dart';
import 'package:ogree_app/pages/tenant_page.dart';
import 'package:ogree_app/widgets/change_password_popup.dart';
import 'package:ogree_app/widgets/login/change_password_popup.dart';
import 'package:ogree_app/widgets/common/language_toggle.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:ogree_app/widgets/tools/download_tool_popup.dart';
Expand Down
46 changes: 21 additions & 25 deletions APP/lib/pages/alert_page.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:ogree_app/common/appbar.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:ogree_app/models/tenant.dart';
import 'package:ogree_app/pages/projects_page.dart';
import 'package:ogree_app/widgets/select_objects/treeapp_controller.dart';
Expand All @@ -25,7 +24,6 @@ class AlertPageState extends State<AlertPage> with TickerProviderStateMixin {

@override
Widget build(BuildContext context) {
final localeMsg = AppLocalizations.of(context)!;
return Scaffold(
backgroundColor: const Color.fromARGB(255, 238, 238, 241),
appBar: myAppBar(context, widget.userEmail,
Expand Down Expand Up @@ -90,7 +88,7 @@ class AlertPageState extends State<AlertPage> with TickerProviderStateMixin {
],
),
),
VerticalDivider(
const VerticalDivider(
width: 30,
thickness: 0.5,
color: Colors.grey,
Expand Down Expand Up @@ -141,7 +139,7 @@ class AlertPageState extends State<AlertPage> with TickerProviderStateMixin {
backgroundColor: typeColor,
label: Text(
" $type ",
style: TextStyle(
style: const TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: Colors.black),
Expand All @@ -167,7 +165,7 @@ class AlertPageState extends State<AlertPage> with TickerProviderStateMixin {
TextSpan(
children: [
TextSpan(
style: new TextStyle(
style: const TextStyle(
fontSize: 14.0,
color: Colors.black,
),
Expand All @@ -176,31 +174,29 @@ class AlertPageState extends State<AlertPage> with TickerProviderStateMixin {
text: 'Minor Alert\n',
style: Theme.of(context).textTheme.headlineLarge,
),
TextSpan(text: '\nThe temperature of device '),
TextSpan(
const TextSpan(text: '\nThe temperature of device '),
const TextSpan(
text: 'BASIC.A.R1.A02.chassis01',
style: new TextStyle(fontWeight: FontWeight.bold)),
TextSpan(
style: TextStyle(fontWeight: FontWeight.bold)),
const TextSpan(
text:
' is higher than usual. This could impact the performance of your applications running in a Kubernetes cluster with nodes in this device: "my-frontend-app" and "my-backend-app".\n'),
...getSubtitle("Details:"),
TextSpan(
const TextSpan(
text:
'The last measurement of temperature for the device in question reads '),
TextSpan(
text: '64°C',
style: new TextStyle(fontWeight: FontWeight.bold)),
TextSpan(
const TextSpan(
text: '64°C', style: TextStyle(fontWeight: FontWeight.bold)),
const TextSpan(
text:
'. The temperature recommendation for a chassis of this type is to not surpass '),
TextSpan(
text: '55°C',
style: new TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: '.\n'),
const TextSpan(
text: '55°C', style: TextStyle(fontWeight: FontWeight.bold)),
const TextSpan(text: '.\n'),
...getSubtitle("Impacted by this alert:"),
getWidgetSpan(" BASIC.A.R1.A02.chassis01", "Physical - Device",
Colors.teal),
TextSpan(text: '\n'),
const TextSpan(text: '\n'),
...getSubtitle("May also be impacted:"),
getWidgetSpan(" BASIC.A.R1.A02.chassis01.blade01",
"Physical - Device", Colors.teal),
Expand All @@ -224,7 +220,7 @@ class AlertPageState extends State<AlertPage> with TickerProviderStateMixin {
TextSpan(
children: [
TextSpan(
style: new TextStyle(
style: const TextStyle(
fontSize: 14.0,
color: Colors.black,
),
Expand All @@ -233,23 +229,23 @@ class AlertPageState extends State<AlertPage> with TickerProviderStateMixin {
text: 'Hint\n',
style: Theme.of(context).textTheme.headlineLarge,
),
TextSpan(
const TextSpan(
text:
'\nAll nodes of a kubernetes cluster are servers from the same rack.\n'),
...getSubtitle("Details:"),
TextSpan(
const TextSpan(
text:
'The Kubernetes cluster "kubernetes-cluster" has the following devices as its nodes: "chassis01.blade01" , "chassis01.blade02" and "chassis01.blade03". All of these devices are in the same rack "BASIC.A.R1.A02".\n'),
...getSubtitle("Suggestion:"),
TextSpan(
const TextSpan(
text:
'To limit impacts to the cluster and its applications in case of issue with this rack, consider adding a server from a different rack as a node to this cluster.\n'),
...getSubtitle("Impacted by this hint:"),
getWidgetSpan(
" BASIC.A.R1.A02", "Physical - Device", Colors.teal),
getWidgetSpan(" kubernetes-cluster", "Logical - Application",
Colors.deepPurple),
TextSpan(text: '\n'),
const TextSpan(text: '\n'),
...getSubtitle("May also be impacted:"),
getWidgetSpan(" kubernetes-cluster.my-frontend-app",
"Logical - Application", Colors.deepPurple),
Expand Down Expand Up @@ -295,7 +291,7 @@ class AlertPageState extends State<AlertPage> with TickerProviderStateMixin {
text: '\n$subtitle\n',
style: Theme.of(context).textTheme.headlineMedium,
),
TextSpan(text: '\n'),
const TextSpan(text: '\n'),
];
}
}
4 changes: 2 additions & 2 deletions APP/lib/pages/login_page.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:ogree_app/widgets/common/language_toggle.dart';
import 'package:ogree_app/widgets/login_card.dart';
import 'package:ogree_app/widgets/reset_card.dart';
import 'package:ogree_app/widgets/login/login_card.dart';
import 'package:ogree_app/widgets/login/reset_card.dart';

class LoginPage extends StatefulWidget {
final bool isPasswordReset;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:ogree_app/common/api_backend.dart';
import 'package:ogree_app/common/definitions.dart';
import 'package:ogree_app/common/snackbar.dart';
import 'package:ogree_app/common/theme.dart';
import 'package:ogree_app/widgets/common/form_field.dart';

import '../common/snackbar.dart';

class ChangePasswordPopup extends StatefulWidget {
const ChangePasswordPopup({super.key});

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:ogree_app/common/snackbar.dart';
import 'package:ogree_app/common/theme.dart';
import 'package:ogree_app/pages/login_page.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:ogree_app/widgets/login_card.dart';
import 'package:ogree_app/widgets/login/login_card.dart';

class ResetCard extends StatelessWidget {
final _formKey = GlobalKey<FormState>();
Expand Down Expand Up @@ -57,7 +57,7 @@ class ResetCard extends StatelessWidget {
)
: Center(
child: Image.asset(
"assets/edf_logo.png",
"assets/custom/logo.png",
height: 30,
),
),
Expand Down
160 changes: 160 additions & 0 deletions APP/lib/widgets/object_graph_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import 'package:flutter/material.dart';
import 'package:graphview/GraphView.dart';
import 'package:ogree_app/common/api_backend.dart';
import 'package:ogree_app/common/definitions.dart';
import 'package:ogree_app/common/snackbar.dart';
import 'package:ogree_app/common/theme.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class ObjectGraphView extends StatefulWidget {
String rootId;
ObjectGraphView(this.rootId);
@override
_ObjectGraphViewState createState() => _ObjectGraphViewState();
}

class _ObjectGraphViewState extends State<ObjectGraphView> {
bool loaded = false;
Map<String, String> idCategory = {};

final Graph graph = Graph();

SugiyamaConfiguration builder = SugiyamaConfiguration()
..bendPointShape = CurvedBendPointShape(curveLength: 10);

@override
void initState() {
super.initState();

builder
..nodeSeparation = (25)
..levelSeparation = (35)
..orientation = SugiyamaConfiguration.ORIENTATION_TOP_BOTTOM;
}

@override
Widget build(BuildContext context) {
return FutureBuilder(
future: !loaded ? getObject() : null,
builder: (context, _) {
if (!loaded) {
return const Center(child: CircularProgressIndicator());
}
return Center(
child: Container(
constraints: const BoxConstraints(maxHeight: 520, maxWidth: 800),
margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: PopupDecoration,
child: Padding(
padding: const EdgeInsets.fromLTRB(40, 20, 40, 15),
child: Scaffold(
backgroundColor: Colors.white,
body: Column(
mainAxisSize: MainAxisSize.max,
children: [
Center(
child: Text(
AppLocalizations.of(context)!.viewGraph,
style: Theme.of(context).textTheme.headlineMedium,
),
),
Expanded(
child: InteractiveViewer(
alignment: Alignment.center,
constrained: true,
boundaryMargin:
const EdgeInsets.all(double.infinity),
minScale: 0.0001,
maxScale: 10.6,
child: OverflowBox(
alignment: Alignment.center,
minWidth: 0.0,
minHeight: 0.0,
maxWidth: double.infinity,
maxHeight: double.infinity,
child: GraphView(
graph: graph,
algorithm: SugiyamaAlgorithm(builder),
paint: Paint()
..color = Colors.blue
..strokeWidth = 1
..style = PaintingStyle.stroke,
builder: (Node node) {
var a = node.key!.value as String?;
return rectangleWidget(a!);
},
),
)),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton.icon(
onPressed: () {
Navigator.of(context).pop();
},
label: const Text("OK"),
icon: const Icon(Icons.thumb_up, size: 16))
],
)
],
),
),
),
),
);
});
}

Widget rectangleWidget(String a) {
return Tooltip(
message: a,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(
color: idCategory[a] == "virtual_obj"
? Colors.purple[100]!
: Colors.blue[100]!,
spreadRadius: 1),
],
),
child: Text('${a.split(".").last}')),
);
}

getObject() async {
final messenger = ScaffoldMessenger.of(context);
var result = await fetchObjectChildren(widget.rootId);
switch (result) {
case Success(value: final value):
print(value);
addToGraph(value);
loaded = true;
return;
case Failure(exception: final exception):
showSnackBar(messenger, exception.toString(), isError: true);
}
}

addToGraph(Map<String, dynamic> value) {
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"])) {
graph.addEdge(node, Node.Id(vlink),
paint: Paint()..color = Colors.purple);
}
}
if (value["children"] != null) {
for (var child in List<Map<String, dynamic>>.from(value["children"])) {
var childNode = addToGraph(child);
graph.addEdge(node, childNode);
}
}
return node;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:ogree_app/common/definitions.dart';
import 'package:ogree_app/common/popup_dialog.dart';
import 'package:ogree_app/common/snackbar.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:ogree_app/pages/layer_graph.dart';
import 'package:ogree_app/widgets/object_graph_view.dart';
import 'package:ogree_app/pages/tenant_page.dart';
import 'package:ogree_app/widgets/select_objects/view_object_popup.dart';
import 'package:ogree_app/widgets/select_objects/object_popup.dart';
Expand Down
Loading

0 comments on commit bf9cffc

Please sign in to comment.