Added new print label template system

This commit is contained in:
Donkie
2024-06-19 20:33:23 +02:00
parent 4100813f22
commit b2e49aa270
3 changed files with 146 additions and 149 deletions

View File

@@ -101,20 +101,10 @@
"qrcode": { "qrcode": {
"button": "Print QR Codes", "button": "Print QR Codes",
"title": "QR Code Printing", "title": "QR Code Printing",
"spoolWeight": "Spool Weight: {{weight}}", "template": "Template",
"lotNr": "Lot Nr: {{lot}}", "templateHelp": "Use {} to insert values of the spool object as text. For example {id} will be replaced with the spool id, or {filament.material} will be replaced with the material of the spool. Click the button to view a list of all available tags.",
"bedTemp": "BT: {{temp}}",
"extruderTemp": "ET: {{temp}}",
"textSize": "Content Text Size", "textSize": "Content Text Size",
"showSpoolmanIcon": "Show Spoolman Icon", "showSpoolmanIcon": "Show Spoolman Icon"
"showVendor": "Manufacturer",
"showContent": "Print Label",
"showLotNr": "Lot Nr",
"showSpoolWeight": "Spool Weight",
"showTemperatures": "Temperatures",
"showSpoolComment": "Spool Comment",
"showFilamentComment": "Filament Comment",
"showVendorComment": "Manufacturer Comment"
}, },
"spoolSelect": { "spoolSelect": {
"title": "Select Spools", "title": "Select Spools",

View File

@@ -1,3 +1,5 @@
import React, { ReactNode } from "react";
import { ISpool } from "../../pages/spools/model";
import { useGetSetting, useSetSetting } from "../../utils/querySettings"; import { useGetSetting, useSetSetting } from "../../utils/querySettings";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
@@ -24,13 +26,7 @@ export interface QRCodePrintSettings {
} }
export interface SpoolQRCodePrintSettings { export interface SpoolQRCodePrintSettings {
showVendor?: boolean; template?: string;
showLotNr?: boolean;
showSpoolWeight?: boolean;
showTemperatures?: boolean;
showSpoolComment?: boolean;
showFilamentComment?: boolean;
showVendorComment?: boolean;
labelSettings: QRCodePrintSettings; labelSettings: QRCodePrintSettings;
} }
@@ -55,3 +51,42 @@ export function useSetPrintSettings(): (spoolQRCodePrintSettings: SpoolQRCodePri
mut.mutate(spoolQRCodePrintSettings); mut.mutate(spoolQRCodePrintSettings);
}; };
} }
interface GenericObject {
[key: string]: any;
extra: { [key: string]: string };
}
function getTagValue(tag: string, obj: GenericObject): any {
// Split tag by .
const tagParts = tag.split(".");
if (tagParts[0] === "extra") {
return JSON.parse(obj.extra[tagParts[1]]);
}
const value = obj[tagParts[0]] ?? "?";
// check if value is itself an object. If so, recursively call this and remove the first part of the tag
if (typeof value === "object") {
return getTagValue(tagParts.slice(1).join("."), value);
}
return value;
}
export function renderLabelContents(template: string, spool: ISpool): ReactNode {
// Find all {tags} in the template string and loop over them
let result = template.replace(/\{(.*?)\}/g, function (_, tag) {
return getTagValue(tag, spool);
});
// Split string on \n into individual lines
return (
<>
{result.split("\n").map((line, index) => (
<span key={index}>
{line}
<br />
</span>
))}
</>
);
}

View File

