Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions Binner/Binner.Web/ClientApp/src/pages/Inventory.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ export function Inventory({ partNumber = "", ...rest }) {
const [confirmReImport, setConfirmReImport] = useState(false);
const [confirmReImportAction, setConfirmReImportAction] = useState(null);

// check if we are on the add page
const onAddPage = location.pathname === "/inventory/add";

let blocker = useBlocker(
({ currentLocation, nextLocation }) =>
isDirty && currentLocation.pathname !== nextLocation.pathname
Expand Down Expand Up @@ -243,8 +246,8 @@ export function Inventory({ partNumber = "", ...rest }) {
setLoadingPartMetadata(false);
} else if (rest.params.partNumberToAdd) {
// a part number to add is specified in the URL path
const { data } = await doFetchPartMetadata(rest.params.partNumberToAdd, partToSearch, false);
processPartMetadataResponse(data, partToSearch.storedFiles, true, true);
const { data, responseCode } = await doFetchPartMetadata(rest.params.partNumberToAdd, partToSearch, false, onAddPage);
processPartMetadataResponse(data, partToSearch.storedFiles, true, true, responseCode);
setLoadingPartMetadata(false);
setIsDirty(true);
} else {
Expand All @@ -254,8 +257,8 @@ export function Inventory({ partNumber = "", ...rest }) {
} else {
// fetch part metadata, don't allow overwriting of fields that have already been entered
setLoadingPartMetadata(true);
const { data } = await doFetchPartMetadata(targetPart.partNumber, partToSearch, false);
processPartMetadataResponse(data, partToSearch.storedFiles, true, false); // false, don't overwrite entered fields
const { data, responseCode } = await doFetchPartMetadata(targetPart.partNumber, partToSearch, false, onAddPage);
processPartMetadataResponse(data, partToSearch.storedFiles, true, false, responseCode); // false, don't overwrite entered fields
setLoadingPartMetadata(false);
setIsDirty(true);
}
Expand Down Expand Up @@ -296,7 +299,7 @@ export function Inventory({ partNumber = "", ...rest }) {
setPartMetadataErrors([]);
try {
const includeInventorySearch = !pageHasParameters;
const { data, existsInInventory, inventoryPart } = await doFetchPartMetadata(input, localPart, includeInventorySearch);
const { data, existsInInventory, inventoryPart, responseCode } = await doFetchPartMetadata(input, localPart, includeInventorySearch, onAddPage);
if (existsInInventory) {
setPartExistsInInventory(true);
setSuggestedPartNumber(inventoryPart);
Expand All @@ -305,7 +308,7 @@ export function Inventory({ partNumber = "", ...rest }) {
setSuggestedPartNumber(null);
}

processPartMetadataResponse(data, localPart.storedFiles, !pageHasParameters, true);
processPartMetadataResponse(data, localPart.storedFiles, !pageHasParameters, true, responseCode);
setLoadingPartMetadata(false);
return { part: localPart, exists: existsInInventory };
} catch (ex) {
Expand Down Expand Up @@ -466,7 +469,7 @@ export function Inventory({ partNumber = "", ...rest }) {
return entity;
}, []);

const processPartMetadataResponse = useCallback((data, storedFiles, allowSetFromMetadata, allowOverwrite) => {
const processPartMetadataResponse = useCallback((data, storedFiles, allowSetFromMetadata, allowOverwrite, responseCode) => {
// cancelled or auth required
if (!data) {
setLoadingPartMetadata(false);
Expand All @@ -488,7 +491,7 @@ export function Inventory({ partNumber = "", ...rest }) {
if (allowSetFromMetadata) {
updatedPart = setPartFromMetadata(metadataParts, { ...suggestedPart, quantity: -1 }, allowOverwrite);
}
} else {
} else if (responseCode !== 204) {
// no part metadata available
setPartMetadataIsSubscribed(true);
}
Expand All @@ -509,13 +512,13 @@ export function Inventory({ partNumber = "", ...rest }) {
* @param {bool} includeInventorySearch true to also check local inventory for the part
* @returns part information
*/
const doFetchPartMetadata = async (partNumber, part, includeInventorySearch = true) => {
const doFetchPartMetadata = async (partNumber, part, includeInventorySearch = true, newPart = true) => {
if (partTypesRef.current.length === 0)
console.error("There are no partTypes! This shouldn't happen and is a bug.");
Inventory.doFetchPartMetadataController?.abort();
Inventory.doFetchPartMetadataController = new AbortController();
try {
const response = await fetchApi(`/api/part/info?partNumber=${encodeURIComponent(partNumber.trim())}&partTypeId=${part.partTypeId}&mountingTypeId=${part.mountingTypeId}&supplierPartNumbers=digikey:${part.digiKeyPartNumber || ""},mouser:${part.mouserPartNumber || ""},arrow:${part.arrowPartNumber},tme:${part.tmePartNumber},element14:${part.element14PartNumber}`, {
const response = await fetchApi(`/api/part/info?newPart=${newPart}&partNumber=${encodeURIComponent(partNumber.trim())}&partTypeId=${part.partTypeId}&mountingTypeId=${part.mountingTypeId}&supplierPartNumbers=digikey:${part.digiKeyPartNumber || ""},mouser:${part.mouserPartNumber || ""},arrow:${part.arrowPartNumber},tme:${part.tmePartNumber},element14:${part.element14PartNumber}`, {
signal: Inventory.doFetchPartMetadataController.signal
});
const data = response.data;
Expand Down Expand Up @@ -545,7 +548,7 @@ export function Inventory({ partNumber = "", ...rest }) {
}

// let caller handle errors
return { data, existsInInventory, inventoryPart: existingInventoryPartNumber };
return { data, existsInInventory, inventoryPart: existingInventoryPartNumber, responseCode: response.responseObject.status };

} catch (ex) {
if (ex?.name === "AbortError") {
Expand Down Expand Up @@ -836,8 +839,8 @@ export function Inventory({ partNumber = "", ...rest }) {

// part is not in inventory, add it as new
setLoadingPartMetadata(true);
const { data } = await doFetchPartMetadata(cleanPartNumber, part, false);
const metaResult = processPartMetadataResponse(data, part.storedFiles, true, true);
const { data, responseCode} = await doFetchPartMetadata(cleanPartNumber, part, false, onAddPage);
const metaResult = processPartMetadataResponse(data, part.storedFiles, true, true, responseCode);
setLoadingPartMetadata(false);
setIsDirty(true);

Expand Down Expand Up @@ -1453,8 +1456,8 @@ export function Inventory({ partNumber = "", ...rest }) {
e.stopPropagation();
setLoadingPartMetadata(true);
setConfirmRefreshPartIsOpen(false);
const { data } = await doFetchPartMetadata(inputPartNumber, part, false);
processPartMetadataResponse(data, part.storedFiles, true, true);
const { data, responseCode } = await doFetchPartMetadata(inputPartNumber, part, false, true);
processPartMetadataResponse(data, part.storedFiles, true, true, responseCode);
setLoadingPartMetadata(false);
setIsDirty(true);
if (confirmRefreshPartDoNotAskAgain) {
Expand Down
27 changes: 25 additions & 2 deletions Binner/Binner.Web/ClientApp/src/pages/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export const Settings = () => {
enableAutoPartSearch: true,
enableDarkMode: false,
enableCheckNewVersion: true,
enableAutomaticMetadataFetchingForExistingParts: true,
});
const [integrationSettings, setIntegrationSettings] = useState({
binner: {
Expand Down Expand Up @@ -200,10 +201,10 @@ export const Settings = () => {
const { data } = response;
setLoading(false);
// break out data into multiple state variables to optimize render performance
const { licenseKey, maxCacheItems, cacheAbsoluteExpirationMinutes, cacheSlidingExpirationMinutes, enableAutoPartSearch, enableDarkMode, enableCheckNewVersion } = data;
const { licenseKey, maxCacheItems, cacheAbsoluteExpirationMinutes, cacheSlidingExpirationMinutes, enableAutoPartSearch, enableDarkMode, enableCheckNewVersion, enableAutomaticMetadataFetchingForExistingParts } = data;
const language = data.locale.language;
const currency = data.locale.currency;
setGlobalSettings({ licenseKey, language, currency, maxCacheItems, cacheAbsoluteExpirationMinutes, cacheSlidingExpirationMinutes, enableAutoPartSearch, enableDarkMode, enableCheckNewVersion });
setGlobalSettings({ licenseKey, language, currency, maxCacheItems, cacheAbsoluteExpirationMinutes, cacheSlidingExpirationMinutes, enableAutoPartSearch, enableDarkMode, enableCheckNewVersion, enableAutomaticMetadataFetchingForExistingParts });
const { binner, digikey, mouser, arrow, octopart, tme, element14 } = data;
setIntegrationSettings({ binner, digikey, mouser, arrow, octopart, tme, element14 });
setPrinterSettings({ printer: data.printer });
Expand Down Expand Up @@ -895,6 +896,28 @@ export const Settings = () => {
}
/>
</Form.Field>

<Form.Field>
<label>{t('page.settings.enableAutomaticMetadataFetchingForExistingParts', "Enable automatic updating of metadata using the APIs for existing parts")}</label>
<Popup
wide
position="top left"
offset={[0, 20]}
hoverable
content={<Trans i18nKey="page.settings.popup.enableAutomaticMetadataFetchingForExistingParts">
Select this option to enable automatic updating using the part search APIs to fetch metadata for existing parts in your inventory when opening them in the inventory.
</Trans>}
trigger={
<Form.Checkbox
name="enableAutomaticMetadataFetchingForExistingParts"
type="checkbox"
toggle
checked={globalSettings.enableAutomaticMetadataFetchingForExistingParts}
onChange={(e, control) => handleChange(e, control, 'global')}
/>
}
/>
</Form.Field>
</Segment>

</Segment>);
Expand Down
12 changes: 11 additions & 1 deletion Binner/Binner.Web/Controllers/PartController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -639,8 +639,18 @@ public async Task<IActionResult> GetLowStockAsync([FromQuery] PaginatedRequest r
/// <param name="supplierPartNumbers">List of supplier part numbers if known, in the format: 'suppliername:partnumber,suppliername2:partnumber'</param>
/// <returns></returns>
[HttpGet("info")]
public async Task<IActionResult> GetPartInfoAsync([FromQuery] string partNumber, [FromQuery] string partTypeId = "", [FromQuery] string mountingTypeId = "", [FromQuery] string supplierPartNumbers = "")
public async Task<IActionResult> GetPartInfoAsync([FromQuery] string partNumber, [FromQuery] string partTypeId = "", [FromQuery] string mountingTypeId = "", [FromQuery] string supplierPartNumbers = "", [FromQuery] bool? newPart = true)
{
// get the organization configuration
var organisationConfig = await _userConfigurationService.GetOrganizationConfigurationAsync();

// check the settings if we need to skip non new part search requests
if (newPart != null && newPart == false && organisationConfig.enableAutomaticMetadataFetchingForExistingParts == false)
{
// check if we should skip this request
return StatusCode(StatusCodes.Status204NoContent);
}

try
{
var partType = partTypeId;
Expand Down
2 changes: 2 additions & 0 deletions Binner/Binner.Web/Controllers/PartTypeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
using System.Linq;
using System.Net.Mime;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication.JwtBearer;

namespace Binner.Web.Controllers
{
Expand Down
Loading