From 60475f518ed208714363bf29d5183d9da593c0d6 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@gmail.com>
Date: Thu, 21 Apr 2022 00:51:52 +1000
Subject: [PATCH] Render link to "parent template part" (if it exists)

---
 lib/inventree/part.dart     |  3 +++
 lib/l10n                    |  2 +-
 lib/widget/part_detail.dart | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart
index a5b7ef39..723a7e8e 100644
--- a/lib/inventree/part.dart
+++ b/lib/inventree/part.dart
@@ -305,6 +305,9 @@ class InvenTreePart extends InvenTreeModel {
 
     String get units => (jsondata["units"] ?? "") as String;
 
+    // Get the ID of the Part that this part is a variant of (or null)
+    int? get variantOf => jsondata["variant_of"] as int?;
+
     // Get the number of units being build for this Part
     double get building => double.tryParse(jsondata["building"].toString()) ?? 0;
 
diff --git a/lib/l10n b/lib/l10n
index f4cb1831..cab0624b 160000
--- a/lib/l10n
+++ b/lib/l10n
@@ -1 +1 @@
-Subproject commit f4cb183197069dbf166b453358771dffa36b40ed
+Subproject commit cab0624b64c1b5926bd7188b4ae8381f1181842d
diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart
index 07a37c44..b66f91a9 100644
--- a/lib/widget/part_detail.dart
+++ b/lib/widget/part_detail.dart
@@ -37,6 +37,8 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
 
   InvenTreePart part;
 
+  InvenTreePart? parentPart;
+
   @override
   String getAppBarTitle(BuildContext context) => L10().partDetails;
 
@@ -92,6 +94,21 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
       Navigator.of(context).pop();
     }
 
+    // If the part points to a parent "template" part, request that too
+    int? templatePartId = part.variantOf;
+
+    if (templatePartId == null) {
+      parentPart = null;
+    } else {
+      final result = await InvenTreePart().get(templatePartId);
+
+      if (result != null && result is InvenTreePart) {
+        parentPart = result;
+      } else {
+        parentPart = null;
+      }
+    }
+
     await part.getTestTemplates();
   }
 
@@ -182,6 +199,26 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
       );
     }
 
+    if (parentPart != null) {
+      tiles.add(
+        ListTile(
+          title: Text(L10().templatePart),
+          subtitle: Text(parentPart!.fullname),
+          leading: InvenTreeAPI().getImage(
+            parentPart!.thumbnail,
+            width: 32,
+            height: 32,
+          ),
+          onTap: () {
+            Navigator.push(
+              context,
+              MaterialPageRoute(builder: (context) => PartDetailWidget(parentPart!))
+            );
+          }
+        )
+      );
+    }
+
     // Category information
     if (part.categoryName.isNotEmpty) {
       tiles.add(