@@ -1,14 +1,24 @@
import { Button, Flex, Form, Input, Modal, Popconfirm, Select, Space, Switch } from "antd"; import { Button, Flex, Form, Input, Modal, Popconfirm, Select, Space, Switch, Table, Typography } from "antd";
import { IFilament } from "../../pages/filaments/model"; import { IFilament } from "../../pages/filaments/model";
import { ISpool } from "../../pages/spools/model"; import { ISpool } from "../../pages/spools/model";
import QRCodePrintingDialog from "./qrCodePrintingDialog"; import QRCodePrintingDialog from "./qrCodePrintingDialog";
import { useSavedState } from "../../utils/saveload"; import { useSavedState } from "../../utils/saveload";
import { useTranslate } from "@refinedev/core"; import { useTranslate } from "@refinedev/core";
import { QRCodePrintSettings, SpoolQRCodePrintSettings, useGetPrintSettings, useSetPrintSettings } from "./printing"; import {
QRCodePrintSettings,
SpoolQRCodePrintSettings,
renderLabelContents,
useGetPrintSettings,
useSetPrintSettings,
} from "./printing";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { DeleteOutlined, EditOutlined, PlusOutlined } from "@ant-design/icons"; import { DeleteOutlined, EditOutlined, PlusOutlined } from "@ant-design/icons";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import _ from "lodash"; import _ from "lodash";
import TextArea from "antd/es/input/TextArea";
import { EntityType, useGetFields } from "../../utils/queryFields";
const { Text } = Typography;
interface SpoolQRCodePrintingDialog { interface SpoolQRCodePrintingDialog {
visible: boolean; visible: boolean;
@@ -120,25 +130,73 @@ const SpoolQRCodePrintingDialog: React.FC<SpoolQRCodePrintingDialog> = ({ visibl
} }
} }
const showVendor = selectedPrintSetting?.showVendor; const [templateHelpOpen, setTemplateHelpOpen] = useState(false);
const showLotNr = selectedPrintSetting?.showLotNr; const template = selectedPrintSetting.template ?? "";
const showSpoolWeight = selectedPrintSetting?.showSpoolWeight;
const showTemperatures = selectedPrintSetting?.showTemperatures;
const showSpoolComment = selectedPrintSetting?.showSpoolComment;
const showFilamentComment = selectedPrintSetting?.showFilamentComment;
const showVendorComment = selectedPrintSetting?.showVendorComment;
const formatFilament = (filament: IFilament) => { const spoolTags = [
let vendorPrefix = ""; { tag: "id" },
if (showVendor && filament.vendor) { { tag: "registered" },
vendorPrefix = `${filament.vendor.name} - `; { tag: "first_used" },
} { tag: "last_used" },
let name = filament.name; { tag: "price" },
if (!name) { { tag: "initial_weight" },
name = `Filament #${filament.id}`; { tag: "spool_weight" },
} { tag: "remaining_weight" },
return `${vendorPrefix}${name}`; { tag: "used_weight" },
}; { tag: "remaining_length" },
{ tag: "used_length" },
{ tag: "location" },
{ tag: "lot_nr" },
{ tag: "comment" },
{ tag: "archived" },
];
const spoolFields = useGetFields(EntityType.spool);
if (spoolFields.data !== undefined) {
spoolFields.data.forEach((field) => {
spoolTags.push({ tag: `extra.${field.key}` });
});
}
const filamentTags = [
{ tag: "filament.id" },
{ tag: "filament.registered" },
{ tag: "filament.name" },
{ tag: "filament.material" },
{ tag: "filament.price" },
{ tag: "filament.density" },
{ tag: "filament.diameter" },
{ tag: "filament.weight" },
{ tag: "filament.spool_weight" },
{ tag: "filament.article_number" },
{ tag: "filament.comment" },
{ tag: "filament.settings_extruder_temp" },
{ tag: "filament.settings_bed_temp" },
{ tag: "filament.color_hex" },
{ tag: "filament.multi_color_hexes" },
{ tag: "filament.multi_color_direction" },
{ tag: "filament.external_id" },
];
const filamentFields = useGetFields(EntityType.filament);
if (filamentFields.data !== undefined) {
filamentFields.data.forEach((field) => {
filamentTags.push({ tag: `filament.extra.${field.key}` });
});
}
const vendorTags = [
{ tag: "filament.vendor.id" },
{ tag: "filament.vendor.registered" },
{ tag: "filament.vendor.name" },
{ tag: "filament.vendor.comment" },
{ tag: "filament.vendor.empty_spool_weight" },
{ tag: "filament.vendor.external_id" },
];
const vendorFields = useGetFields(EntityType.vendor);
if (vendorFields.data !== undefined) {
vendorFields.data.forEach((field) => {
vendorTags.push({ tag: `filament.vendor.extra.${field.key}` });
});
}
const templateTags = [...spoolTags, ...filamentTags, ...vendorTags];
return ( return (
<QRCodePrintingDialog <QRCodePrintingDialog
@@ -202,65 +260,16 @@ const SpoolQRCodePrintingDialog: React.FC<SpoolQRCodePrintingDialog> = ({ visibl
</> </>
} }
items={items.map(function (spool) { items={items.map(function (spool) {
const temps = [];
if (spool.filament.settings_extruder_temp) {
temps.push(t("printing.qrcode.extruderTemp", { temp: `${spool.filament.settings_extruder_temp} °C` }));
}
if (spool.filament.settings_bed_temp) {
temps.push(t("printing.qrcode.bedTemp", { temp: `${spool.filament.settings_bed_temp} °C` }));
}
const tempLine = temps.join(" - ");
return { return {
value: `web+spoolman:s-${spool.id}`, value: `web+spoolman:s-${spool.id}`,
label: ( label: (
<p <p
style={{ style={{
padding: "1mm 1mm 1mm 0", padding: "1mm 1mm 1mm 0",
whiteSpace: "pre-wrap",
}} }}
> >
<b>{formatFilament(spool.filament)}</b> {renderLabelContents(template, spool)}
<br />
<b>
#{spool.id}
{spool.filament.material && <> - {spool.filament.material}</>}
</b>
{showSpoolWeight && (
<>
<br />
{t("printing.qrcode.spoolWeight", { weight: `${spool.filament.spool_weight ?? "?"} g` })}
</>
)}
{showTemperatures && tempLine && (
<>
<br />
{tempLine}
</>
)}
{showLotNr && (
<>
<br />
{t("printing.qrcode.lotNr", { lot: spool.lot_nr ?? "?" })}
</>
)}
{showSpoolComment && spool.comment && (
<>
<br />
{spool.comment}
</>
)}
{showFilamentComment && spool.filament.comment && (
<>
<br />
{spool.filament.comment}
</>
)}
{showVendorComment && spool.filament.vendor?.comment && (
<>
<br />
{spool.filament.vendor.comment}
</>
)}
</p> </p>
), ),
errorLevel: "H", errorLevel: "H",
@@ -268,69 +277,32 @@ const SpoolQRCodePrintingDialog: React.FC<SpoolQRCodePrintingDialog> = ({ visibl
})} })}
extraSettings={ extraSettings={
<> <>
<Form.Item label={t("printing.qrcode.showVendor")}> <Form.Item label={t("printing.qrcode.template")}>
<Switch <TextArea
checked={showVendor} value={template}
onChange={(checked) => { rows={8}
selectedPrintSetting.showVendor = checked; onChange={(newValue) => {
selectedPrintSetting.template = newValue.target.value;
updateCurrentPrintSettings(selectedPrintSetting); updateCurrentPrintSettings(selectedPrintSetting);
}} }}
/> />
</Form.Item> </Form.Item>
<Form.Item label={t("printing.qrcode.showSpoolWeight")}> <Modal open={templateHelpOpen} footer={null} onCancel={() => setTemplateHelpOpen(false)}>
<Switch <Table
checked={showSpoolWeight} size="small"
onChange={(checked) => { showHeader={false}
selectedPrintSetting.showSpoolWeight = checked; pagination={false}
updateCurrentPrintSettings(selectedPrintSetting); scroll={{ y: 400 }}
}} columns={[{ dataIndex: "tag" }]}
dataSource={templateTags}
/> />
</Form.Item> </Modal>
<Form.Item label={t("printing.qrcode.showTemperatures")}> <Text type="secondary">
<Switch {t("printing.qrcode.templateHelp")}{" "}
checked={showTemperatures} <Button size="small" onClick={() => setTemplateHelpOpen(true)}>
onChange={(checked) => { {t("actions.show")}
selectedPrintSetting.showTemperatures = checked; </Button>
updateCurrentPrintSettings(selectedPrintSetting); </Text>
}}
/>
</Form.Item>
<Form.Item label={t("printing.qrcode.showLotNr")}>
<Switch
checked={showLotNr}
onChange={(checked) => {
selectedPrintSetting.showLotNr = checked;
updateCurrentPrintSettings(selectedPrintSetting);
}}
/>
</Form.Item>
<Form.Item label={t("printing.qrcode.showSpoolComment")}>
<Switch
checked={showSpoolComment}
onChange={(checked) => {
selectedPrintSetting.showSpoolComment = checked;
updateCurrentPrintSettings(selectedPrintSetting);
}}
/>
</Form.Item>
<Form.Item label={t("printing.qrcode.showFilamentComment")}>
<Switch
checked={showFilamentComment}
onChange={(checked) => {
selectedPrintSetting.showFilamentComment = checked;
updateCurrentPrintSettings(selectedPrintSetting);
}}
/>
</Form.Item>
<Form.Item label={t("printing.qrcode.showVendorComment")}>
<Switch
checked={showVendorComment}
onChange={(checked) => {
selectedPrintSetting.showVendorComment = checked;
updateCurrentPrintSettings(selectedPrintSetting);
}}
/>
</Form.Item>
</> </>
} }
/> />