feat: Add temperature ranges for extruder and bed temps (#5)
Some checks failed
CI / style (push) Has been cancelled
CI / build-client (push) Has been cancelled
CI / build-amd64 (push) Has been cancelled
CI / build-tester (push) Has been cancelled
CI / test (cockroachdb) (push) Has been cancelled
CI / test (mariadb) (push) Has been cancelled
CI / test (postgres) (push) Has been cancelled
CI / test (sqlite) (push) Has been cancelled
CI / build-arm64 (push) Has been cancelled
CI / build-armv7 (push) Has been cancelled
CI / publish-images (push) Has been cancelled
CI / publish-release (push) Has been cancelled
Some checks failed
CI / style (push) Has been cancelled
CI / build-client (push) Has been cancelled
CI / build-amd64 (push) Has been cancelled
CI / build-tester (push) Has been cancelled
CI / test (cockroachdb) (push) Has been cancelled
CI / test (mariadb) (push) Has been cancelled
CI / test (postgres) (push) Has been cancelled
CI / test (sqlite) (push) Has been cancelled
CI / build-arm64 (push) Has been cancelled
CI / build-armv7 (push) Has been cancelled
CI / publish-images (push) Has been cancelled
CI / publish-release (push) Has been cancelled
Store extruder and bed temperatures as min/max ranges instead of single values for more accurate filament specifications. Backend changes: - Add 4 new columns: settings_extruder_temp_min/max, settings_bed_temp_min/max - Keep old columns for backward compatibility (marked deprecated) - Alembic migration copies existing values to both min and max - Update Pydantic models and API endpoints Frontend changes: - Filament model updated with new fields - Create form uses min/max input pairs with Space.Compact - Import from external DB populates both min and max with same value - Label template updated to show ranges: "ET: 190-220 °C" - Template help includes new tags Labels now display temperature ranges like "190-220°C" which is more useful for printing than a single recommended value. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -236,6 +236,8 @@
|
|||||||
"comment": "Comment",
|
"comment": "Comment",
|
||||||
"settings_extruder_temp": "Extruder Temp",
|
"settings_extruder_temp": "Extruder Temp",
|
||||||
"settings_bed_temp": "Bed Temp",
|
"settings_bed_temp": "Bed Temp",
|
||||||
|
"temp_min": "Min",
|
||||||
|
"temp_max": "Max",
|
||||||
"color_hex": "Color",
|
"color_hex": "Color",
|
||||||
"single_color": "Single",
|
"single_color": "Single",
|
||||||
"multi_color": "Multi",
|
"multi_color": "Multi",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Create, useForm, useSelect } from "@refinedev/antd";
|
import { Create, useForm, useSelect } from "@refinedev/antd";
|
||||||
import { HttpError, IResourceComponentsProps, useInvalidate, useTranslate } from "@refinedev/core";
|
import { HttpError, IResourceComponentsProps, useInvalidate, useTranslate } from "@refinedev/core";
|
||||||
import { AutoComplete, Button, ColorPicker, Divider, Form, Input, InputNumber, Radio, Select, Typography } from "antd";
|
import { AutoComplete, Button, ColorPicker, Divider, Form, Input, InputNumber, Radio, Select, Space, Typography } from "antd";
|
||||||
import { PlusOutlined } from "@ant-design/icons";
|
import { PlusOutlined } from "@ant-design/icons";
|
||||||
import TextArea from "antd/es/input/TextArea";
|
import TextArea from "antd/es/input/TextArea";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
@@ -126,8 +126,10 @@ export const FilamentCreate: React.FC<IResourceComponentsProps & CreateOrClonePr
|
|||||||
color_hex: filament.color_hex,
|
color_hex: filament.color_hex,
|
||||||
multi_color_hexes: filament.color_hexes?.join(",") || undefined,
|
multi_color_hexes: filament.color_hexes?.join(",") || undefined,
|
||||||
multi_color_direction: filament.multi_color_direction,
|
multi_color_direction: filament.multi_color_direction,
|
||||||
settings_extruder_temp: filament.extruder_temp || undefined,
|
settings_extruder_temp_min: filament.extruder_temp || undefined,
|
||||||
settings_bed_temp: filament.bed_temp || undefined,
|
settings_extruder_temp_max: filament.extruder_temp || undefined,
|
||||||
|
settings_bed_temp_min: filament.bed_temp || undefined,
|
||||||
|
settings_bed_temp_max: filament.bed_temp || undefined,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -376,31 +378,43 @@ export const FilamentCreate: React.FC<IResourceComponentsProps & CreateOrClonePr
|
|||||||
>
|
>
|
||||||
<InputNumber addonAfter="g" precision={1} />
|
<InputNumber addonAfter="g" precision={1} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item label={t("filament.fields.settings_extruder_temp")}>
|
||||||
label={t("filament.fields.settings_extruder_temp")}
|
<Space.Compact>
|
||||||
name={["settings_extruder_temp"]}
|
<Form.Item
|
||||||
rules={[
|
name={["settings_extruder_temp_min"]}
|
||||||
{
|
noStyle
|
||||||
required: false,
|
rules={[{ type: "number", min: 0 }]}
|
||||||
type: "number",
|
>
|
||||||
min: 0,
|
<InputNumber placeholder={t("filament.fields.temp_min")} addonAfter="°C" precision={0} style={{ width: 140 }} />
|
||||||
},
|
</Form.Item>
|
||||||
]}
|
<span style={{ padding: "4px 8px", background: "#fafafa", border: "1px solid #d9d9d9", borderLeft: 0, borderRight: 0 }}>-</span>
|
||||||
>
|
<Form.Item
|
||||||
<InputNumber addonAfter="°C" precision={0} />
|
name={["settings_extruder_temp_max"]}
|
||||||
|
noStyle
|
||||||
|
rules={[{ type: "number", min: 0 }]}
|
||||||
|
>
|
||||||
|
<InputNumber placeholder={t("filament.fields.temp_max")} addonAfter="°C" precision={0} style={{ width: 140 }} />
|
||||||
|
</Form.Item>
|
||||||
|
</Space.Compact>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item label={t("filament.fields.settings_bed_temp")}>
|
||||||
label={t("filament.fields.settings_bed_temp")}
|
<Space.Compact>
|
||||||
name={["settings_bed_temp"]}
|
<Form.Item
|
||||||
rules={[
|
name={["settings_bed_temp_min"]}
|
||||||
{
|
noStyle
|
||||||
required: false,
|
rules={[{ type: "number", min: 0 }]}
|
||||||
type: "number",
|
>
|
||||||
min: 0,
|
<InputNumber placeholder={t("filament.fields.temp_min")} addonAfter="°C" precision={0} style={{ width: 140 }} />
|
||||||
},
|
</Form.Item>
|
||||||
]}
|
<span style={{ padding: "4px 8px", background: "#fafafa", border: "1px solid #d9d9d9", borderLeft: 0, borderRight: 0 }}>-</span>
|
||||||
>
|
<Form.Item
|
||||||
<InputNumber addonAfter="°C" precision={0} />
|
name={["settings_bed_temp_max"]}
|
||||||
|
noStyle
|
||||||
|
rules={[{ type: "number", min: 0 }]}
|
||||||
|
>
|
||||||
|
<InputNumber placeholder={t("filament.fields.temp_max")} addonAfter="°C" precision={0} style={{ width: 140 }} />
|
||||||
|
</Form.Item>
|
||||||
|
</Space.Compact>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("filament.fields.article_number")}
|
label={t("filament.fields.article_number")}
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ export interface IFilament {
|
|||||||
comment?: string;
|
comment?: string;
|
||||||
settings_extruder_temp?: number;
|
settings_extruder_temp?: number;
|
||||||
settings_bed_temp?: number;
|
settings_bed_temp?: number;
|
||||||
|
settings_extruder_temp_min?: number;
|
||||||
|
settings_extruder_temp_max?: number;
|
||||||
|
settings_bed_temp_min?: number;
|
||||||
|
settings_bed_temp_max?: number;
|
||||||
color_hex?: string;
|
color_hex?: string;
|
||||||
multi_color_hexes?: string;
|
multi_color_hexes?: string;
|
||||||
multi_color_direction?: string;
|
multi_color_direction?: string;
|
||||||
|
|||||||
@@ -157,8 +157,8 @@ const SpoolQRCodePrintingDialog: React.FC<SpoolQRCodePrintingDialog> = ({ spoolI
|
|||||||
`**{filament.vendor.name} - {filament.name}
|
`**{filament.vendor.name} - {filament.name}
|
||||||
#{id} - {filament.material}**
|
#{id} - {filament.material}**
|
||||||
Spool Weight: {filament.spool_weight} g
|
Spool Weight: {filament.spool_weight} g
|
||||||
{ET: {filament.settings_extruder_temp} °C}
|
{ET: {filament.settings_extruder_temp_min}-{filament.settings_extruder_temp_max} °C}
|
||||||
{BT: {filament.settings_bed_temp} °C}
|
{BT: {filament.settings_bed_temp_min}-{filament.settings_bed_temp_max} °C}
|
||||||
{Lot Nr: {lot_nr}}
|
{Lot Nr: {lot_nr}}
|
||||||
{{comment}}
|
{{comment}}
|
||||||
{filament.comment}
|
{filament.comment}
|
||||||
@@ -201,6 +201,10 @@ Spool Weight: {filament.spool_weight} g
|
|||||||
{ tag: "filament.comment" },
|
{ tag: "filament.comment" },
|
||||||
{ tag: "filament.settings_extruder_temp" },
|
{ tag: "filament.settings_extruder_temp" },
|
||||||
{ tag: "filament.settings_bed_temp" },
|
{ tag: "filament.settings_bed_temp" },
|
||||||
|
{ tag: "filament.settings_extruder_temp_min" },
|
||||||
|
{ tag: "filament.settings_extruder_temp_max" },
|
||||||
|
{ tag: "filament.settings_bed_temp_min" },
|
||||||
|
{ tag: "filament.settings_bed_temp_max" },
|
||||||
{ tag: "filament.color_hex" },
|
{ tag: "filament.color_hex" },
|
||||||
{ tag: "filament.multi_color_hexes" },
|
{ tag: "filament.multi_color_hexes" },
|
||||||
{ tag: "filament.multi_color_direction" },
|
{ tag: "filament.multi_color_direction" },
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
"""add_temperature_ranges.
|
||||||
|
|
||||||
|
Revision ID: a1b2c3d4e5f6
|
||||||
|
Revises: 415a8f855e14
|
||||||
|
Create Date: 2025-01-15 02:00:00.000000
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "a1b2c3d4e5f6"
|
||||||
|
down_revision = "415a8f855e14"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Add temperature range columns and migrate existing data."""
|
||||||
|
# Add new columns for temperature ranges
|
||||||
|
op.add_column("filament", sa.Column("settings_extruder_temp_min", sa.Integer(), nullable=True))
|
||||||
|
op.add_column("filament", sa.Column("settings_extruder_temp_max", sa.Integer(), nullable=True))
|
||||||
|
op.add_column("filament", sa.Column("settings_bed_temp_min", sa.Integer(), nullable=True))
|
||||||
|
op.add_column("filament", sa.Column("settings_bed_temp_max", sa.Integer(), nullable=True))
|
||||||
|
|
||||||
|
# Migrate existing single temp values to both min and max
|
||||||
|
# This preserves the existing data while enabling the new range functionality
|
||||||
|
connection = op.get_bind()
|
||||||
|
connection.execute(
|
||||||
|
sa.text(
|
||||||
|
"""
|
||||||
|
UPDATE filament
|
||||||
|
SET settings_extruder_temp_min = settings_extruder_temp,
|
||||||
|
settings_extruder_temp_max = settings_extruder_temp
|
||||||
|
WHERE settings_extruder_temp IS NOT NULL
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
connection.execute(
|
||||||
|
sa.text(
|
||||||
|
"""
|
||||||
|
UPDATE filament
|
||||||
|
SET settings_bed_temp_min = settings_bed_temp,
|
||||||
|
settings_bed_temp_max = settings_bed_temp
|
||||||
|
WHERE settings_bed_temp IS NOT NULL
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Remove temperature range columns."""
|
||||||
|
op.drop_column("filament", "settings_bed_temp_max")
|
||||||
|
op.drop_column("filament", "settings_bed_temp_min")
|
||||||
|
op.drop_column("filament", "settings_extruder_temp_max")
|
||||||
|
op.drop_column("filament", "settings_extruder_temp_min")
|
||||||
@@ -75,15 +75,39 @@ class FilamentParameters(BaseModel):
|
|||||||
settings_extruder_temp: Optional[int] = Field(
|
settings_extruder_temp: Optional[int] = Field(
|
||||||
None,
|
None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Overridden extruder temperature, in °C.",
|
description="Overridden extruder temperature, in °C. Deprecated: use settings_extruder_temp_min/max.",
|
||||||
examples=[210],
|
examples=[210],
|
||||||
)
|
)
|
||||||
settings_bed_temp: Optional[int] = Field(
|
settings_bed_temp: Optional[int] = Field(
|
||||||
None,
|
None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Overridden bed temperature, in °C.",
|
description="Overridden bed temperature, in °C. Deprecated: use settings_bed_temp_min/max.",
|
||||||
examples=[60],
|
examples=[60],
|
||||||
)
|
)
|
||||||
|
settings_extruder_temp_min: Optional[int] = Field(
|
||||||
|
None,
|
||||||
|
ge=0,
|
||||||
|
description="Minimum extruder temperature, in °C.",
|
||||||
|
examples=[190],
|
||||||
|
)
|
||||||
|
settings_extruder_temp_max: Optional[int] = Field(
|
||||||
|
None,
|
||||||
|
ge=0,
|
||||||
|
description="Maximum extruder temperature, in °C.",
|
||||||
|
examples=[220],
|
||||||
|
)
|
||||||
|
settings_bed_temp_min: Optional[int] = Field(
|
||||||
|
None,
|
||||||
|
ge=0,
|
||||||
|
description="Minimum bed temperature, in °C.",
|
||||||
|
examples=[50],
|
||||||
|
)
|
||||||
|
settings_bed_temp_max: Optional[int] = Field(
|
||||||
|
None,
|
||||||
|
ge=0,
|
||||||
|
description="Maximum bed temperature, in °C.",
|
||||||
|
examples=[70],
|
||||||
|
)
|
||||||
color_hex: Optional[str] = Field(
|
color_hex: Optional[str] = Field(
|
||||||
None,
|
None,
|
||||||
description=(
|
description=(
|
||||||
@@ -454,6 +478,10 @@ async def create( # noqa: ANN201
|
|||||||
comment=body.comment,
|
comment=body.comment,
|
||||||
settings_extruder_temp=body.settings_extruder_temp,
|
settings_extruder_temp=body.settings_extruder_temp,
|
||||||
settings_bed_temp=body.settings_bed_temp,
|
settings_bed_temp=body.settings_bed_temp,
|
||||||
|
settings_extruder_temp_min=body.settings_extruder_temp_min,
|
||||||
|
settings_extruder_temp_max=body.settings_extruder_temp_max,
|
||||||
|
settings_bed_temp_min=body.settings_bed_temp_min,
|
||||||
|
settings_bed_temp_max=body.settings_bed_temp_max,
|
||||||
color_hex=body.color_hex,
|
color_hex=body.color_hex,
|
||||||
multi_color_hexes=body.multi_color_hexes,
|
multi_color_hexes=body.multi_color_hexes,
|
||||||
multi_color_direction=body.multi_color_direction,
|
multi_color_direction=body.multi_color_direction,
|
||||||
|
|||||||
@@ -149,15 +149,39 @@ class Filament(BaseModel):
|
|||||||
settings_extruder_temp: Optional[int] = Field(
|
settings_extruder_temp: Optional[int] = Field(
|
||||||
None,
|
None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Overridden extruder temperature, in °C.",
|
description="Overridden extruder temperature, in °C. Deprecated: use settings_extruder_temp_min/max.",
|
||||||
examples=[210],
|
examples=[210],
|
||||||
)
|
)
|
||||||
settings_bed_temp: Optional[int] = Field(
|
settings_bed_temp: Optional[int] = Field(
|
||||||
None,
|
None,
|
||||||
ge=0,
|
ge=0,
|
||||||
description="Overridden bed temperature, in °C.",
|
description="Overridden bed temperature, in °C. Deprecated: use settings_bed_temp_min/max.",
|
||||||
examples=[60],
|
examples=[60],
|
||||||
)
|
)
|
||||||
|
settings_extruder_temp_min: Optional[int] = Field(
|
||||||
|
None,
|
||||||
|
ge=0,
|
||||||
|
description="Minimum extruder temperature, in °C.",
|
||||||
|
examples=[190],
|
||||||
|
)
|
||||||
|
settings_extruder_temp_max: Optional[int] = Field(
|
||||||
|
None,
|
||||||
|
ge=0,
|
||||||
|
description="Maximum extruder temperature, in °C.",
|
||||||
|
examples=[220],
|
||||||
|
)
|
||||||
|
settings_bed_temp_min: Optional[int] = Field(
|
||||||
|
None,
|
||||||
|
ge=0,
|
||||||
|
description="Minimum bed temperature, in °C.",
|
||||||
|
examples=[50],
|
||||||
|
)
|
||||||
|
settings_bed_temp_max: Optional[int] = Field(
|
||||||
|
None,
|
||||||
|
ge=0,
|
||||||
|
description="Maximum bed temperature, in °C.",
|
||||||
|
examples=[70],
|
||||||
|
)
|
||||||
color_hex: Optional[str] = Field(
|
color_hex: Optional[str] = Field(
|
||||||
None,
|
None,
|
||||||
min_length=6,
|
min_length=6,
|
||||||
@@ -216,6 +240,10 @@ class Filament(BaseModel):
|
|||||||
comment=item.comment,
|
comment=item.comment,
|
||||||
settings_extruder_temp=item.settings_extruder_temp,
|
settings_extruder_temp=item.settings_extruder_temp,
|
||||||
settings_bed_temp=item.settings_bed_temp,
|
settings_bed_temp=item.settings_bed_temp,
|
||||||
|
settings_extruder_temp_min=item.settings_extruder_temp_min,
|
||||||
|
settings_extruder_temp_max=item.settings_extruder_temp_max,
|
||||||
|
settings_bed_temp_min=item.settings_bed_temp_min,
|
||||||
|
settings_bed_temp_max=item.settings_bed_temp_max,
|
||||||
color_hex=item.color_hex,
|
color_hex=item.color_hex,
|
||||||
multi_color_hexes=item.multi_color_hexes,
|
multi_color_hexes=item.multi_color_hexes,
|
||||||
multi_color_direction=(
|
multi_color_direction=(
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ async def create(
|
|||||||
comment: Optional[str] = None,
|
comment: Optional[str] = None,
|
||||||
settings_extruder_temp: Optional[int] = None,
|
settings_extruder_temp: Optional[int] = None,
|
||||||
settings_bed_temp: Optional[int] = None,
|
settings_bed_temp: Optional[int] = None,
|
||||||
|
settings_extruder_temp_min: Optional[int] = None,
|
||||||
|
settings_extruder_temp_max: Optional[int] = None,
|
||||||
|
settings_bed_temp_min: Optional[int] = None,
|
||||||
|
settings_bed_temp_max: Optional[int] = None,
|
||||||
color_hex: Optional[str] = None,
|
color_hex: Optional[str] = None,
|
||||||
multi_color_hexes: Optional[str] = None,
|
multi_color_hexes: Optional[str] = None,
|
||||||
multi_color_direction: Optional[MultiColorDirection] = None,
|
multi_color_direction: Optional[MultiColorDirection] = None,
|
||||||
@@ -69,6 +73,10 @@ async def create(
|
|||||||
comment=comment,
|
comment=comment,
|
||||||
settings_extruder_temp=settings_extruder_temp,
|
settings_extruder_temp=settings_extruder_temp,
|
||||||
settings_bed_temp=settings_bed_temp,
|
settings_bed_temp=settings_bed_temp,
|
||||||
|
settings_extruder_temp_min=settings_extruder_temp_min,
|
||||||
|
settings_extruder_temp_max=settings_extruder_temp_max,
|
||||||
|
settings_bed_temp_min=settings_bed_temp_min,
|
||||||
|
settings_bed_temp_max=settings_bed_temp_max,
|
||||||
color_hex=color_hex,
|
color_hex=color_hex,
|
||||||
multi_color_hexes=multi_color_hexes,
|
multi_color_hexes=multi_color_hexes,
|
||||||
multi_color_direction=multi_color_direction.value if multi_color_direction is not None else None,
|
multi_color_direction=multi_color_direction.value if multi_color_direction is not None else None,
|
||||||
|
|||||||
@@ -46,8 +46,12 @@ class Filament(Base):
|
|||||||
spool_weight: Mapped[Optional[float]] = mapped_column(comment="The weight of an empty spool.")
|
spool_weight: Mapped[Optional[float]] = mapped_column(comment="The weight of an empty spool.")
|
||||||
article_number: Mapped[Optional[str]] = mapped_column(String(64))
|
article_number: Mapped[Optional[str]] = mapped_column(String(64))
|
||||||
comment: Mapped[Optional[str]] = mapped_column(String(1024))
|
comment: Mapped[Optional[str]] = mapped_column(String(1024))
|
||||||
settings_extruder_temp: Mapped[Optional[int]] = mapped_column(comment="Overridden extruder temperature.")
|
settings_extruder_temp: Mapped[Optional[int]] = mapped_column(comment="Overridden extruder temperature (deprecated, use min/max).")
|
||||||
settings_bed_temp: Mapped[Optional[int]] = mapped_column(comment="Overridden bed temperature.")
|
settings_bed_temp: Mapped[Optional[int]] = mapped_column(comment="Overridden bed temperature (deprecated, use min/max).")
|
||||||
|
settings_extruder_temp_min: Mapped[Optional[int]] = mapped_column(comment="Minimum extruder temperature.")
|
||||||
|
settings_extruder_temp_max: Mapped[Optional[int]] = mapped_column(comment="Maximum extruder temperature.")
|
||||||
|
settings_bed_temp_min: Mapped[Optional[int]] = mapped_column(comment="Minimum bed temperature.")
|
||||||
|
settings_bed_temp_max: Mapped[Optional[int]] = mapped_column(comment="Maximum bed temperature.")
|
||||||
color_hex: Mapped[Optional[str]] = mapped_column(String(8))
|
color_hex: Mapped[Optional[str]] = mapped_column(String(8))
|
||||||
multi_color_hexes: Mapped[Optional[str]] = mapped_column(String(128))
|
multi_color_hexes: Mapped[Optional[str]] = mapped_column(String(128))
|
||||||
multi_color_direction: Mapped[Optional[str]] = mapped_column(String(16))
|
multi_color_direction: Mapped[Optional[str]] = mapped_column(String(16))
|
||||||
|
|||||||
Reference in New Issue
Block a user