Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Releases/v2.6.0 #216

Merged
merged 11 commits into from
Jun 27, 2023
Merged
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
1,308 changes: 759 additions & 549 deletions Binner/Binner.Web/ClientApp/public/locales/de/translation.json

Large diffs are not rendered by default.

112 changes: 99 additions & 13 deletions Binner/Binner.Web/ClientApp/public/locales/it/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@
"deleteLocalFile": "Cancellare questo file locale",
"technicalSpecs": "Visualizzare specifiche tecniche",
"compliance": "Visualizzare le informazioni di conformità",
"cadModels": "Visualizzare i modelli CAD disponibili per questo componente"
"cadModels": "Visualizzare i modelli CAD disponibili per questo componente",
"symbolName": "Associare un nome di simbolo KiCad a questo componente",
"footprintName": "Associare un nome di impronta KiCad a questo componente",
"extensionValue": "Associare un valore personalizzato a questo componente"
}
},
"lowInventory": {
Expand All @@ -88,8 +91,8 @@
"notEnoughPartsToProducePcb": "Non ci sono componenti sufficienti per produrre questo PCB.",
"notEnoughPartsToProduceBom": "Non ci sono componenti sufficienti per produrre l'intera DBA.",
"noPartsAssigned": "Assegnare i componenti per contare quante volte puoi produrre questo PCB.",
"pcbProduceCount": "Con le attuali disponibilità in inventario si può produrre questo PCB <b>{{count}}</b> volte.",
"bomProduceCount": "Con le attuali disponibilità in inventario si può produrre l'intera DBA <b>{{count}}</b> volte.",
"pcbProduceCount": "Con le attuali disponibilità in inventario si può produrre questo PCB <1>{{count}}</1> volte.",
"bomProduceCount": "Con le attuali disponibilità in inventario si può produrre l'intera DBA <1>{{count}}</1> volte.",
"lowestPcb": "<i>{{name}}</i> manda componenti in sottoscorta."
},
"boms": {
Expand All @@ -101,8 +104,9 @@
"title": "Categorie",
"description": "Le categorie e le sottocategorie sono utilizzate per organizzare i componenti in modo logico e ordinato. Non c'è limite al numero di livelli nella gerarchia, basta collegare alla categoria <1>Parent</1> la sottocategoria voluta.<3 />Ad esempio: gli amplificatori operazionali possono essere un sottotipo dei Circuiti Integrati, quindi il <1>Parent</1> degli amplificatori operazionali è la categoria Circuiti Integrati.",
"rename": "Rinominare Categoria",
"edit": "Modificare Categoria",
"partCount": "Il numero di componenti in questa categoria",
"viewParts": "Vedi Compoonenti"
"viewParts": "Vedi Componenti"
},
"exportData": {
"title": "Importare/Esportare",
Expand All @@ -113,7 +117,7 @@
"totalRowsImported": "Righe totali importate",
"totalProjectsImported": "Progetti importati",
"totalPartTypesImported": "Categorie importate",
"totalPartsImported": "Compoonenti importati",
"totalPartsImported": "Componenti importati",
"noFilesSelected": "Nessun file selezionato per il caricamento!",
"importUploadFailed": "Importazione non riuscita!",
"importFailed": "Impossibile importare i dati.",
Expand Down Expand Up @@ -237,7 +241,9 @@
"orderNum": "Order Number",
"instructions": "Per gli ordini <1>DigiKey</1>, questo è il <3>Sales Order #</3>.<4 />Per glii ordini <6>Mouser</6>, questo è il <8>Web Order #</8>.<10 />Per gli ordini <12>Arrow</12>, questo è l'<14>Order Number</14>.",
"mouserNote": "<0>Nota:</0> Mouser supporta soltanto Web Order # quindi quando si importa assicurarsi di utilizzare il Web Order # e <2>non il Sales Order #</2>",
"arrowNote": "<0>Note:</0> Arrow richiede che sia richiesto via email l'accesso al loro Order API. Vedi <2>Arrow Order Api</2>"
"arrowNote": "<0>Note:</0> Arrow richiede che sia richiesto via email l'accesso al loro Order API. Vedi <2>Arrow Order Api</2>",
"addedToInventory": "aggiunto all'inventario",
"alreadyInInventory": "già presente in inventario"
},
"printLabels": {
"title": "Stampa Etichette",
Expand Down Expand Up @@ -371,14 +377,64 @@
"totalPartTypes": "N.Totale Categorie",
"totalUserFiles": "N.Totale Files Utente",
"userFilesSize": "Dimensione Files Utente"
}
},
"backupRestore": {
"title": "Backup/Restore",
"baseDescription": "Backup o ripristino dell'installazione di Binner."
}
},
"backup": {
"title": "Backup / Restore",
"baseDescription": "Backup o ripristino dell'installazione di Binner.",
"description": "Creare un backup o ripristinare da un precedente backup.",
"acceptedFileTypes": "Tipi di file accettati: \"*.bak\"",
"backupDescription": "Creare una istantanea dell'installazione di Binner."
},
"printing": {
"title": "Stampa",
"description": "Stampa etichette e modelli di etichette.",
"header": "Scegliere una attività",
"labelTemplates": {
"title": "Modelli di etichette",
"description": "Modificare le etichette dei componenti e i modelli di etichette personalizzate.",
"baseDescription": "Creare e modificare modelli di etichette.",
"barcodeLabels": "Etichette con codici a barre",
"custom": "Testo personalizzato",
"preview": "Anteprima",
"labelEditor": "Editor di etichette",
"manage": "Gestire",
"zoomLevel": "Livello di ingrandimento",
"labelProperties": "Proprietà dell'etichetta",
"labelTemplate": "Modello etichetta",
"width": "Larghezza",
"height": "Altezza",
"dpi": "Dpi",
"margin": "Margine",
"templateName": "Nome modello",
"itemProperties": "Proprietà dell'elemento",
"align": "Allineamento",
"font": "Font",
"rotate": "Ruotare",
"fontSize": "Dimensione del Font",
"fontWeight": "Spessore del Font",
"color": "Colore",
"length": "Lunghezza",
"textBarcodeValue": "Valore del Testo/Barcode",
"partInformation": "Dati del componente",
"button": {
"print": "Stampare",
"load": "Caricare..."
}
},
"printLabels": {
"title": "Stampa Etichette Personalizzate",
"baseDescription": "Stampa etichette personalizzate per qualsiasi attività."
},
"bulkprint": {
"title": "Stampa massiva",
"description": "Stampa etichette per più componenti contemporaneamente.",
"baseDescription": "Stampa massiva etichette per componenti"
}
}
},
"bc": {
Expand All @@ -398,7 +454,12 @@
"backupRestore": "Backup / Restore",
"accountSettings": "Dati Utente",
"activateLicense": "Attivare Licenza",
"systemInfo": "Informazioni di Sistema"
"systemInfo": "Informazioni di Sistema",
"barcodeScanner": "Barcode Scanner",
"printing": "Stampa",
"labelTemplates": "Modelli di Etichette",
"bulkPrint": "Stampa massiva",
"inventory": "Inventario"
},
"comp": {
"navBar": {
Expand Down Expand Up @@ -439,6 +500,10 @@
"arrowPartNumber": "Arrow Part Number",
"packageType": "Tipo di package",
"mountingType": "Tipo montaggio",
"symbolName": "Nome Simbolo",
"footprintName": "Nome Impronta",
"extensionValue1": "Valore aggiuntivo 1",
"extensionValue2": "Valore aggiuntivo 2",
"ok": "Ok",
"popup": {
"lowStock": "Se la disponibilità del componente è inferiore a questo valore il componente sarà considerato sottoscorta.",
Expand Down Expand Up @@ -554,7 +619,19 @@
"duplicatePartModal": {
"title": "Componente Duplicato",
"description": "C'è già un possibile componente duplicato nel tuo inventario."
}
},
"labelSelectionModal": {
"title": "Editor di Etichette",
"header": "Selezionare Etichetta",
"description": "Selezionare una etichetta esistente per modificarla o crearne una nuova.",
"chooseLabel": "Scegliere l'etichetta da modificare",
"createNewLabel": "Creare una nuova etichetta..."
},
"labelSetNameModal": {
"description": "Indicare un nome per la nuova etichetta.",
"labelName": "Nome etichetta",
"makeDefault": "Rendere questa l'etichetta di default?"
}
},
"button": {
"addBomProject": "Aggiungi un Progetto DBA",
Expand Down Expand Up @@ -603,7 +680,9 @@
"specs": "Specifiche",
"compliance": "Conformità",
"cadModels": "Modelli CAD",
"addAnyway": "Aggiungere comunque"
"addAnyway": "Aggiungere comunque",
"move": "Spostare",
"select": "Selezionare"
},
"label": {
"name": "Nome",
Expand Down Expand Up @@ -718,7 +797,11 @@
"allowLogin": "Consentire Accesso",
"active": "Attivo",
"inactive": "Inattivo",
"rowsPerPage": "Righe per pagina"
"rowsPerPage": "Righe per pagina",
"symbolName": "Nome Simbolo KiCad",
"footprintName": "Nome Impronta KiCad",
"extensionValue1": "Valore Aggiuntivo 1",
"extensionValue2": "Valore Aggiuntivo 2"
},
"message": {
"noPartsAdded": "Nessun componente aggiunto.",
Expand Down Expand Up @@ -819,8 +902,11 @@
"editSchematicReferenceId": "Modifica l' <1 />Id(s) di riferimento nello schema usato per identificare il componente sulla serigrafia del PCB. <3 />Ad esempio: <5>D1</5>, <7>C2</7>, <9>Q1</9>",
"customDescription": "Fornire una descrizione personale",
"customNote": "Fornire una nota personale",
"produceHistory": "Visualizza cronologia di produzione"
}
"produceHistory": "Visualizza cronologia di produzione",
"movePart": "Spostare i componenti selezionati in un altro tab"
},
"makerSubscriptionRequired": "Richiede un abbonamento di livello Maker. <1>Clicca qui</1> per dettagli.",
"proSubscriptionRequired": "Richiede un abbonamento di livello Professional. <1>Clicca qui</1> per dettagli."
},
"footer": {
"version": "Version",
Expand Down
33 changes: 33 additions & 0 deletions Binner/Binner.Web/ClientApp/src/common/applicationSettings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { fetchApi } from "./fetchApi";
import _ from "underscore";

let GLOBAL_APPSETTINGS = {};

/**
* Get the system settings (cached)
* @returns the system settings
*/
export const getSystemSettings = async (force) => {
if (force || _.isEmpty(GLOBAL_APPSETTINGS)) {
return await fetchApi("api/system/settings", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
}).then((response) => {
const { data } = response;
GLOBAL_APPSETTINGS = data;
return GLOBAL_APPSETTINGS;
});
} else {
return GLOBAL_APPSETTINGS;
}
};

