2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-12-16 09:08:05 +00:00

Parameters refactor (#738)

* refactor attachment code into its own file

* Add getters

* Remove custom models for each type of attachment

* Refactor existing widgets

* Fix double camera open bug

* Add check for modern parameter API

* Add generic parameter type

* Remove old code

* Remove dead code

* Refactor previous widget

* Remove unused imports

* Refactor common code

* format

* Update release notes

* Helper func to render parameters list tile

* Display parameters on part page

* parameters for company

* Supplier more model types:

- ManufacturerPart
- SupplierPart
- PurchaseOrder
- SalesOrder

* dart format

* Fix image prefix

* Remove unused import

* Adjust API version
This commit is contained in:
Oliver
2025-12-04 18:34:05 +11:00
committed by GitHub
parent 346b1a150f
commit 864c3eea76
12 changed files with 378 additions and 129 deletions

View File

@@ -353,6 +353,10 @@ class InvenTreeAPI {
// Supports separate search against "supplier" / "customer" / "manufacturer" // Supports separate search against "supplier" / "customer" / "manufacturer"
bool get supportsSplitCompanySearch => apiVersion >= 315; bool get supportsSplitCompanySearch => apiVersion >= 315;
// Does the server support the "modern" (consolidated) parameter API?
// Ref: https://github.com/inventree/InvenTree/pull/10699
bool get supportsModernParameters => apiVersion >= 429;
// Cached list of plugins (refreshed when we connect to the server) // Cached list of plugins (refreshed when we connect to the server)
List<InvenTreePlugin> _plugins = []; List<InvenTreePlugin> _plugins = [];

View File

@@ -0,0 +1,77 @@
import "package:inventree/inventree/model.dart";
class InvenTreeParameter extends InvenTreeModel {
InvenTreeParameter() : super();
InvenTreeParameter.fromJson(Map<String, dynamic> json) : super.fromJson(json);
@override
InvenTreeParameter createFromJson(Map<String, dynamic> json) =>
InvenTreeParameter.fromJson(json);
@override
String get URL => "parameter/";
@override
Map<String, Map<String, dynamic>> formFields() {
Map<String, Map<String, dynamic>> fields = {
"header": {
"type": "string",
"read_only": true,
"label": name,
"help_text": description,
"value": "",
},
"data": {"type": "string"},
"note": {},
};
return fields;
}
@override
String get name => getString("name", subKey: "template_detail");
@override
String get description => getString("description", subKey: "template_detail");
String get value => getString("data");
String get valueString {
String v = value;
if (units.isNotEmpty) {
v += " ";
v += units;
}
return v;
}
bool get as_bool => value.toLowerCase() == "true";
String get units => getString("units", subKey: "template_detail");
bool get is_checkbox =>
getBool("checkbox", subKey: "template_detail", backup: false);
// The model type of the instance this attachment is associated with
String get modelType => getString("model_type");
// The ID of the instance this attachment is associated with
int get modelId => getInt("model_id");
// Return a count of how many parameters exist against the specified model ID
Future<int> countParameters(String modelType, int modelId) async {
Map<String, String> filters = {};
if (!api.supportsModernParameters) {
return 0;
}
filters["model_type"] = modelType;
filters["model_id"] = modelId.toString();
return count(filters: filters);
}
}

View File

@@ -132,68 +132,6 @@ class InvenTreePartTestTemplate extends InvenTreeModel {
} }
} }
/*
Class representing the PartParameter database model
*/
class InvenTreePartParameter extends InvenTreeModel {
InvenTreePartParameter() : super();
InvenTreePartParameter.fromJson(Map<String, dynamic> json)
: super.fromJson(json);
@override
String get URL => "part/parameter/";
@override
List<String> get rolesRequired => ["part"];
@override
InvenTreeModel createFromJson(Map<String, dynamic> json) =>
InvenTreePartParameter.fromJson(json);
@override
Map<String, Map<String, dynamic>> formFields() {
Map<String, Map<String, dynamic>> fields = {
"header": {
"type": "string",
"read_only": true,
"label": name,
"help_text": description,
"value": "",
},
"data": {"type": "string"},
};
return fields;
}
@override
String get name => getString("name", subKey: "template_detail");
@override
String get description => getString("description", subKey: "template_detail");
String get value => getString("data");
String get valueString {
String v = value;
if (units.isNotEmpty) {
v += " ";
v += units;
}
return v;
}
bool get as_bool => value.toLowerCase() == "true";
String get units => getString("units", subKey: "template_detail");
bool get is_checkbox =>
getBool("checkbox", subKey: "template_detail", backup: false);
}
/* /*
* Class representing the Part database model * Class representing the Part database model
*/ */

