Added new print label template system
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user