/**
* Set/update the system settings
* @param {object} applicationSettings the system settings
*/
export const setSystemSettings = (applicationSettings) => {
GLOBAL_APPSETTINGS = applicationSettings;
};
22 changes: 20 additions & 2 deletions Binner/Binner.Web/ClientApp/src/common/currency.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,25 @@ export const Currencies = [
{ key: 3, text: getCurrencySymbol("JPY"), value: "JPY", description: "Japanese yen" },
{ key: 4, text: getCurrencySymbol("GBP"), value: "GBP", description: "Pound sterling" },
{ key: 5, text: getCurrencySymbol("AUD"), value: "AUD", description: "Australian dollar" },
{ key: 6, text: getCurrencySymbol("CAD"), value: "CNY", description: "Renminbi" },
{ key: 6, text: getCurrencySymbol("CNY"), value: "CNY", description: "Chinese Yuan (Renminbi)" },
{ key: 7, text: getCurrencySymbol("KRW"), value: "KRW", description: "South Korean won" },
{ key: 8, text: getCurrencySymbol("MXN"), value: "MXN", description: "Mexican peso" }
{ key: 8, text: getCurrencySymbol("MXN"), value: "MXN", description: "Mexican peso" },
{ key: 9, text: getCurrencySymbol("HKD"), value: "HKD", description: "Hong Kong dollar" },
{ key: 10, text: getCurrencySymbol("SGD"), value: "SGD", description: "Singapore dollar" },
{ key: 11, text: getCurrencySymbol("TWD"), value: "TWD", description: "New Taiwan dollar" },
{ key: 12, text: getCurrencySymbol("NZD"), value: "NZD", description: "New Zealand dollar" },
{ key: 13, text: getCurrencySymbol("INR"), value: "INR", description: "Indian Rupee" },
{ key: 14, text: getCurrencySymbol("DKK"), value: "DKK", description: "Danish krone" },
{ key: 15, text: getCurrencySymbol("NOK"), value: "NOK", description: "Norwegian krone" },
{ key: 16, text: getCurrencySymbol("SEK"), value: "SEK", description: "Swedish krona" },
{ key: 17, text: getCurrencySymbol("ILS"), value: "ILS", description: "Israeli new shekel" },
{ key: 18, text: getCurrencySymbol("PLN"), value: "PLN", description: "Polish Zloty" },
{ key: 19, text: getCurrencySymbol("CHF"), value: "CHF", description: "Swiss Franc" },
{ key: 20, text: getCurrencySymbol("CZK"), value: "CZK", description: "Czech Koruna" },
{ key: 21, text: getCurrencySymbol("HUF"), value: "HUF", description: "Hungarian Forint" },
{ key: 22, text: getCurrencySymbol("RON"), value: "RON", description: "Romanian Leu" },
{ key: 23, text: getCurrencySymbol("ZAR"), value: "ZAR", description: "South African Rand" },
{ key: 24, text: getCurrencySymbol("MYR"), value: "MYR", description: "Malaysian Ringgit" },
{ key: 25, text: getCurrencySymbol("THB"), value: "THB", description: "Thai Baht" },
{ key: 26, text: getCurrencySymbol("PHP"), value: "PHP", description: "Philippine peso" },
];
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function AddBomPartModal(props) {
setLoading(true);

try {
const response = await fetchApi(`api/part/search?keywords=${keyword}`, {
const response = await fetchApi(`api/part/search?keywords=${encodeURIComponent(keyword.trim())}`, {
signal: AddBomPartModal.abortController.signal
}).catch(() => {
setLoading(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function PartSuppliersMemoized({ loadingPartMetadata, part, metadataParts
const [partSupplier, setPartSupplier] = useState(defaultPartSupplier);
const [theMetadataParts, setTheMetadataParts] = useState(metadataParts);
const [showAddPartSupplier, setShowAddPartSupplier] = useState(false);
const [isEditing, setIsEditing] = useState('');

useEffect(() => {
setIsLoadingPartMetadata(loadingPartMetadata);
Expand Down Expand Up @@ -92,6 +93,31 @@ export function PartSuppliersMemoized({ loadingPartMetadata, part, metadataParts
setIsLoadingPartMetadata(false);
};

const saveSupplier = async (supplier) => {
const request = {
partId: thePart.partId,
partSupplierId: supplier.partSupplierId,
name: supplier.supplier,
supplierPartNumber: supplier.supplierPartNumber,
cost: parseFloat(supplier.cost || "0") || 0,
quantityAvailable: parseInt(supplier.quantityAvailable || "0") || 0,
minimumOrderQuantity: parseInt(supplier.minimumOrderQuantity || "0") || 0,
productUrl: supplier.productUrl && supplier.productUrl.length > 4 ? `https://${supplier.productUrl.replace("https://", "").replace("http://", "")}` : null,
imageUrl: supplier.imageUrl && supplier.imageUrl.length > 4 ? `https://${supplier.imageUrl.replace("https://", "").replace("http://", "")}` : null
};
const response = await fetchApi("api/part/partSupplier", {
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(request)
});
if (response.responseObject.status === 200) {
const { data } = response;
toast.success(t("message.savedSupplier", "Saved supplier!"));
} else toast.error(t("error.failedSaveSupplier", "Failed to save supplier change!"));
};

const deletePartSupplier = async (e, partSupplier) => {
e.preventDefault();
e.stopPropagation();
Expand Down Expand Up @@ -139,6 +165,37 @@ export function PartSuppliersMemoized({ loadingPartMetadata, part, metadataParts
setShowAddPartSupplier(!showAddPartSupplier);
};

const handleFocus = (e, control, supplier) => {
e.target.value = supplier[e.target.name];
setIsEditing(e.target.name);
};

const handleInlineChange = (e, control, supplier) => {
e.preventDefault();
e.stopPropagation();

switch(control.name) {
case 'cost':
supplier[control.name] = parseFloat(control.value);
break;
case 'quantityAvailable':
supplier[control.name] = parseInt(control.value);
break;
case 'minimumOrderQuantity':
supplier[control.name] = parseInt(control.value);
break;
default:
supplier[control.name] = control.value;
break;
}
setTheMetadataParts({ ...theMetadataParts });
};

const saveColumn = async (e, supplier) => {
setIsEditing('');
await saveSupplier(supplier);
};

const renderSuppliers = useMemo(() => {
return (<Table compact celled sortable selectable striped unstackable size="small">
<Table.Header>
Expand All @@ -158,11 +215,11 @@ export function PartSuppliersMemoized({ loadingPartMetadata, part, metadataParts
theMetadataParts &&
_.filter(theMetadataParts, (p) => p.manufacturerPartNumber === part.manufacturerPartNumber).map((supplier, supplierKey) => (
<Table.Row key={supplierKey}>
<Table.Cell textAlign="center">{supplier.supplier}</Table.Cell>
<Table.Cell textAlign="center">{supplier.supplierPartNumber}</Table.Cell>
<Table.Cell textAlign="center">{formatCurrency(supplier.cost, supplier.currency)}</Table.Cell>
<Table.Cell textAlign="center">{formatNumber(supplier.quantityAvailable)}</Table.Cell>
<Table.Cell textAlign="center">{formatNumber(supplier.minimumOrderQuantity)}</Table.Cell>
<Table.Cell textAlign="center"><Input type="text" transparent className="inline-editable" onBlur={(e) => saveColumn(e, supplier)} onChange={(e, control) => handleInlineChange(e, control, supplier)} name="supplier" value={supplier.supplier} /></Table.Cell>
<Table.Cell textAlign="center"><Input type="text" transparent className="inline-editable" onBlur={(e) => saveColumn(e, supplier)} onChange={(e, control) => handleInlineChange(e, control, supplier)} name="supplierPartNumber" value={supplier.supplierPartNumber} /></Table.Cell>
<Table.Cell textAlign="center"><Input type="text" transparent className="inline-editable" onBlur={(e) => saveColumn(e, supplier)} onFocus={(e, control) => handleFocus(e, control, supplier)} onChange={(e, control) => handleInlineChange(e, control, supplier)} name="cost" value={isEditing === 'cost' ? supplier.cost : formatCurrency(supplier.cost, supplier.currency)} style={{width: '40px'}} /></Table.Cell>
<Table.Cell textAlign="center"><Input type="text" transparent className="inline-editable" onBlur={(e) => saveColumn(e, supplier)} onFocus={(e, control) => handleFocus(e, control, supplier)} onChange={(e, control) => handleInlineChange(e, control, supplier)} name="quantityAvailable" value={isEditing === 'quantityAvailable' ? supplier.quantityAvailable : formatNumber(supplier.quantityAvailable)} /></Table.Cell>
<Table.Cell textAlign="center"><Input type="text" transparent className="inline-editable" onBlur={(e) => saveColumn(e, supplier)} onFocus={(e, control) => handleFocus(e, control, supplier)} onChange={(e, control) => handleInlineChange(e, control, supplier)} name="minimumOrderQuantity" value={!isEditing === 'minimumOrderQuantity' ? supplier.minimumOrderQuantity : formatNumber(supplier.minimumOrderQuantity)} /></Table.Cell>
<Table.Cell textAlign="center">
{supplier.imageUrl && supplier.imageUrl.length > 10 && supplier.imageUrl.startsWith("http") && (
<img src={supplier.imageUrl} alt={supplier.supplierPartNumber} className="product productshot" />
Expand Down
Loading