View File

@@ -32,7 +32,6 @@ const String INV_LABEL_DEFAULT_PRINTER = "defaultLabelPrinter";
const String INV_LABEL_DEFAULT_PLUGIN = "defaultLabelPlugin"; const String INV_LABEL_DEFAULT_PLUGIN = "defaultLabelPlugin";
// Part settings // Part settings
const String INV_PART_SHOW_PARAMETERS = "partShowParameters";
const String INV_PART_SHOW_BOM = "partShowBom"; const String INV_PART_SHOW_BOM = "partShowBom";
const String INV_PART_SHOW_PRICING = "partShowPricing"; const String INV_PART_SHOW_PRICING = "partShowPricing";

View File

@@ -13,7 +13,6 @@ class InvenTreePartSettingsWidget extends StatefulWidget {
class _InvenTreePartSettingsState extends State<InvenTreePartSettingsWidget> { class _InvenTreePartSettingsState extends State<InvenTreePartSettingsWidget> {
_InvenTreePartSettingsState(); _InvenTreePartSettingsState();
bool partShowParameters = true;
bool partShowBom = true; bool partShowBom = true;
bool partShowPricing = true; bool partShowPricing = true;
bool stockShowHistory = false; bool stockShowHistory = false;
@@ -28,10 +27,6 @@ class _InvenTreePartSettingsState extends State<InvenTreePartSettingsWidget> {
} }
Future<void> loadSettings() async { Future<void> loadSettings() async {
partShowParameters = await InvenTreeSettingsManager().getBool(
INV_PART_SHOW_PARAMETERS,
true,
);
partShowBom = await InvenTreeSettingsManager().getBool( partShowBom = await InvenTreeSettingsManager().getBool(
INV_PART_SHOW_BOM, INV_PART_SHOW_BOM,
true, true,
@@ -68,23 +63,6 @@ class _InvenTreePartSettingsState extends State<InvenTreePartSettingsWidget> {
body: Container( body: Container(
child: ListView( child: ListView(
children: [ children: [
ListTile(
title: Text(L10().parameters),
subtitle: Text(L10().parametersSettingDetail),
leading: Icon(TablerIcons.list),
trailing: Switch(
value: partShowParameters,
onChanged: (bool value) {
InvenTreeSettingsManager().setValue(
INV_PART_SHOW_PARAMETERS,
value,
);
setState(() {
partShowParameters = value;
});
},
),
),
ListTile( ListTile(
title: Text(L10().bom), title: Text(L10().bom),
subtitle: Text(L10().bomEnable), subtitle: Text(L10().bomEnable),

View File

@@ -2,6 +2,7 @@ import "package:flutter/material.dart";
import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart";
import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
import "package:inventree/inventree/attachment.dart"; import "package:inventree/inventree/attachment.dart";
import "package:inventree/inventree/parameter.dart";
import "package:inventree/l10.dart"; import "package:inventree/l10.dart";
import "package:inventree/api.dart"; import "package:inventree/api.dart";
@@ -14,6 +15,7 @@ import "package:inventree/widget/attachment_widget.dart";
import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/link_icon.dart";
import "package:inventree/widget/order/purchase_order_list.dart"; import "package:inventree/widget/order/purchase_order_list.dart";
import "package:inventree/widget/order/sales_order_list.dart"; import "package:inventree/widget/order/sales_order_list.dart";
import "package:inventree/widget/parameter_widget.dart";
import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/refreshable_state.dart";
import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/snacks.dart";
import "package:inventree/widget/company/supplier_part_list.dart"; import "package:inventree/widget/company/supplier_part_list.dart";
@@ -38,6 +40,7 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
int outstandingPurchaseOrders = 0; int outstandingPurchaseOrders = 0;
int outstandingSalesOrders = 0; int outstandingSalesOrders = 0;
int parameterCount = 0;
int attachmentCount = 0; int attachmentCount = 0;
@override @override
@@ -185,6 +188,16 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
} }
}); });
InvenTreeParameter()
.countParameters(InvenTreeCompany.MODEL_TYPE, widget.company.pk)
.then((value) {
if (mounted) {
setState(() {
parameterCount = value;
});
}
});
InvenTreeAttachment() InvenTreeAttachment()
.countAttachments(InvenTreeCompany.MODEL_TYPE, widget.company.pk) .countAttachments(InvenTreeCompany.MODEL_TYPE, widget.company.pk)
.then((value) { .then((value) {
@@ -394,6 +407,18 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
); );
} }
ListTile? parameterTile = ShowParametersItem(
context,
InvenTreeCompany.MODEL_TYPE,
widget.company.pk,
parameterCount,
widget.company.canEdit,
);
if (parameterTile != null) {
tiles.add(parameterTile);
}
ListTile? attachmentTile = ShowAttachmentsItem( ListTile? attachmentTile = ShowAttachmentsItem(
context, context,
InvenTreeCompany.MODEL_TYPE, InvenTreeCompany.MODEL_TYPE,

View File

@@ -1,6 +1,8 @@
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart";
import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
import "package:inventree/inventree/attachment.dart";
import "package:inventree/inventree/parameter.dart";
import "package:inventree/l10.dart"; import "package:inventree/l10.dart";
import "package:inventree/api.dart"; import "package:inventree/api.dart";
@@ -8,6 +10,8 @@ import "package:inventree/app_colors.dart";
import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/company.dart";
import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/part.dart";
import "package:inventree/widget/attachment_widget.dart";
import "package:inventree/widget/parameter_widget.dart";
import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/refreshable_state.dart";
import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/snacks.dart";
@@ -31,6 +35,9 @@ class _ManufacturerPartDisplayState
extends RefreshableState<ManufacturerPartDetailWidget> { extends RefreshableState<ManufacturerPartDetailWidget> {
_ManufacturerPartDisplayState(); _ManufacturerPartDisplayState();
int parameterCount = 0;
int attachmentCount = 0;
@override @override
String getAppBarTitle() => L10().manufacturerPart; String getAppBarTitle() => L10().manufacturerPart;
@@ -42,7 +49,34 @@ class _ManufacturerPartDisplayState
if (!result) { if (!result) {
Navigator.of(context).pop(); Navigator.of(context).pop();
return;
} }
InvenTreeParameter()
.countParameters(
InvenTreeManufacturerPart.MODEL_TYPE,
widget.manufacturerPart.pk,
)
.then((value) {
if (mounted) {
setState(() {
parameterCount = value;
});
}
});
InvenTreeAttachment()
.countAttachments(
InvenTreeManufacturerPart.MODEL_TYPE,
widget.manufacturerPart.pk,
)
.then((value) {
if (mounted) {
setState(() {
attachmentCount = value;
});
}
});
} }
Future<void> editManufacturerPart(BuildContext context) async { Future<void> editManufacturerPart(BuildContext context) async {
@@ -91,11 +125,6 @@ class _ManufacturerPartDisplayState
List<Widget> getTiles(BuildContext context) { List<Widget> getTiles(BuildContext context) {
List<Widget> tiles = []; List<Widget> tiles = [];
if (loading) {
tiles.add(progressIndicator());
return tiles;
}
// Internal Part // Internal Part
tiles.add( tiles.add(
ListTile( ListTile(
@@ -174,6 +203,31 @@ class _ManufacturerPartDisplayState
); );
} }
ListTile? parameterTile = ShowParametersItem(
context,
InvenTreeManufacturerPart.MODEL_TYPE,
widget.manufacturerPart.pk,
parameterCount,
widget.manufacturerPart.canEdit,
);
if (parameterTile != null) {
tiles.add(parameterTile);
}
ListTile? attachmentTile = ShowAttachmentsItem(
context,
InvenTreeManufacturerPart.MODEL_TYPE,
widget.manufacturerPart.pk,
widget.manufacturerPart.MPN,
attachmentCount,
widget.manufacturerPart.canEdit,
);
if (attachmentTile != null) {
tiles.add(attachmentTile);
}
return tiles; return tiles;
} }
} }

View File

@@ -2,6 +2,9 @@ import "package:flutter/material.dart";
import "package:flutter_speed_dial/flutter_speed_dial.dart"; import "package:flutter_speed_dial/flutter_speed_dial.dart";
import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
import "package:inventree/helpers.dart"; import "package:inventree/helpers.dart";
import "package:inventree/inventree/attachment.dart";
import "package:inventree/inventree/parameter.dart";
import "package:inventree/widget/attachment_widget.dart";
import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/link_icon.dart";
import "package:inventree/app_colors.dart"; import "package:inventree/app_colors.dart";
@@ -11,6 +14,7 @@ import "package:inventree/barcode/barcode.dart";
import "package:inventree/inventree/part.dart"; import "package:inventree/inventree/part.dart";
import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/company.dart";
import "package:inventree/widget/parameter_widget.dart";
import "package:inventree/widget/progress.dart"; import "package:inventree/widget/progress.dart";
import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/refreshable_state.dart";
@@ -35,6 +39,9 @@ class _SupplierPartDisplayState
extends RefreshableState<SupplierPartDetailWidget> { extends RefreshableState<SupplierPartDetailWidget> {
_SupplierPartDisplayState(); _SupplierPartDisplayState();
int parameterCount = 0;
int attachmentCount = 0;
@override @override
String getAppBarTitle() => L10().supplierPart; String getAppBarTitle() => L10().supplierPart;
@@ -97,7 +104,34 @@ class _SupplierPartDisplayState
if (!result) { if (!result) {
Navigator.of(context).pop(); Navigator.of(context).pop();
return;
} }
InvenTreeParameter()
.countParameters(
InvenTreeSupplierPart.MODEL_TYPE,
widget.supplierPart.pk,
)
.then((value) {
if (mounted) {
setState(() {
parameterCount = value;
});
}
});
InvenTreeAttachment()
.countAttachments(
InvenTreeSupplierPart.MODEL_TYPE,
widget.supplierPart.pk,
)
.then((value) {
if (mounted) {
setState(() {
attachmentCount = value;
});
}
});
} }
/* /*
@@ -286,6 +320,31 @@ class _SupplierPartDisplayState
); );
} }
ListTile? parameterTile = ShowParametersItem(
context,
InvenTreeSupplierPart.MODEL_TYPE,
widget.supplierPart.pk,
parameterCount,
widget.supplierPart.canEdit,
);
if (parameterTile != null) {
tiles.add(parameterTile);
}
ListTile? attachmentTile = ShowAttachmentsItem(
context,
InvenTreeSupplierPart.MODEL_TYPE,
widget.supplierPart.pk,
widget.supplierPart.SKU,
attachmentCount,
widget.supplierPart.canEdit,
);
if (attachmentTile != null) {
tiles.add(attachmentTile);
}
return tiles; return tiles;
} }
} }

View File

@@ -8,6 +8,7 @@ import "package:inventree/barcode/barcode.dart";
import "package:inventree/barcode/purchase_order.dart"; import "package:inventree/barcode/purchase_order.dart";
import "package:inventree/helpers.dart"; import "package:inventree/helpers.dart";
import "package:inventree/inventree/attachment.dart"; import "package:inventree/inventree/attachment.dart";
import "package:inventree/inventree/parameter.dart";
import "package:inventree/l10.dart"; import "package:inventree/l10.dart";
import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/model.dart";
@@ -22,6 +23,7 @@ import "package:inventree/widget/order/po_line_list.dart";
import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/attachment_widget.dart";
import "package:inventree/widget/notes_widget.dart"; import "package:inventree/widget/notes_widget.dart";
import "package:inventree/widget/parameter_widget.dart";
import "package:inventree/widget/progress.dart"; import "package:inventree/widget/progress.dart";
import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/refreshable_state.dart";
import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/snacks.dart";
@@ -51,6 +53,7 @@ class _PurchaseOrderDetailState
int completedLines = 0; int completedLines = 0;
int attachmentCount = 0; int attachmentCount = 0;
int parameterCount = 0;
bool showCameraShortcut = true; bool showCameraShortcut = true;
bool supportProjectCodes = false; bool supportProjectCodes = false;
@@ -300,6 +303,16 @@ class _PurchaseOrderDetailState
} }
} }
InvenTreeParameter()
.countParameters(InvenTreePurchaseOrder.MODEL_TYPE, widget.order.pk)
.then((int value) {
if (mounted) {
setState(() {
parameterCount = value;
});
}
});
InvenTreeAttachment() InvenTreeAttachment()
.countAttachments(InvenTreePurchaseOrder.MODEL_TYPE, widget.order.pk) .countAttachments(InvenTreePurchaseOrder.MODEL_TYPE, widget.order.pk)
.then((int value) { .then((int value) {
@@ -570,6 +583,18 @@ class _PurchaseOrderDetailState
), ),
); );
ListTile? parameterTile = ShowParametersItem(
context,
InvenTreePurchaseOrder.MODEL_TYPE,
widget.order.pk,
parameterCount,
widget.order.canEdit,
);
if (parameterTile != null) {
tiles.add(parameterTile);
}
ListTile? attachmentTile = ShowAttachmentsItem( ListTile? attachmentTile = ShowAttachmentsItem(
context, context,
InvenTreePurchaseOrder.MODEL_TYPE, InvenTreePurchaseOrder.MODEL_TYPE,

View File

@@ -5,12 +5,14 @@ import "package:inventree/barcode/barcode.dart";
import "package:inventree/barcode/sales_order.dart"; import "package:inventree/barcode/sales_order.dart";
import "package:inventree/inventree/attachment.dart"; import "package:inventree/inventree/attachment.dart";
import "package:inventree/inventree/company.dart"; import "package:inventree/inventree/company.dart";
import "package:inventree/inventree/parameter.dart";
import "package:inventree/inventree/sales_order.dart"; import "package:inventree/inventree/sales_order.dart";
import "package:inventree/preferences.dart"; import "package:inventree/preferences.dart";
import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/link_icon.dart";
import "package:inventree/widget/order/so_extra_line_list.dart"; import "package:inventree/widget/order/so_extra_line_list.dart";
import "package:inventree/widget/order/so_line_list.dart"; import "package:inventree/widget/order/so_line_list.dart";
import "package:inventree/widget/order/so_shipment_list.dart"; import "package:inventree/widget/order/so_shipment_list.dart";
import "package:inventree/widget/parameter_widget.dart";
import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/refreshable_state.dart";
import "package:inventree/l10.dart"; import "package:inventree/l10.dart";
@@ -43,6 +45,7 @@ class _SalesOrderDetailState extends RefreshableState<SalesOrderDetailWidget> {
bool showCameraShortcut = true; bool showCameraShortcut = true;
bool supportsProjectCodes = false; bool supportsProjectCodes = false;
int attachmentCount = 0; int attachmentCount = 0;
int parameterCount = 0;
@override @override
String getAppBarTitle() { String getAppBarTitle() {
@@ -271,6 +274,16 @@ class _SalesOrderDetailState extends RefreshableState<SalesOrderDetailWidget> {
true, true,
); );
InvenTreeParameter()
.countParameters(InvenTreeSalesOrder.MODEL_TYPE, widget.order.pk)
.then((int value) {
if (mounted) {
setState(() {
parameterCount = value;
});
}
});
InvenTreeAttachment() InvenTreeAttachment()
.countAttachments(InvenTreeSalesOrder.MODEL_TYPE, widget.order.pk) .countAttachments(InvenTreeSalesOrder.MODEL_TYPE, widget.order.pk)
.then((int value) { .then((int value) {
@@ -497,6 +510,18 @@ class _SalesOrderDetailState extends RefreshableState<SalesOrderDetailWidget> {
), ),
); );
ListTile? parameterTile = ShowParametersItem(
context,
InvenTreeSalesOrder.MODEL_TYPE,
widget.order.pk,
parameterCount,
widget.order.canEdit,
);
if (parameterTile != null) {
tiles.add(parameterTile);
}
ListTile? attachmentTile = ShowAttachmentsItem( ListTile? attachmentTile = ShowAttachmentsItem(
context, context,
InvenTreeSalesOrder.MODEL_TYPE, InvenTreeSalesOrder.MODEL_TYPE,

View File

@@ -1,8 +1,12 @@
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
import "package:inventree/api.dart";
import "package:inventree/app_colors.dart";
import "package:inventree/inventree/model.dart"; import "package:inventree/inventree/model.dart";
import "package:inventree/inventree/parameter.dart";
import "package:inventree/l10.dart"; import "package:inventree/l10.dart";
import "package:inventree/inventree/part.dart"; import "package:inventree/widget/link_icon.dart";
import "package:inventree/widget/paginator.dart"; import "package:inventree/widget/paginator.dart";
import "package:inventree/widget/progress.dart"; import "package:inventree/widget/progress.dart";
import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/refreshable_state.dart";
@@ -10,16 +14,18 @@ import "package:inventree/widget/refreshable_state.dart";
/* /*
* Widget for displaying a list of parameters associated with a given Part instance * Widget for displaying a list of parameters associated with a given Part instance
*/ */
class PartParameterWidget extends StatefulWidget { class ParameterWidget extends StatefulWidget {
const PartParameterWidget(this.part); const ParameterWidget(this.modelType, this.modelId, this.editable) : super();
final InvenTreePart part; final String modelType;
final int modelId;
final bool editable;
@override @override
_ParameterWidgetState createState() => _ParameterWidgetState(); _ParameterWidgetState createState() => _ParameterWidgetState();
} }
class _ParameterWidgetState extends RefreshableState<PartParameterWidget> { class _ParameterWidgetState extends RefreshableState<ParameterWidget> {
_ParameterWidgetState(); _ParameterWidgetState();
@override @override
@@ -34,9 +40,16 @@ class _ParameterWidgetState extends RefreshableState<PartParameterWidget> {
@override @override
Widget getBody(BuildContext context) { Widget getBody(BuildContext context) {
Map<String, String> filters = {"part": widget.part.pk.toString()}; Map<String, String> filters = {
"model_type": widget.modelType,
"model_id": widget.modelId.toString(),
};
return Column(children: [Expanded(child: PaginatedParameterList(filters))]); return Column(
children: [
Expanded(child: PaginatedParameterList(filters, widget.editable)),
],
);
} }
} }
@@ -44,9 +57,11 @@ class _ParameterWidgetState extends RefreshableState<PartParameterWidget> {
* Widget for displaying a paginated list of Part parameters * Widget for displaying a paginated list of Part parameters
*/ */
class PaginatedParameterList extends PaginatedSearchWidget { class PaginatedParameterList extends PaginatedSearchWidget {
const PaginatedParameterList(Map<String, String> filters) const PaginatedParameterList(Map<String, String> filters, this.editable)
: super(filters: filters); : super(filters: filters);
final bool editable;
@override @override
String get searchTitle => L10().parameters; String get searchTitle => L10().parameters;
@@ -75,7 +90,7 @@ class _PaginatedParameterState
int offset, int offset,
Map<String, String> params, Map<String, String> params,
) async { ) async {
final page = await InvenTreePartParameter().listPaginated( final page = await InvenTreeParameter().listPaginated(
limit, limit,
offset, offset,
filters: params, filters: params,
@@ -84,7 +99,7 @@ class _PaginatedParameterState
return page; return page;
} }
Future<void> editParameter(InvenTreePartParameter parameter) async { Future<void> editParameter(InvenTreeParameter parameter) async {
// Checkbox values are handled separately // Checkbox values are handled separately
if (parameter.is_checkbox) { if (parameter.is_checkbox) {
return; return;
@@ -101,7 +116,7 @@ class _PaginatedParameterState
@override @override
Widget buildItem(BuildContext context, InvenTreeModel model) { Widget buildItem(BuildContext context, InvenTreeModel model) {
InvenTreePartParameter parameter = model as InvenTreePartParameter; InvenTreeParameter parameter = model as InvenTreeParameter;
String title = parameter.name; String title = parameter.name;
@@ -116,7 +131,7 @@ class _PaginatedParameterState
? Switch( ? Switch(
value: parameter.as_bool, value: parameter.as_bool,
onChanged: (bool value) { onChanged: (bool value) {
if (parameter.canEdit) { if (widget.editable) {
showLoadingOverlay(); showLoadingOverlay();
parameter.update(values: {"data": value.toString()}).then(( parameter.update(values: {"data": value.toString()}).then((
value, value,
@@ -131,10 +146,47 @@ class _PaginatedParameterState
onTap: parameter.is_checkbox onTap: parameter.is_checkbox
? null ? null
: () async { : () async {
if (parameter.canEdit) { if (widget.editable) {
editParameter(parameter); editParameter(parameter);
} }
}, },
); );
} }
} }
/*
* Return a ListTile to display parameters for the specified model
*/
ListTile? ShowParametersItem(
BuildContext context,
String modelType,
int modelId,
int parameterCount,
bool editable,
) {
// Note: Currently cannot add parameters from the app,
// So, if there are no parameters, do not show the item
if (parameterCount == 0) {
return null;
}
if (!InvenTreeAPI().supportsModernParameters) {
return null;
}
return ListTile(
title: Text(L10().parameters),
leading: Icon(TablerIcons.list_details, color: COLOR_ACTION),
trailing: LinkIcon(
text: parameterCount > 0 ? parameterCount.toString() : null,
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ParameterWidget(modelType, modelId, editable),
),
);
},
);
}

View File

@@ -5,6 +5,7 @@ import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
import "package:inventree/app_colors.dart"; import "package:inventree/app_colors.dart";
import "package:inventree/barcode/barcode.dart"; import "package:inventree/barcode/barcode.dart";
import "package:inventree/inventree/attachment.dart"; import "package:inventree/inventree/attachment.dart";
import "package:inventree/inventree/parameter.dart";
import "package:inventree/l10.dart"; import "package:inventree/l10.dart";
import "package:inventree/helpers.dart"; import "package:inventree/helpers.dart";
@@ -16,10 +17,10 @@ import "package:inventree/preferences.dart";
import "package:inventree/widget/attachment_widget.dart"; import "package:inventree/widget/attachment_widget.dart";
import "package:inventree/widget/link_icon.dart"; import "package:inventree/widget/link_icon.dart";
import "package:inventree/widget/parameter_widget.dart";
import "package:inventree/widget/part/bom_list.dart"; import "package:inventree/widget/part/bom_list.dart";
import "package:inventree/widget/part/part_list.dart"; import "package:inventree/widget/part/part_list.dart";
import "package:inventree/widget/notes_widget.dart"; import "package:inventree/widget/notes_widget.dart";
import "package:inventree/widget/part/part_parameter_widget.dart";
import "package:inventree/widget/part/part_pricing.dart"; import "package:inventree/widget/part/part_pricing.dart";
import "package:inventree/widget/progress.dart"; import "package:inventree/widget/progress.dart";
import "package:inventree/widget/part/category_display.dart"; import "package:inventree/widget/part/category_display.dart";
@@ -50,13 +51,11 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
InvenTreeStockLocation? defaultLocation; InvenTreeStockLocation? defaultLocation;
int parameterCount = 0;
bool allowLabelPrinting = false; bool allowLabelPrinting = false;
bool showParameters = false;
bool showBom = false; bool showBom = false;
bool showPricing = false; bool showPricing = false;
int parameterCount = 0;
int attachmentCount = 0; int attachmentCount = 0;
int bomCount = 0; int bomCount = 0;
int usedInCount = 0; int usedInCount = 0;
@@ -153,10 +152,6 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
INV_PART_SHOW_PRICING, INV_PART_SHOW_PRICING,
true, true,
); );
showParameters = await InvenTreeSettingsManager().getBool(
INV_PART_SHOW_PARAMETERS,
true,
);
showBom = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_BOM, true); showBom = await InvenTreeSettingsManager().getBool(INV_PART_SHOW_BOM, true);
allowLabelPrinting = await InvenTreeSettingsManager().getBool( allowLabelPrinting = await InvenTreeSettingsManager().getBool(
INV_ENABLE_LABEL_PRINTING, INV_ENABLE_LABEL_PRINTING,
@@ -213,15 +208,30 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
} }
// Request the number of attachments // Request the number of attachments
InvenTreeAttachment() if (api.supportsModernAttachments) {
.countAttachments(InvenTreePart.MODEL_TYPE, part.pk) InvenTreeAttachment()
.then((int value) { .countAttachments(InvenTreePart.MODEL_TYPE, part.pk)
if (mounted) { .then((int value) {
setState(() { if (mounted) {
attachmentCount = value; setState(() {
}); attachmentCount = value;
} });
}); }
});
}
// Request the number of parameters
if (api.supportsModernParameters) {
InvenTreeParameter()
.countParameters(InvenTreePart.MODEL_TYPE, part.pk)
.then((int value) {
if (mounted) {
setState(() {
parameterCount = value;
});
}
});
}
// If show pricing information? // If show pricing information?
if (showPricing) { if (showPricing) {
@@ -599,6 +609,18 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
), ),
); );
ListTile? parameterTile = ShowParametersItem(
context,
InvenTreePart.MODEL_TYPE,
part.pk,
parameterCount,
part.canEdit,
);
if (parameterTile != null) {
tiles.add(parameterTile);
}
ListTile? attachmentTile = ShowAttachmentsItem( ListTile? attachmentTile = ShowAttachmentsItem(
context, context,
InvenTreePart.MODEL_TYPE, InvenTreePart.MODEL_TYPE,
@@ -705,10 +727,6 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
List<Widget> getTabIcons(BuildContext context) { List<Widget> getTabIcons(BuildContext context) {
List<Widget> icons = [Tab(text: L10().details), Tab(text: L10().stock)]; List<Widget> icons = [Tab(text: L10().details), Tab(text: L10().stock)];
if (showParameters) {
icons.add(Tab(text: L10().parameters));
}
return icons; return icons;
} }
@@ -721,11 +739,6 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
), ),
PaginatedStockItemList({"part": part.pk.toString()}), PaginatedStockItemList({"part": part.pk.toString()}),
]; ];
if (showParameters) {
tabs.add(PaginatedParameterList({"part": part.pk.toString()}));
}
return tabs; return tabs;
} }
} }