Skip to content

Commit

Permalink
fixes #239 - Same part in different containers (allows UI to duplicat…
Browse files Browse the repository at this point in the history
…e parts with the same name)
  • Loading branch information
replaysMike committed Mar 13, 2024
1 parent 2bb7e0c commit 860168f
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@
"footprintName": "Footprint Name",
"extensionValue1": "Extension Value 1",
"extensionValue2": "Extension Value 2",
"partId": "Part Id",
"ok": "Ok",
"popup": {
"lowStock": "Quantities below this value will indicate the part is low on stock.",
Expand Down Expand Up @@ -803,7 +804,8 @@
"symbolName": "KiCad Symbol Name",
"footprintName": "KiCad Footprint Name",
"extensionValue1": "Extension Value 1",
"extensionValue2": "Extension Value 2"
"extensionValue2": "Extension Value 2",
"partId": "Part Id"
},
"message": {
"noPartsAdded": "No parts added.",
Expand Down
4 changes: 4 additions & 0 deletions Binner/Binner.Web/ClientApp/src/components/PartsGrid2.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,8 @@

.MuiSwitch-root:hover {
scale: 0.9 !important;
}

.Mui-TableHeadCell-Content-Labels .Mui-TableHeadCell-Content-Wrapper {
padding-right: 2px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ export default function PartsGrid2Memoized(props) {
switch (columnName) {
case "partNumber":
return 180;
case "partId":
return 180;
case "quantity":
return 140;
case "lowStockThreshold":
Expand Down Expand Up @@ -268,6 +270,8 @@ export default function PartsGrid2Memoized(props) {
switch(columnName){
case 'partNumber':
return {...def, Cell: ({row}) => (<span><Clipboard text={row.original.partNumber} /> <span className="text-highlight">{row.original.partNumber}</span></span>)};
case 'partId':
return { ...def, Cell: ({ row }) => (<span><Clipboard text={row.original.partId.toString()} /> <span className="text-highlight">{row.original.partId}</span></span>) };
case 'manufacturerPartNumber':
return {...def, Cell: ({row}) => (<span><Clipboard text={row.original[columnName]} /> {row.original[columnName]}</span>)};
case 'description':
Expand Down Expand Up @@ -489,7 +493,7 @@ PartsGrid2Memoized.propTypes = {

PartsGrid2Memoized.defaultProps = {
loading: true,
columns: "partNumber,quantity,lowStockThreshold,manufacturerPartNumber,description,partType,packageType,mountingType,location,binNumber,binNumber2,cost,digikeyPartNumber,mouserPartNumber,arrowPartNumber,datasheetUrl,print,delete,symbolName,footprintName,extensionValue1,extensionValue2",
columns: "partNumber,partId,quantity,lowStockThreshold,manufacturerPartNumber,description,partType,packageType,mountingType,location,binNumber,binNumber2,cost,digikeyPartNumber,mouserPartNumber,arrowPartNumber,datasheetUrl,print,delete,symbolName,footprintName,extensionValue1,extensionValue2",
defaultVisibleColumns: "partNumber,quantity,manufacturerPartNumber,description,partType,location,binNumber,binNumber2,cost,datasheetUrl,print,delete",
page: 1,
totalPages: 1,
Expand Down
32 changes: 24 additions & 8 deletions Binner/Binner.Web/ClientApp/src/pages/Inventory.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,16 @@ export function Inventory(props) {
partTypesRef.current = partTypes;

useEffect(() => {
const partNumberStr = props.params.partNumber;
const partNumberRaw = props.params.partNumber;
let partNumberStr = partNumberRaw?.trim();
let partId = 0;
if (partNumberRaw?.includes(':')) {
const parts = partNumberRaw.split(':');
if (parts.length >= 1)
partNumberStr = parts[0].trim();
if (parts.length >= 2)
partId = parseInt(parts[1].trim());
}
const newIsEditing = partNumberStr?.length > 0;
setIsEditing(newIsEditing);
const fetchData = async () => {
Expand All @@ -143,7 +152,7 @@ export function Inventory(props) {
await fetchPartTypes();
await fetchRecentRows();
if (partNumberStr) {
var loadedPart = await fetchPart(partNumberStr);
var loadedPart = await fetchPart(partNumberStr, partId);
if (newIsEditing) setInputPartNumber(partNumberStr);
setInputPartNumber(partNumberStr);
await fetchPartMetadataAndInventory(partNumberStr, loadedPart || part);
Expand Down Expand Up @@ -528,12 +537,16 @@ export function Inventory(props) {
setPart(part);
};

const fetchPart = async (partNumber) => {
const fetchPart = async (partNumber, partId) => {
Inventory.partAbortController.abort();
Inventory.partAbortController = new AbortController();
setLoadingPart(true);
try {
const response = await fetchApi(`api/part?partNumber=${encodeURIComponent(partNumber.trim())}`, {
let query = `partNumber=${encodeURIComponent(partNumber.trim())}`;
const validPartId = typeof partId === "number" ? partId : partId && parseInt(partId.trim());
if (validPartId > 0)
query += `&partId=${partId}`;
const response = await fetchApi(`api/part?${query}`, {
signal: Inventory.partAbortController.signal
});
const { data } = response;
Expand Down Expand Up @@ -851,7 +864,7 @@ export function Inventory(props) {
e.stopPropagation();
if (systemSettings.printer.printMode === 0) {
// direct print
await fetchApi(`api/part/print?partNumber=${encodeURIComponent(part.partNumber.trim())}&generateImageOnly=false`, { method: "POST" });
await fetchApi(`api/part/print?partNumber=${encodeURIComponent(part.partNumber.trim())}&partId=${part.partId}&generateImageOnly=false`, { method: "POST" });
} else {
window.print();
}
Expand Down Expand Up @@ -881,8 +894,11 @@ export function Inventory(props) {

const handleRecentPartClick = async (e, part) => {
setPart(part);
props.history(`/inventory/${encodeURIComponent(part.partNumber)}`);
await fetchPart(part.partNumber);
if (part.partId)
props.history(`/inventory/${encodeURIComponent(part.partNumber)}:${part.partId}`);
else
props.history(`/inventory/${encodeURIComponent(part.partNumber)}`);
await fetchPart(part.partNumber, part.partId);
};

const handleSaveScannedParts = async (e, scannedParts) => {
Expand Down Expand Up @@ -1477,7 +1493,7 @@ export function Inventory(props) {
<Breadcrumb.Divider />
<Breadcrumb.Section active>{isEditing ? part.partNumber : t('page.inventory.addtitle', "Add Inventory")}</Breadcrumb.Section>
</Breadcrumb>
{part.partNumber && <Image src={`api/part/preview?partNumber=${encodeURIComponent(part.partNumber.trim())}&token=${getImagesToken()}`} id="printarea" width={180} floated="right" style={{ marginTop: "0px" }} />}
{part.partNumber && <Image src={`api/part/preview?partNumber=${encodeURIComponent(part.partNumber.trim())}&partId=${part.partId}&token=${getImagesToken()}`} id="printarea" width={180} floated="right" style={{ marginTop: "0px" }} />}
<div style={{ display: 'flex' }}>
<FormHeader name={title} to=".." />
{!isEditing &&
Expand Down
5 changes: 4 additions & 1 deletion Binner/Binner.Web/ClientApp/src/pages/LowInventory.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ export function LowInventory (props) {
};

const handlePartClick = (e, part) => {
props.history(`/inventory/${encodeURIComponent(part.partNumber)}`);
if (part.partId)
props.history(`/inventory/${encodeURIComponent(part.partNumber)}:${part.partId}`);
else
props.history(`/inventory/${encodeURIComponent(part.partNumber)}`);
};

const removeFilter = (e, filterName, filterValue) => {
Expand Down
5 changes: 4 additions & 1 deletion Binner/Binner.Web/ClientApp/src/pages/Search.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,10 @@ export function Search(props) {
}, [filterBy, filterByValue, keyword]);

const handlePartClick = (e, part) => {
props.history(`/inventory/${encodeURIComponent(part.partNumber)}`);
if (part.partId)
props.history(`/inventory/${encodeURIComponent(part.partNumber)}:${part.partId}`);
else
props.history(`/inventory/${encodeURIComponent(part.partNumber)}`);
};

const handleNextPage = async (e, page) => {
Expand Down
8 changes: 4 additions & 4 deletions Binner/Binner.Web/Controllers/PartController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public async Task<IActionResult> GetAsync([FromQuery] GetPartRequest request)
{
if (string.IsNullOrEmpty(request.PartNumber))
return BadRequest($"No part number specified!");
var response = await _partService.GetPartWithStoredFilesAsync(request.PartNumber);
var response = await _partService.GetPartWithStoredFilesAsync(request);
if (response.Part == null) return NotFound();
var partResponse = Mapper.Map<Part, PartStoredFilesResponse>(response.Part);
partResponse.StoredFiles = response.StoredFiles;
Expand Down Expand Up @@ -335,7 +335,7 @@ public async Task<IActionResult> SearchAsync([FromQuery] string keywords, [FromQ
if (exactMatch)
{
// search by exact part name match
var part = await _partService.GetPartAsync(keywords);
var part = await _partService.GetPartAsync(new GetPartRequest { PartNumber = keywords });
if (part == null) return NotFound();

var partTypes = await _partService.GetPartTypesAsync();
Expand Down Expand Up @@ -599,7 +599,7 @@ public async Task<IActionResult> PrintPartAsync([FromQuery] PrintPartRequest req
try
{
if (string.IsNullOrEmpty(request.PartNumber)) return BadRequest("No part number specified.");
var part = await _partService.GetPartAsync(request.PartNumber);
var part = await _partService.GetPartAsync(new GetPartRequest { PartNumber = request.PartNumber, PartId = request.PartId });
if (part == null) return NotFound();

if (await _printService.HasPartLabelTemplateAsync())
Expand Down Expand Up @@ -651,7 +651,7 @@ public async Task<IActionResult> PreviewPrintPartAsync([FromQuery] PrintPartRequ
System.Threading.Thread.CurrentPrincipal = new TokenPrincipal(userContext, request.Token);

if (string.IsNullOrEmpty(request.PartNumber)) return BadRequest("No part number specified.");
var part = await _partService.GetPartAsync(request.PartNumber);
var part = await _partService.GetPartAsync(new GetPartRequest { PartNumber = request.PartNumber, PartId = request.PartId });

var stream = new MemoryStream();
if (await _printService.HasPartLabelTemplateAsync())
Expand Down
8 changes: 4 additions & 4 deletions Binner/Library/Binner.Common/Services/IPartService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,16 @@ public interface IPartService
/// <summary>
/// Get a part by part number
/// </summary>
/// <param name="partNumber"></param>
/// <param name="request"></param>
/// <returns></returns>
Task<Part?> GetPartAsync(string partNumber);
Task<Part?> GetPartAsync(GetPartRequest request);

/// <summary>
/// Get a part with its associated stored files
/// </summary>
/// <param name="partNumber"></param>
/// <param name="request"></param>
/// <returns></returns>
Task<(Part? Part, ICollection<StoredFile> StoredFiles)> GetPartWithStoredFilesAsync(string partNumber);
Task<(Part? Part, ICollection<StoredFile> StoredFiles)> GetPartWithStoredFilesAsync(GetPartRequest request);

/// <summary>
/// Get all parts
Expand Down
13 changes: 8 additions & 5 deletions Binner/Library/Binner.Common/Services/PartService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,18 @@ public async Task<PaginatedResponse<Part>> GetLowStockAsync(PaginatedRequest req
return await _storageProvider.GetLowStockAsync(request, _requestContext.GetUserContext());
}

public async Task<Part?> GetPartAsync(string partNumber)
public async Task<Part?> GetPartAsync(GetPartRequest request)
{
return await _storageProvider.GetPartAsync(partNumber, _requestContext.GetUserContext());
if (request.PartId > 0)
return await _storageProvider.GetPartAsync(request.PartId, _requestContext.GetUserContext());
else
return await _storageProvider.GetPartAsync(request.PartNumber ?? string.Empty, _requestContext.GetUserContext());
}

public async Task<(Part? Part, ICollection<StoredFile> StoredFiles)> GetPartWithStoredFilesAsync(string partNumber)
public async Task<(Part? Part, ICollection<StoredFile> StoredFiles)> GetPartWithStoredFilesAsync(GetPartRequest request)
{
var userContext = _requestContext.GetUserContext();
var partEntity = await _storageProvider.GetPartAsync(partNumber, userContext);
var partEntity = await GetPartAsync(request);
var storedFiles = new List<StoredFile>();
if (partEntity != null)
{
Expand Down Expand Up @@ -1082,7 +1085,7 @@ private CommonPart MouserOrderLineToCommonPart(OrderHistoryLine? orderLine, stri
var datasheetUrls = new List<NameValuePair<DatasheetSource>>();

// fetch part if it's in inventory
var inventoryPart = await GetPartAsync(partNumber);
var inventoryPart = await GetPartAsync(new GetPartRequest { PartNumber = partNumber });
if (inventoryPart != null && !string.IsNullOrEmpty(inventoryPart.DatasheetUrl))
datasheetUrls.Add(new NameValuePair<DatasheetSource>(inventoryPart.ManufacturerPartNumber ?? string.Empty, new DatasheetSource($"https://{_configuration.ResourceSource}/{MissingDatasheetCoverName}", inventoryPart.DatasheetUrl, inventoryPart.ManufacturerPartNumber ?? string.Empty, inventoryPart.Description ?? string.Empty, inventoryPart.Manufacturer ?? string.Empty)));
if (inventoryPart != null)
Expand Down
5 changes: 5 additions & 0 deletions Binner/Library/Binner.Model/Requests/GetPartRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@ public class GetPartRequest
/// The main part number
/// </summary>
public string? PartNumber { get; set; }

/// <summary>
/// Optional part id
/// </summary>
public long PartId { get; set; }
}
}
7 changes: 6 additions & 1 deletion Binner/Library/Binner.Model/Requests/PrintPartRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ public class PrintPartRequest : IImagesToken
/// The main part number
/// </summary>
public string? PartNumber { get; set; }


/// <summary>
/// Optional part id
/// </summary>
public long PartId { get; set; }

/// <summary>
/// True to generate image only
/// </summary>
Expand Down

0 comments on commit 860168f

Please sign in to comment.