2577 lines
78 KiB
JavaScript
2577 lines
78 KiB
JavaScript
var At = Object.defineProperty;
|
|
var wt = (a, t, e) => t in a ? At(a, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[t] = e;
|
|
var j = (a, t, e) => wt(a, typeof t != "symbol" ? t + "" : t, e);
|
|
const J = "filament-card", Q = "filament-card-editor", S = {
|
|
preset: "spoolman",
|
|
title: "Filament",
|
|
group_by: "material",
|
|
group_sort_by: "name",
|
|
group_sort_direction: "asc",
|
|
group_order: [],
|
|
group_icon: "mdi:printer-3d-nozzle",
|
|
group_title_actions: {},
|
|
group_title_icons: {},
|
|
group_title_colors: {},
|
|
max_weight: 1e3,
|
|
hide_archived: !0,
|
|
sort_by: "remaining_weight",
|
|
sort_direction: "asc",
|
|
bar_direction: "vertical",
|
|
name_position: "bottom",
|
|
show_name: !0,
|
|
show_group_title: !0,
|
|
value_position: "center",
|
|
use_filament_color: !0,
|
|
// Custom mode
|
|
custom_attribute_entities: [],
|
|
custom_items: [],
|
|
custom_max_value: 1e3,
|
|
custom_unit: "g",
|
|
custom_label_id: "",
|
|
tap_action: {
|
|
action: "more-info"
|
|
},
|
|
double_tap_action: {
|
|
action: "none"
|
|
},
|
|
hold_action: {
|
|
action: "none"
|
|
},
|
|
spool_actions: {}
|
|
}, St = `
|
|
ha-card {
|
|
padding: 16px;
|
|
}
|
|
|
|
.title {
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.heading {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
margin: 18px 0 10px;
|
|
}
|
|
|
|
.heading:first-child {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.heading ha-icon {
|
|
--mdc-icon-size: 20px;
|
|
color: var(--secondary-text-color);
|
|
}
|
|
|
|
.heading.clickable {
|
|
cursor: pointer;
|
|
user-select: none;
|
|
}
|
|
|
|
.heading.clickable:hover {
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.spools {
|
|
display: flex;
|
|
gap: 0;
|
|
overflow-x: auto;
|
|
align-items: flex-end;
|
|
padding-bottom: 4px;
|
|
}
|
|
|
|
.spools.horizontal {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
gap: 6px;
|
|
}
|
|
|
|
.spool {
|
|
width: 70px;
|
|
min-width: 70px;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
padding: 8px 4px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.spool.vertical {
|
|
width: 70px;
|
|
min-width: 70px;
|
|
}
|
|
|
|
.spool.vertical.name-top {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.spool.vertical.name-top .name {
|
|
order: -1;
|
|
margin-top: 0;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.spool.horizontal {
|
|
width: 100%;
|
|
min-width: 160px;
|
|
display: grid;
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.spool.horizontal.name-left,
|
|
.spool.horizontal.name-right {
|
|
display: grid;
|
|
grid-template-columns: auto 1fr;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.spool.horizontal.name-right {
|
|
grid-template-columns: 1fr auto;
|
|
}
|
|
|
|
.spool.horizontal.name-left .name,
|
|
.spool.horizontal.name-right .name {
|
|
margin-top: 0;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.bar {
|
|
height: 200px;
|
|
border-radius: 10px;
|
|
background: var(--divider-color);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.spool.horizontal .bar {
|
|
height: 28px;
|
|
}
|
|
|
|
.fill {
|
|
position: absolute;
|
|
left: 0;
|
|
bottom: 0;
|
|
background: var(--primary-color);
|
|
}
|
|
|
|
.spool.vertical .fill {
|
|
width: 100%;
|
|
height: 0;
|
|
border-radius: 10px 10px 0 0;
|
|
}
|
|
|
|
.spool.horizontal .fill {
|
|
top: 0;
|
|
bottom: 0;
|
|
height: 100%;
|
|
width: 0;
|
|
border-radius: 10px 0 0 10px;
|
|
}
|
|
|
|
.value {
|
|
position: absolute;
|
|
z-index: 2;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 20px;
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
text-align: center;
|
|
text-shadow: 0 1px 2px rgba(0,0,0,.25);
|
|
}
|
|
|
|
.spool.vertical.value-top .value {
|
|
top: 12px;
|
|
bottom: auto;
|
|
}
|
|
|
|
.spool.vertical.value-center .value {
|
|
top: 50%;
|
|
bottom: auto;
|
|
transform: translateY(-50%);
|
|
}
|
|
|
|
.spool.vertical.value-bottom .value {
|
|
bottom: 20px;
|
|
}
|
|
|
|
.spool.horizontal .value {
|
|
top: 50%;
|
|
bottom: auto;
|
|
transform: translateY(-50%);
|
|
}
|
|
|
|
.spool.horizontal.value-left .value {
|
|
left: 10px;
|
|
right: auto;
|
|
text-align: left;
|
|
}
|
|
|
|
.spool.horizontal.value-center .value {
|
|
left: 0;
|
|
right: 0;
|
|
text-align: center;
|
|
}
|
|
|
|
.spool.horizontal.value-right .value {
|
|
left: auto;
|
|
right: 10px;
|
|
text-align: right;
|
|
}
|
|
|
|
.name {
|
|
font-size: 12px;
|
|
font-weight: bold;
|
|
margin-top: 6px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.spool.horizontal .name {
|
|
text-align: left;
|
|
margin-top: 4px;
|
|
}
|
|
|
|
.empty {
|
|
color: var(--secondary-text-color);
|
|
padding: 8px 0;
|
|
}
|
|
|
|
.expandable-section {
|
|
border: 1px solid var(--divider-color);
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.expandable-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 8px;
|
|
padding: 12px;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
font-weight: 500;
|
|
background: var(--secondary-background-color);
|
|
}
|
|
|
|
.expandable-header:hover {
|
|
filter: brightness(1.03);
|
|
}
|
|
|
|
.expandable-content {
|
|
display: grid;
|
|
gap: 12px;
|
|
padding: 12px;
|
|
}
|
|
`;
|
|
function Ct(a) {
|
|
return a ? a.startsWith("#") ? a : `#${a}` : "#999999";
|
|
}
|
|
function A(a) {
|
|
if (!a || a.startsWith("var("))
|
|
return "var(--primary-text-color)";
|
|
const t = a.replace("#", "");
|
|
if (t.length !== 6)
|
|
return "var(--primary-text-color)";
|
|
const e = parseInt(t.substring(0, 2), 16), n = parseInt(t.substring(2, 4), 16), i = parseInt(t.substring(4, 6), 16);
|
|
return (e * 299 + n * 587 + i * 114) / 1e3 > 140 ? "black" : "white";
|
|
}
|
|
function Et(a, t, e) {
|
|
const n = a.value_position || "center";
|
|
return a.use_filament_color ? a.bar_direction === "horizontal" ? n === "left" && e >= 15 || n === "center" && e >= 50 || n === "right" && e >= 85 ? A(t) : "var(--primary-text-color)" : a.bar_direction === "vertical" && (n === "bottom" && e >= 15 || n === "center" && e >= 50 || n === "top" && e >= 85) ? A(t) : "var(--primary-text-color)" : "var(--primary-text-color)";
|
|
}
|
|
function Tt(a, t, e) {
|
|
return a.bar_direction === "horizontal" ? `width:${t}%; background:${e};` : `height:${t}%; background:${e};`;
|
|
}
|
|
function C(a, t) {
|
|
const e = t.state.attributes;
|
|
return a.group_by === "color" ? e.filament_name || e.filament_color_hex || "unknown" : a.group_by === "material" ? e.filament_material || "unknown" : a.group_by === "vendor" ? e.filament_vendor_name || "unknown" : "all";
|
|
}
|
|
function B(a, t, e) {
|
|
const n = a.sort_by, i = a.sort_direction === "desc" ? -1 : 1, r = t.state.attributes[n] ?? t.state.state ?? "", s = e.state.attributes[n] ?? e.state.state ?? "", o = Number(r), l = Number(s);
|
|
return !Number.isNaN(o) && !Number.isNaN(l) ? (o - l) * i : String(r).localeCompare(String(s), void 0, { numeric: !0 }) * i;
|
|
}
|
|
function Nt(a, t, e, n) {
|
|
const i = a.group_sort_direction === "desc" ? -1 : 1, r = n.filter((o) => C(a, o) === t), s = n.filter((o) => C(a, o) === e);
|
|
switch (a.group_sort_by) {
|
|
case "total_remaining_weight": {
|
|
const o = r.reduce((c, h) => c + Number(h.state.attributes.remaining_weight || 0), 0), l = s.reduce((c, h) => c + Number(h.state.attributes.remaining_weight || 0), 0);
|
|
return (o - l) * i;
|
|
}
|
|
case "max_remaining_weight": {
|
|
const o = Math.max(...r.map((c) => Number(c.state.attributes.remaining_weight || 0))), l = Math.max(...s.map((c) => Number(c.state.attributes.remaining_weight || 0)));
|
|
return (o - l) * i;
|
|
}
|
|
case "spool_count":
|
|
return (r.length - s.length) * i;
|
|
case "name":
|
|
default:
|
|
return String(t).localeCompare(String(e), void 0, { numeric: !0 }) * i;
|
|
}
|
|
}
|
|
function gt(a, t, e) {
|
|
var n;
|
|
if ((n = a.group_order) != null && n.length) {
|
|
const i = a.group_order.map((r) => String(r));
|
|
return t.sort((r, s) => {
|
|
const o = i.indexOf(String(r)), l = i.indexOf(String(s)), c = o !== -1, h = l !== -1;
|
|
return c && h ? o - l : c ? -1 : h ? 1 : String(r).localeCompare(String(s), void 0, { numeric: !0 });
|
|
});
|
|
}
|
|
return t.sort((i, r) => Nt(a, i, r, e));
|
|
}
|
|
class Ot extends HTMLElement {
|
|
static getConfigElement() {
|
|
return document.createElement(Q);
|
|
}
|
|
static getStubConfig() {
|
|
return { ...S };
|
|
}
|
|
setConfig(t) {
|
|
this.config = {
|
|
...S,
|
|
group_by: t.group_by ?? (t.group_by_material === !1 ? "none" : "material"),
|
|
group_order: t.group_order ?? t.materials ?? S.group_order,
|
|
...t
|
|
}, this.shadowRoot || this.attachShadow({ mode: "open" });
|
|
}
|
|
set hass(t) {
|
|
const e = this._spoolSignature;
|
|
this._hass = t, this._spoolSignature = this.createSpoolSignature(t), (!e || e !== this._spoolSignature) && this.render();
|
|
}
|
|
createSpoolSignature(t) {
|
|
var n;
|
|
const e = ((n = this.config) == null ? void 0 : n.preset) || "spoolman";
|
|
if (e === "custom_attributes")
|
|
return (this.config.custom_attribute_entities || []).map((i) => {
|
|
const r = t.states[i];
|
|
if (!r) return `${i}|missing`;
|
|
const s = r.attributes || {};
|
|
return [
|
|
i,
|
|
r.state,
|
|
s.value,
|
|
s.remaining_weight,
|
|
s.max_value,
|
|
s.max,
|
|
s.name,
|
|
s.friendly_name,
|
|
s.group,
|
|
s.material,
|
|
s.vendor,
|
|
s.color,
|
|
s.filament_color_hex,
|
|
s.unit
|
|
].join("|");
|
|
}).sort().join(";");
|
|
if (e === "custom_entities")
|
|
return (this.config.custom_items || []).map((i, r) => {
|
|
const s = [
|
|
i.value_entity,
|
|
i.max_entity,
|
|
i.color_entity,
|
|
i.group_entity,
|
|
i.vendor_entity,
|
|
i.name_entity
|
|
].filter(Boolean);
|
|
return [
|
|
r,
|
|
i.name,
|
|
i.group,
|
|
i.vendor,
|
|
i.color,
|
|
i.max,
|
|
i.max_value,
|
|
i.unit,
|
|
...s.map((o) => {
|
|
var c;
|
|
const l = t.states[o];
|
|
return l ? `${o}|${l.state}|${((c = l.attributes) == null ? void 0 : c.friendly_name) || ""}` : `${o}|missing`;
|
|
})
|
|
].join("|");
|
|
}).sort().join(";");
|
|
if (e === "custom_label") {
|
|
const i = this.config.custom_label_id;
|
|
return !i || !t.entities ? "" : Object.entries(t.entities).filter(([, r]) => {
|
|
var s;
|
|
return (s = r.labels) == null ? void 0 : s.includes(i);
|
|
}).map(([r]) => {
|
|
const s = t.states[r];
|
|
if (!s) return `${r}|missing`;
|
|
const o = s.attributes || {};
|
|
return [
|
|
r,
|
|
s.state,
|
|
o.value,
|
|
o.remaining_weight,
|
|
o.max_value,
|
|
o.max,
|
|
o.name,
|
|
o.friendly_name,
|
|
o.group,
|
|
o.material,
|
|
o.vendor,
|
|
o.color,
|
|
o.filament_color_hex,
|
|
o.unit
|
|
].join("|");
|
|
}).sort().join(";");
|
|
}
|
|
return Object.entries(t.states).filter(([, i]) => {
|
|
var r;
|
|
return (r = i.attributes) == null ? void 0 : r.filament_material;
|
|
}).map(([i, r]) => {
|
|
const s = r.attributes;
|
|
return [
|
|
i,
|
|
r.state,
|
|
s.remaining_weight,
|
|
s.filament_weight,
|
|
s.archived,
|
|
s.filament_material,
|
|
s.filament_name,
|
|
s.filament_color_hex,
|
|
s.filament_vendor_name
|
|
].join("|");
|
|
}).sort().join(";");
|
|
}
|
|
render() {
|
|
if (!this._hass || !this.config) return;
|
|
const t = this.getItems();
|
|
this._actionConfigsByEntity = Object.fromEntries(
|
|
t.map((i) => [i.entity_id, this.getActionConfigsForItem(i)])
|
|
);
|
|
const e = Math.max(
|
|
...t.map(
|
|
(i) => Number(i.state.attributes.filament_weight || i.state.attributes.remaining_weight || 0)
|
|
),
|
|
Number(this.config.max_weight || 0),
|
|
1e3
|
|
), n = this.config.group_by === "none" ? this.renderFlat(t, e) : this.renderGrouped(t, e);
|
|
this.shadowRoot.innerHTML = `
|
|
<style>${St}</style>
|
|
|
|
<ha-card>
|
|
${this.config.title ? `<div class="title">${this.config.title}</div>` : ""}
|
|
${n}
|
|
</ha-card>
|
|
`, this.attachActionHandlers(), this.attachGroupTitleActionHandlers();
|
|
}
|
|
getItems() {
|
|
const t = this.config.preset || "spoolman";
|
|
let e;
|
|
return t === "custom_attributes" ? e = this.getCustomAttributeItems() : t === "custom_entities" ? e = this.getCustomEntityItems() : t === "custom_label" ? e = this.getCustomLabelItems() : e = this.getSpoolmanItems(), this.applyFilters(e);
|
|
}
|
|
applyFilters(t) {
|
|
if (this.config.group_by === "none")
|
|
return t;
|
|
const e = this.config.filters || {}, n = this.normalizeFilterValues(e.include), i = this.normalizeFilterValues(e.exclude);
|
|
return !n.length && !i.length ? t : t.filter((r) => {
|
|
const s = C(this.config, r), o = this.normalizeFilterValue(s);
|
|
return !(n.length && !n.includes(o) || i.includes(o));
|
|
});
|
|
}
|
|
normalizeFilterValues(t) {
|
|
return Array.isArray(t) ? t.map((e) => this.normalizeFilterValue(e)).filter(Boolean) : [];
|
|
}
|
|
normalizeFilterValue(t) {
|
|
return String(t ?? "").trim().toLocaleLowerCase();
|
|
}
|
|
getSpoolmanItems() {
|
|
return Object.entries(this._hass.states).map(([t, e]) => ({ entity_id: t, state: e })).filter(({ state: t }) => {
|
|
var e;
|
|
return (e = t.attributes) == null ? void 0 : e.filament_material;
|
|
}).filter(({ state: t }) => !this.config.hide_archived || t.attributes.archived === !1).sort((t, e) => B(this.config, t, e));
|
|
}
|
|
getCustomAttributeItems() {
|
|
const t = this.config.custom_attribute_entities || [], e = Number(this.config.custom_max_value || 1e3), n = this.config.custom_unit || "g";
|
|
return t.map((i) => {
|
|
const r = this._hass.states[i];
|
|
if (!r) return null;
|
|
const s = r.attributes || {}, o = Number(s.value ?? s.remaining_weight ?? r.state);
|
|
return Number.isNaN(o) ? null : this.createVirtualItem({
|
|
entity_id: i,
|
|
value: o,
|
|
max: Number(s.max_value ?? s.max ?? e),
|
|
name: s.name || s.friendly_name || i,
|
|
group: s.group || s.material || "Custom",
|
|
vendor: s.vendor || "",
|
|
color: s.color || s.filament_color_hex,
|
|
unit: s.unit || n,
|
|
tap_action: s.tap_action,
|
|
double_tap_action: s.double_tap_action,
|
|
hold_action: s.hold_action
|
|
});
|
|
}).filter(Boolean).sort((i, r) => B(this.config, i, r));
|
|
}
|
|
getCustomEntityItems() {
|
|
const t = this.config.custom_items || [], e = Number(this.config.custom_max_value || 1e3), n = this.config.custom_unit || "g";
|
|
return t.map((i, r) => {
|
|
var m, g, N, O, P, H;
|
|
const s = this._hass.states[i.value_entity];
|
|
if (!s) return null;
|
|
const o = Number(s.state);
|
|
if (Number.isNaN(o)) return null;
|
|
const l = i.max_entity ? Number(((m = this._hass.states[i.max_entity]) == null ? void 0 : m.state) ?? e) : Number(i.max ?? i.max_value ?? e), c = i.color_entity ? (g = this._hass.states[i.color_entity]) == null ? void 0 : g.state : i.color, h = i.group_entity ? (N = this._hass.states[i.group_entity]) == null ? void 0 : N.state : i.group, d = i.vendor_entity ? (O = this._hass.states[i.vendor_entity]) == null ? void 0 : O.state : i.vendor, _ = i.name_entity ? (P = this._hass.states[i.name_entity]) == null ? void 0 : P.state : i.name;
|
|
return this.createVirtualItem({
|
|
entity_id: i.value_entity || `custom_item_${r}`,
|
|
value: o,
|
|
max: Number.isNaN(l) ? e : l,
|
|
name: _ || ((H = s.attributes) == null ? void 0 : H.friendly_name) || i.value_entity,
|
|
group: h || "Custom",
|
|
vendor: d || "",
|
|
color: c,
|
|
unit: i.unit || n,
|
|
tap_action: i.tap_action,
|
|
double_tap_action: i.double_tap_action,
|
|
hold_action: i.hold_action
|
|
});
|
|
}).filter(Boolean).sort((i, r) => B(this.config, i, r));
|
|
}
|
|
getCustomLabelItems() {
|
|
var n;
|
|
const t = this.config.custom_label_id;
|
|
if (!t || !((n = this._hass) != null && n.entities)) return [];
|
|
const e = Object.entries(this._hass.entities).filter(([, i]) => {
|
|
var r;
|
|
return (r = i.labels) == null ? void 0 : r.includes(t);
|
|
}).map(([i]) => i);
|
|
return this.config.custom_attribute_entities = e, this.getCustomAttributeItems();
|
|
}
|
|
getActionConfigsForItem(t) {
|
|
var r, s;
|
|
const e = t.entity_id, n = ((r = t.state) == null ? void 0 : r.attributes) || {}, i = ((s = this.config.spool_actions) == null ? void 0 : s[e]) || {};
|
|
return {
|
|
tap: n.tap_action || t.tap_action || i.tap_action || this.config.tap_action,
|
|
double_tap: n.double_tap_action || t.double_tap_action || i.double_tap_action || this.config.double_tap_action,
|
|
hold: n.hold_action || t.hold_action || i.hold_action || this.config.hold_action
|
|
};
|
|
}
|
|
getGroupTitleActionConfigs(t) {
|
|
var n, i;
|
|
const e = ((n = this.config.group_title_actions) == null ? void 0 : n[t]) || ((i = this.config.group_actions) == null ? void 0 : i[t]) || {};
|
|
return {
|
|
tap: e.tap_action || { action: "none" },
|
|
double_tap: e.double_tap_action || { action: "none" },
|
|
hold: e.hold_action || { action: "none" }
|
|
};
|
|
}
|
|
getGroupTitleIcon(t) {
|
|
var e, n;
|
|
return ((e = this.config.group_title_icons) == null ? void 0 : e[t]) || ((n = this.config.group_icons) == null ? void 0 : n[t]) || this.config.group_icon;
|
|
}
|
|
getGroupTitleColor(t) {
|
|
var e, n;
|
|
return ((e = this.config.group_title_colors) == null ? void 0 : e[t]) || ((n = this.config.group_colors) == null ? void 0 : n[t]);
|
|
}
|
|
attachGroupTitleActionHandlers() {
|
|
this.shadowRoot.querySelectorAll(".heading[data-group]").forEach((t) => {
|
|
const e = t.dataset.group;
|
|
if (!e) return;
|
|
const n = this.getGroupTitleActionConfigs(e);
|
|
t.addEventListener("click", (i) => {
|
|
i.stopPropagation(), this.handleTap(e, n);
|
|
}), t.addEventListener("dblclick", (i) => {
|
|
i.stopPropagation(), this.handleDoubleTap(e, n);
|
|
}), t.addEventListener(
|
|
"pointerdown",
|
|
() => this.handleHoldStart(e, n)
|
|
), t.addEventListener("pointerup", () => this.handleHoldEnd()), t.addEventListener("pointerleave", () => this.handleHoldEnd()), t.addEventListener("pointercancel", () => this.handleHoldEnd());
|
|
});
|
|
}
|
|
createVirtualItem({
|
|
entity_id: t,
|
|
value: e,
|
|
max: n,
|
|
name: i,
|
|
group: r,
|
|
vendor: s,
|
|
color: o,
|
|
unit: l,
|
|
tap_action: c,
|
|
double_tap_action: h,
|
|
hold_action: d
|
|
}) {
|
|
return {
|
|
entity_id: t,
|
|
tap_action: c,
|
|
double_tap_action: h,
|
|
hold_action: d,
|
|
state: {
|
|
state: String(e),
|
|
attributes: {
|
|
friendly_name: i,
|
|
remaining_weight: e,
|
|
filament_weight: n,
|
|
filament_material: r,
|
|
filament_name: i,
|
|
filament_vendor_name: s,
|
|
filament_color_hex: o,
|
|
archived: !1,
|
|
custom_unit: l,
|
|
tap_action: c,
|
|
double_tap_action: h,
|
|
hold_action: d
|
|
}
|
|
}
|
|
};
|
|
}
|
|
fireHassAction(t, e, n) {
|
|
this.dispatchEvent(
|
|
new CustomEvent("hass-action", {
|
|
detail: {
|
|
config: {
|
|
entity: t,
|
|
tap_action: e.tap || { action: "more-info" },
|
|
double_tap_action: e.double_tap || { action: "none" },
|
|
hold_action: e.hold || { action: "none" }
|
|
},
|
|
action: n
|
|
},
|
|
bubbles: !0,
|
|
composed: !0
|
|
})
|
|
);
|
|
}
|
|
handleTap(t, e) {
|
|
if (this._holdFired) {
|
|
this._holdFired = !1;
|
|
return;
|
|
}
|
|
clearTimeout(this._tapTimer), this._tapTimer = setTimeout(() => {
|
|
this.fireHassAction(t, e, "tap");
|
|
}, 250);
|
|
}
|
|
handleDoubleTap(t, e) {
|
|
clearTimeout(this._tapTimer), this.fireHassAction(t, e, "double_tap");
|
|
}
|
|
handleHoldStart(t, e) {
|
|
this._holdFired = !1, clearTimeout(this._holdTimer), this._holdTimer = setTimeout(() => {
|
|
this._holdFired = !0, this.fireHassAction(t, e, "hold");
|
|
}, 500);
|
|
}
|
|
handleHoldEnd() {
|
|
clearTimeout(this._holdTimer);
|
|
}
|
|
attachActionHandlers() {
|
|
this.shadowRoot.querySelectorAll(".spool").forEach((t) => {
|
|
var i;
|
|
const e = t.dataset.entity;
|
|
if (!e) return;
|
|
const n = ((i = this._actionConfigsByEntity) == null ? void 0 : i[e]) || {
|
|
tap: this.config.tap_action,
|
|
double_tap: this.config.double_tap_action,
|
|
hold: this.config.hold_action
|
|
};
|
|
t.addEventListener("click", (r) => {
|
|
r.stopPropagation(), this.handleTap(e, n);
|
|
}), t.addEventListener("dblclick", (r) => {
|
|
r.stopPropagation(), this.handleDoubleTap(e, n);
|
|
}), t.addEventListener(
|
|
"pointerdown",
|
|
() => this.handleHoldStart(e, n)
|
|
), t.addEventListener("pointerup", () => this.handleHoldEnd()), t.addEventListener("pointerleave", () => this.handleHoldEnd()), t.addEventListener("pointercancel", () => this.handleHoldEnd());
|
|
});
|
|
}
|
|
renderGrouped(t, e) {
|
|
let n = [...new Set(t.map((i) => C(this.config, i)))];
|
|
return n = gt(this.config, n, t), n.map((i) => {
|
|
const r = this.getGroupTitleIcon(i), s = this.getGroupTitleColor(i);
|
|
this.getGroupTitleActionConfigs(i);
|
|
const o = t.filter((l) => C(this.config, l) === i);
|
|
return o.length ? `
|
|
${this.config.show_group_title ? `
|
|
<div
|
|
class="heading clickable"
|
|
data-group="${i}"
|
|
>
|
|
${r !== "none" ? `<ha-icon icon="${r}"></ha-icon>` : ""}
|
|
<span ${s ? `style="color:${s};"` : ""}>
|
|
${i}
|
|
</span>
|
|
</div>
|
|
` : ""}
|
|
|
|
<div class="spools ${this.config.bar_direction}">
|
|
${o.map((l) => this.renderSpool(l, e)).join("")}
|
|
</div>
|
|
` : "";
|
|
}).join("");
|
|
}
|
|
renderFlat(t, e) {
|
|
return t.length ? `
|
|
<div class="spools ${this.config.bar_direction}">
|
|
${t.map((n) => this.renderSpool(n, e)).join("")}
|
|
</div>
|
|
` : '<div class="empty">Keine Filamente gefunden.</div>';
|
|
}
|
|
renderSpool({ entity_id: t, state: e }, n) {
|
|
const i = e.attributes, r = Number(i.remaining_weight ?? e.state ?? 0), s = Number(i.filament_weight || n || 1e3), o = Math.max(0, Math.min(100, r / s * 100)), l = this.config.use_filament_color ? Ct(i.filament_color_hex) : "var(--primary-color)", c = Et(this.config, l, o), h = this.config.group_by === "color" ? i.filament_material || i.friendly_name || t : i.filament_name || i.friendly_name || t;
|
|
return `
|
|
<div class="spool ${this.config.bar_direction} name-${this.config.name_position} value-${this.config.value_position}" data-entity="${t}">
|
|
${this.config.show_name && ["top", "left"].includes(this.config.name_position) ? `<div class="name">${h}</div>` : ""}
|
|
|
|
<div class="bar">
|
|
<div class="fill" style="${Tt(this.config, o, l)}"></div>
|
|
<div class="value" style="color:${c};">${r.toFixed(1)}${i.custom_unit || "g"}</div>
|
|
</div>
|
|
|
|
${this.config.show_name && ["bottom", "right"].includes(this.config.name_position) ? `<div class="name">${h}</div>` : ""}
|
|
</div>
|
|
`;
|
|
}
|
|
getCardSize() {
|
|
return 4;
|
|
}
|
|
}
|
|
customElements.get(J) || customElements.define(J, Ot);
|
|
/**
|
|
* @license
|
|
* Copyright 2019 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const M = globalThis, tt = M.ShadowRoot && (M.ShadyCSS === void 0 || M.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, et = Symbol(), nt = /* @__PURE__ */ new WeakMap();
|
|
let ft = class {
|
|
constructor(t, e, n) {
|
|
if (this._$cssResult$ = !0, n !== et) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
|
|
this.cssText = t, this.t = e;
|
|
}
|
|
get styleSheet() {
|
|
let t = this.o;
|
|
const e = this.t;
|
|
if (tt && t === void 0) {
|
|
const n = e !== void 0 && e.length === 1;
|
|
n && (t = nt.get(e)), t === void 0 && ((this.o = t = new CSSStyleSheet()).replaceSync(this.cssText), n && nt.set(e, t));
|
|
}
|
|
return t;
|
|
}
|
|
toString() {
|
|
return this.cssText;
|
|
}
|
|
};
|
|
const Pt = (a) => new ft(typeof a == "string" ? a : a + "", void 0, et), Ht = (a, ...t) => {
|
|
const e = a.length === 1 ? a[0] : t.reduce((n, i, r) => n + ((s) => {
|
|
if (s._$cssResult$ === !0) return s.cssText;
|
|
if (typeof s == "number") return s;
|
|
throw Error("Value passed to 'css' function must be a 'css' function result: " + s + ". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.");
|
|
})(i) + a[r + 1], a[0]);
|
|
return new ft(e, a, et);
|
|
}, It = (a, t) => {
|
|
if (tt) a.adoptedStyleSheets = t.map((e) => e instanceof CSSStyleSheet ? e : e.styleSheet);
|
|
else for (const e of t) {
|
|
const n = document.createElement("style"), i = M.litNonce;
|
|
i !== void 0 && n.setAttribute("nonce", i), n.textContent = e.cssText, a.appendChild(n);
|
|
}
|
|
}, rt = tt ? (a) => a : (a) => a instanceof CSSStyleSheet ? ((t) => {
|
|
let e = "";
|
|
for (const n of t.cssRules) e += n.cssText;
|
|
return Pt(e);
|
|
})(a) : a;
|
|
/**
|
|
* @license
|
|
* Copyright 2017 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const { is: kt, defineProperty: Vt, getOwnPropertyDescriptor: Gt, getOwnPropertyNames: zt, getOwnPropertySymbols: Ft, getPrototypeOf: Ut } = Object, v = globalThis, st = v.trustedTypes, Lt = st ? st.emptyScript : "", W = v.reactiveElementPolyfillSupport, k = (a, t) => a, X = { toAttribute(a, t) {
|
|
switch (t) {
|
|
case Boolean:
|
|
a = a ? Lt : null;
|
|
break;
|
|
case Object:
|
|
case Array:
|
|
a = a == null ? a : JSON.stringify(a);
|
|
}
|
|
return a;
|
|
}, fromAttribute(a, t) {
|
|
let e = a;
|
|
switch (t) {
|
|
case Boolean:
|
|
e = a !== null;
|
|
break;
|
|
case Number:
|
|
e = a === null ? null : Number(a);
|
|
break;
|
|
case Object:
|
|
case Array:
|
|
try {
|
|
e = JSON.parse(a);
|
|
} catch {
|
|
e = null;
|
|
}
|
|
}
|
|
return e;
|
|
} }, vt = (a, t) => !kt(a, t), ot = { attribute: !0, type: String, converter: X, reflect: !1, useDefault: !1, hasChanged: vt };
|
|
Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), v.litPropertyMetadata ?? (v.litPropertyMetadata = /* @__PURE__ */ new WeakMap());
|
|
let w = class extends HTMLElement {
|
|
static addInitializer(t) {
|
|
this._$Ei(), (this.l ?? (this.l = [])).push(t);
|
|
}
|
|
static get observedAttributes() {
|
|
return this.finalize(), this._$Eh && [...this._$Eh.keys()];
|
|
}
|
|
static createProperty(t, e = ot) {
|
|
if (e.state && (e.attribute = !1), this._$Ei(), this.prototype.hasOwnProperty(t) && ((e = Object.create(e)).wrapped = !0), this.elementProperties.set(t, e), !e.noAccessor) {
|
|
const n = Symbol(), i = this.getPropertyDescriptor(t, n, e);
|
|
i !== void 0 && Vt(this.prototype, t, i);
|
|
}
|
|
}
|
|
static getPropertyDescriptor(t, e, n) {
|
|
const { get: i, set: r } = Gt(this.prototype, t) ?? { get() {
|
|
return this[e];
|
|
}, set(s) {
|
|
this[e] = s;
|
|
} };
|
|
return { get: i, set(s) {
|
|
const o = i == null ? void 0 : i.call(this);
|
|
r == null || r.call(this, s), this.requestUpdate(t, o, n);
|
|
}, configurable: !0, enumerable: !0 };
|
|
}
|
|
static getPropertyOptions(t) {
|
|
return this.elementProperties.get(t) ?? ot;
|
|
}
|
|
static _$Ei() {
|
|
if (this.hasOwnProperty(k("elementProperties"))) return;
|
|
const t = Ut(this);
|
|
t.finalize(), t.l !== void 0 && (this.l = [...t.l]), this.elementProperties = new Map(t.elementProperties);
|
|
}
|
|
static finalize() {
|
|
if (this.hasOwnProperty(k("finalized"))) return;
|
|
if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(k("properties"))) {
|
|
const e = this.properties, n = [...zt(e), ...Ft(e)];
|
|
for (const i of n) this.createProperty(i, e[i]);
|
|
}
|
|
const t = this[Symbol.metadata];
|
|
if (t !== null) {
|
|
const e = litPropertyMetadata.get(t);
|
|
if (e !== void 0) for (const [n, i] of e) this.elementProperties.set(n, i);
|
|
}
|
|
this._$Eh = /* @__PURE__ */ new Map();
|
|
for (const [e, n] of this.elementProperties) {
|
|
const i = this._$Eu(e, n);
|
|
i !== void 0 && this._$Eh.set(i, e);
|
|
}
|
|
this.elementStyles = this.finalizeStyles(this.styles);
|
|
}
|
|
static finalizeStyles(t) {
|
|
const e = [];
|
|
if (Array.isArray(t)) {
|
|
const n = new Set(t.flat(1 / 0).reverse());
|
|
for (const i of n) e.unshift(rt(i));
|
|
} else t !== void 0 && e.push(rt(t));
|
|
return e;
|
|
}
|
|
static _$Eu(t, e) {
|
|
const n = e.attribute;
|
|
return n === !1 ? void 0 : typeof n == "string" ? n : typeof t == "string" ? t.toLowerCase() : void 0;
|
|
}
|
|
constructor() {
|
|
super(), this._$Ep = void 0, this.isUpdatePending = !1, this.hasUpdated = !1, this._$Em = null, this._$Ev();
|
|
}
|
|
_$Ev() {
|
|
var t;
|
|
this._$ES = new Promise((e) => this.enableUpdating = e), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), (t = this.constructor.l) == null || t.forEach((e) => e(this));
|
|
}
|
|
addController(t) {
|
|
var e;
|
|
(this._$EO ?? (this._$EO = /* @__PURE__ */ new Set())).add(t), this.renderRoot !== void 0 && this.isConnected && ((e = t.hostConnected) == null || e.call(t));
|
|
}
|
|
removeController(t) {
|
|
var e;
|
|
(e = this._$EO) == null || e.delete(t);
|
|
}
|
|
_$E_() {
|
|
const t = /* @__PURE__ */ new Map(), e = this.constructor.elementProperties;
|
|
for (const n of e.keys()) this.hasOwnProperty(n) && (t.set(n, this[n]), delete this[n]);
|
|
t.size > 0 && (this._$Ep = t);
|
|
}
|
|
createRenderRoot() {
|
|
const t = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions);
|
|
return It(t, this.constructor.elementStyles), t;
|
|
}
|
|
connectedCallback() {
|
|
var t;
|
|
this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(!0), (t = this._$EO) == null || t.forEach((e) => {
|
|
var n;
|
|
return (n = e.hostConnected) == null ? void 0 : n.call(e);
|
|
});
|
|
}
|
|
enableUpdating(t) {
|
|
}
|
|
disconnectedCallback() {
|
|
var t;
|
|
(t = this._$EO) == null || t.forEach((e) => {
|
|
var n;
|
|
return (n = e.hostDisconnected) == null ? void 0 : n.call(e);
|
|
});
|
|
}
|
|
attributeChangedCallback(t, e, n) {
|
|
this._$AK(t, n);
|
|
}
|
|
_$ET(t, e) {
|
|
var r;
|
|
const n = this.constructor.elementProperties.get(t), i = this.constructor._$Eu(t, n);
|
|
if (i !== void 0 && n.reflect === !0) {
|
|
const s = (((r = n.converter) == null ? void 0 : r.toAttribute) !== void 0 ? n.converter : X).toAttribute(e, n.type);
|
|
this._$Em = t, s == null ? this.removeAttribute(i) : this.setAttribute(i, s), this._$Em = null;
|
|
}
|
|
}
|
|
_$AK(t, e) {
|
|
var r, s;
|
|
const n = this.constructor, i = n._$Eh.get(t);
|
|
if (i !== void 0 && this._$Em !== i) {
|
|
const o = n.getPropertyOptions(i), l = typeof o.converter == "function" ? { fromAttribute: o.converter } : ((r = o.converter) == null ? void 0 : r.fromAttribute) !== void 0 ? o.converter : X;
|
|
this._$Em = i;
|
|
const c = l.fromAttribute(e, o.type);
|
|
this[i] = c ?? ((s = this._$Ej) == null ? void 0 : s.get(i)) ?? c, this._$Em = null;
|
|
}
|
|
}
|
|
requestUpdate(t, e, n, i = !1, r) {
|
|
var s;
|
|
if (t !== void 0) {
|
|
const o = this.constructor;
|
|
if (i === !1 && (r = this[t]), n ?? (n = o.getPropertyOptions(t)), !((n.hasChanged ?? vt)(r, e) || n.useDefault && n.reflect && r === ((s = this._$Ej) == null ? void 0 : s.get(t)) && !this.hasAttribute(o._$Eu(t, n)))) return;
|
|
this.C(t, e, n);
|
|
}
|
|
this.isUpdatePending === !1 && (this._$ES = this._$EP());
|
|
}
|
|
C(t, e, { useDefault: n, reflect: i, wrapped: r }, s) {
|
|
n && !(this._$Ej ?? (this._$Ej = /* @__PURE__ */ new Map())).has(t) && (this._$Ej.set(t, s ?? e ?? this[t]), r !== !0 || s !== void 0) || (this._$AL.has(t) || (this.hasUpdated || n || (e = void 0), this._$AL.set(t, e)), i === !0 && this._$Em !== t && (this._$Eq ?? (this._$Eq = /* @__PURE__ */ new Set())).add(t));
|
|
}
|
|
async _$EP() {
|
|
this.isUpdatePending = !0;
|
|
try {
|
|
await this._$ES;
|
|
} catch (e) {
|
|
Promise.reject(e);
|
|
}
|
|
const t = this.scheduleUpdate();
|
|
return t != null && await t, !this.isUpdatePending;
|
|
}
|
|
scheduleUpdate() {
|
|
return this.performUpdate();
|
|
}
|
|
performUpdate() {
|
|
var n;
|
|
if (!this.isUpdatePending) return;
|
|
if (!this.hasUpdated) {
|
|
if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) {
|
|
for (const [r, s] of this._$Ep) this[r] = s;
|
|
this._$Ep = void 0;
|
|
}
|
|
const i = this.constructor.elementProperties;
|
|
if (i.size > 0) for (const [r, s] of i) {
|
|
const { wrapped: o } = s, l = this[r];
|
|
o !== !0 || this._$AL.has(r) || l === void 0 || this.C(r, void 0, s, l);
|
|
}
|
|
}
|
|
let t = !1;
|
|
const e = this._$AL;
|
|
try {
|
|
t = this.shouldUpdate(e), t ? (this.willUpdate(e), (n = this._$EO) == null || n.forEach((i) => {
|
|
var r;
|
|
return (r = i.hostUpdate) == null ? void 0 : r.call(i);
|
|
}), this.update(e)) : this._$EM();
|
|
} catch (i) {
|
|
throw t = !1, this._$EM(), i;
|
|
}
|
|
t && this._$AE(e);
|
|
}
|
|
willUpdate(t) {
|
|
}
|
|
_$AE(t) {
|
|
var e;
|
|
(e = this._$EO) == null || e.forEach((n) => {
|
|
var i;
|
|
return (i = n.hostUpdated) == null ? void 0 : i.call(n);
|
|
}), this.hasUpdated || (this.hasUpdated = !0, this.firstUpdated(t)), this.updated(t);
|
|
}
|
|
_$EM() {
|
|
this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = !1;
|
|
}
|
|
get updateComplete() {
|
|
return this.getUpdateComplete();
|
|
}
|
|
getUpdateComplete() {
|
|
return this._$ES;
|
|
}
|
|
shouldUpdate(t) {
|
|
return !0;
|
|
}
|
|
update(t) {
|
|
this._$Eq && (this._$Eq = this._$Eq.forEach((e) => this._$ET(e, this[e]))), this._$EM();
|
|
}
|
|
updated(t) {
|
|
}
|
|
firstUpdated(t) {
|
|
}
|
|
};
|
|
w.elementStyles = [], w.shadowRootOptions = { mode: "open" }, w[k("elementProperties")] = /* @__PURE__ */ new Map(), w[k("finalized")] = /* @__PURE__ */ new Map(), W == null || W({ ReactiveElement: w }), (v.reactiveElementVersions ?? (v.reactiveElementVersions = [])).push("2.1.2");
|
|
/**
|
|
* @license
|
|
* Copyright 2017 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const V = globalThis, at = (a) => a, D = V.trustedTypes, lt = D ? D.createPolicy("lit-html", { createHTML: (a) => a }) : void 0, bt = "$lit$", f = `lit$${Math.random().toFixed(9).slice(2)}$`, $t = "?" + f, Mt = `<${$t}>`, x = document, z = () => x.createComment(""), F = (a) => a === null || typeof a != "object" && typeof a != "function", it = Array.isArray, Dt = (a) => it(a) || typeof (a == null ? void 0 : a[Symbol.iterator]) == "function", q = `[
|
|
\f\r]`, I = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, ct = /-->/g, ut = />/g, b = RegExp(`>|${q}(?:([^\\s"'>=/]+)(${q}*=${q}*(?:[^
|
|
\f\r"'\`<>=]|("|')|))|$)`, "g"), ht = /'/g, dt = /"/g, yt = /^(?:script|style|textarea|title)$/i, Rt = (a) => (t, ...e) => ({ _$litType$: a, strings: t, values: e }), u = Rt(1), E = Symbol.for("lit-noChange"), p = Symbol.for("lit-nothing"), pt = /* @__PURE__ */ new WeakMap(), $ = x.createTreeWalker(x, 129);
|
|
function xt(a, t) {
|
|
if (!it(a) || !a.hasOwnProperty("raw")) throw Error("invalid template strings array");
|
|
return lt !== void 0 ? lt.createHTML(t) : t;
|
|
}
|
|
const jt = (a, t) => {
|
|
const e = a.length - 1, n = [];
|
|
let i, r = t === 2 ? "<svg>" : t === 3 ? "<math>" : "", s = I;
|
|
for (let o = 0; o < e; o++) {
|
|
const l = a[o];
|
|
let c, h, d = -1, _ = 0;
|
|
for (; _ < l.length && (s.lastIndex = _, h = s.exec(l), h !== null); ) _ = s.lastIndex, s === I ? h[1] === "!--" ? s = ct : h[1] !== void 0 ? s = ut : h[2] !== void 0 ? (yt.test(h[2]) && (i = RegExp("</" + h[2], "g")), s = b) : h[3] !== void 0 && (s = b) : s === b ? h[0] === ">" ? (s = i ?? I, d = -1) : h[1] === void 0 ? d = -2 : (d = s.lastIndex - h[2].length, c = h[1], s = h[3] === void 0 ? b : h[3] === '"' ? dt : ht) : s === dt || s === ht ? s = b : s === ct || s === ut ? s = I : (s = b, i = void 0);
|
|
const m = s === b && a[o + 1].startsWith("/>") ? " " : "";
|
|
r += s === I ? l + Mt : d >= 0 ? (n.push(c), l.slice(0, d) + bt + l.slice(d) + f + m) : l + f + (d === -2 ? o : m);
|
|
}
|
|
return [xt(a, r + (a[e] || "<?>") + (t === 2 ? "</svg>" : t === 3 ? "</math>" : "")), n];
|
|
};
|
|
class U {
|
|
constructor({ strings: t, _$litType$: e }, n) {
|
|
let i;
|
|
this.parts = [];
|
|
let r = 0, s = 0;
|
|
const o = t.length - 1, l = this.parts, [c, h] = jt(t, e);
|
|
if (this.el = U.createElement(c, n), $.currentNode = this.el.content, e === 2 || e === 3) {
|
|
const d = this.el.content.firstChild;
|
|
d.replaceWith(...d.childNodes);
|
|
}
|
|
for (; (i = $.nextNode()) !== null && l.length < o; ) {
|
|
if (i.nodeType === 1) {
|
|
if (i.hasAttributes()) for (const d of i.getAttributeNames()) if (d.endsWith(bt)) {
|
|
const _ = h[s++], m = i.getAttribute(d).split(f), g = /([.?@])?(.*)/.exec(_);
|
|
l.push({ type: 1, index: r, name: g[2], strings: m, ctor: g[1] === "." ? Wt : g[1] === "?" ? qt : g[1] === "@" ? Yt : R }), i.removeAttribute(d);
|
|
} else d.startsWith(f) && (l.push({ type: 6, index: r }), i.removeAttribute(d));
|
|
if (yt.test(i.tagName)) {
|
|
const d = i.textContent.split(f), _ = d.length - 1;
|
|
if (_ > 0) {
|
|
i.textContent = D ? D.emptyScript : "";
|
|
for (let m = 0; m < _; m++) i.append(d[m], z()), $.nextNode(), l.push({ type: 2, index: ++r });
|
|
i.append(d[_], z());
|
|
}
|
|
}
|
|
} else if (i.nodeType === 8) if (i.data === $t) l.push({ type: 2, index: r });
|
|
else {
|
|
let d = -1;
|
|
for (; (d = i.data.indexOf(f, d + 1)) !== -1; ) l.push({ type: 7, index: r }), d += f.length - 1;
|
|
}
|
|
r++;
|
|
}
|
|
}
|
|
static createElement(t, e) {
|
|
const n = x.createElement("template");
|
|
return n.innerHTML = t, n;
|
|
}
|
|
}
|
|
function T(a, t, e = a, n) {
|
|
var s, o;
|
|
if (t === E) return t;
|
|
let i = n !== void 0 ? (s = e._$Co) == null ? void 0 : s[n] : e._$Cl;
|
|
const r = F(t) ? void 0 : t._$litDirective$;
|
|
return (i == null ? void 0 : i.constructor) !== r && ((o = i == null ? void 0 : i._$AO) == null || o.call(i, !1), r === void 0 ? i = void 0 : (i = new r(a), i._$AT(a, e, n)), n !== void 0 ? (e._$Co ?? (e._$Co = []))[n] = i : e._$Cl = i), i !== void 0 && (t = T(a, i._$AS(a, t.values), i, n)), t;
|
|
}
|
|
class Bt {
|
|
constructor(t, e) {
|
|
this._$AV = [], this._$AN = void 0, this._$AD = t, this._$AM = e;
|
|
}
|
|
get parentNode() {
|
|
return this._$AM.parentNode;
|
|
}
|
|
get _$AU() {
|
|
return this._$AM._$AU;
|
|
}
|
|
u(t) {
|
|
const { el: { content: e }, parts: n } = this._$AD, i = ((t == null ? void 0 : t.creationScope) ?? x).importNode(e, !0);
|
|
$.currentNode = i;
|
|
let r = $.nextNode(), s = 0, o = 0, l = n[0];
|
|
for (; l !== void 0; ) {
|
|
if (s === l.index) {
|
|
let c;
|
|
l.type === 2 ? c = new L(r, r.nextSibling, this, t) : l.type === 1 ? c = new l.ctor(r, l.name, l.strings, this, t) : l.type === 6 && (c = new Zt(r, this, t)), this._$AV.push(c), l = n[++o];
|
|
}
|
|
s !== (l == null ? void 0 : l.index) && (r = $.nextNode(), s++);
|
|
}
|
|
return $.currentNode = x, i;
|
|
}
|
|
p(t) {
|
|
let e = 0;
|
|
for (const n of this._$AV) n !== void 0 && (n.strings !== void 0 ? (n._$AI(t, n, e), e += n.strings.length - 2) : n._$AI(t[e])), e++;
|
|
}
|
|
}
|
|
class L {
|
|
get _$AU() {
|
|
var t;
|
|
return ((t = this._$AM) == null ? void 0 : t._$AU) ?? this._$Cv;
|
|
}
|
|
constructor(t, e, n, i) {
|
|
this.type = 2, this._$AH = p, this._$AN = void 0, this._$AA = t, this._$AB = e, this._$AM = n, this.options = i, this._$Cv = (i == null ? void 0 : i.isConnected) ?? !0;
|
|
}
|
|
get parentNode() {
|
|
let t = this._$AA.parentNode;
|
|
const e = this._$AM;
|
|
return e !== void 0 && (t == null ? void 0 : t.nodeType) === 11 && (t = e.parentNode), t;
|
|
}
|
|
get startNode() {
|
|
return this._$AA;
|
|
}
|
|
get endNode() {
|
|
return this._$AB;
|
|
}
|
|
_$AI(t, e = this) {
|
|
t = T(this, t, e), F(t) ? t === p || t == null || t === "" ? (this._$AH !== p && this._$AR(), this._$AH = p) : t !== this._$AH && t !== E && this._(t) : t._$litType$ !== void 0 ? this.$(t) : t.nodeType !== void 0 ? this.T(t) : Dt(t) ? this.k(t) : this._(t);
|
|
}
|
|
O(t) {
|
|
return this._$AA.parentNode.insertBefore(t, this._$AB);
|
|
}
|
|
T(t) {
|
|
this._$AH !== t && (this._$AR(), this._$AH = this.O(t));
|
|
}
|
|
_(t) {
|
|
this._$AH !== p && F(this._$AH) ? this._$AA.nextSibling.data = t : this.T(x.createTextNode(t)), this._$AH = t;
|
|
}
|
|
$(t) {
|
|
var r;
|
|
const { values: e, _$litType$: n } = t, i = typeof n == "number" ? this._$AC(t) : (n.el === void 0 && (n.el = U.createElement(xt(n.h, n.h[0]), this.options)), n);
|
|
if (((r = this._$AH) == null ? void 0 : r._$AD) === i) this._$AH.p(e);
|
|
else {
|
|
const s = new Bt(i, this), o = s.u(this.options);
|
|
s.p(e), this.T(o), this._$AH = s;
|
|
}
|
|
}
|
|
_$AC(t) {
|
|
let e = pt.get(t.strings);
|
|
return e === void 0 && pt.set(t.strings, e = new U(t)), e;
|
|
}
|
|
k(t) {
|
|
it(this._$AH) || (this._$AH = [], this._$AR());
|
|
const e = this._$AH;
|
|
let n, i = 0;
|
|
for (const r of t) i === e.length ? e.push(n = new L(this.O(z()), this.O(z()), this, this.options)) : n = e[i], n._$AI(r), i++;
|
|
i < e.length && (this._$AR(n && n._$AB.nextSibling, i), e.length = i);
|
|
}
|
|
_$AR(t = this._$AA.nextSibling, e) {
|
|
var n;
|
|
for ((n = this._$AP) == null ? void 0 : n.call(this, !1, !0, e); t !== this._$AB; ) {
|
|
const i = at(t).nextSibling;
|
|
at(t).remove(), t = i;
|
|
}
|
|
}
|
|
setConnected(t) {
|
|
var e;
|
|
this._$AM === void 0 && (this._$Cv = t, (e = this._$AP) == null || e.call(this, t));
|
|
}
|
|
}
|
|
class R {
|
|
get tagName() {
|
|
return this.element.tagName;
|
|
}
|
|
get _$AU() {
|
|
return this._$AM._$AU;
|
|
}
|
|
constructor(t, e, n, i, r) {
|
|
this.type = 1, this._$AH = p, this._$AN = void 0, this.element = t, this.name = e, this._$AM = i, this.options = r, n.length > 2 || n[0] !== "" || n[1] !== "" ? (this._$AH = Array(n.length - 1).fill(new String()), this.strings = n) : this._$AH = p;
|
|
}
|
|
_$AI(t, e = this, n, i) {
|
|
const r = this.strings;
|
|
let s = !1;
|
|
if (r === void 0) t = T(this, t, e, 0), s = !F(t) || t !== this._$AH && t !== E, s && (this._$AH = t);
|
|
else {
|
|
const o = t;
|
|
let l, c;
|
|
for (t = r[0], l = 0; l < r.length - 1; l++) c = T(this, o[n + l], e, l), c === E && (c = this._$AH[l]), s || (s = !F(c) || c !== this._$AH[l]), c === p ? t = p : t !== p && (t += (c ?? "") + r[l + 1]), this._$AH[l] = c;
|
|
}
|
|
s && !i && this.j(t);
|
|
}
|
|
j(t) {
|
|
t === p ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, t ?? "");
|
|
}
|
|
}
|
|
class Wt extends R {
|
|
constructor() {
|
|
super(...arguments), this.type = 3;
|
|
}
|
|
j(t) {
|
|
this.element[this.name] = t === p ? void 0 : t;
|
|
}
|
|
}
|
|
class qt extends R {
|
|
constructor() {
|
|
super(...arguments), this.type = 4;
|
|
}
|
|
j(t) {
|
|
this.element.toggleAttribute(this.name, !!t && t !== p);
|
|
}
|
|
}
|
|
class Yt extends R {
|
|
constructor(t, e, n, i, r) {
|
|
super(t, e, n, i, r), this.type = 5;
|
|
}
|
|
_$AI(t, e = this) {
|
|
if ((t = T(this, t, e, 0) ?? p) === E) return;
|
|
const n = this._$AH, i = t === p && n !== p || t.capture !== n.capture || t.once !== n.once || t.passive !== n.passive, r = t !== p && (n === p || i);
|
|
i && this.element.removeEventListener(this.name, this, n), r && this.element.addEventListener(this.name, this, t), this._$AH = t;
|
|
}
|
|
handleEvent(t) {
|
|
var e;
|
|
typeof this._$AH == "function" ? this._$AH.call(((e = this.options) == null ? void 0 : e.host) ?? this.element, t) : this._$AH.handleEvent(t);
|
|
}
|
|
}
|
|
class Zt {
|
|
constructor(t, e, n) {
|
|
this.element = t, this.type = 6, this._$AN = void 0, this._$AM = e, this.options = n;
|
|
}
|
|
get _$AU() {
|
|
return this._$AM._$AU;
|
|
}
|
|
_$AI(t) {
|
|
T(this, t);
|
|
}
|
|
}
|
|
const Y = V.litHtmlPolyfillSupport;
|
|
Y == null || Y(U, L), (V.litHtmlVersions ?? (V.litHtmlVersions = [])).push("3.3.3");
|
|
const Jt = (a, t, e) => {
|
|
const n = (e == null ? void 0 : e.renderBefore) ?? t;
|
|
let i = n._$litPart$;
|
|
if (i === void 0) {
|
|
const r = (e == null ? void 0 : e.renderBefore) ?? null;
|
|
n._$litPart$ = i = new L(t.insertBefore(z(), r), r, void 0, e ?? {});
|
|
}
|
|
return i._$AI(a), i;
|
|
};
|
|
/**
|
|
* @license
|
|
* Copyright 2017 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
const y = globalThis;
|
|
class G extends w {
|
|
constructor() {
|
|
super(...arguments), this.renderOptions = { host: this }, this._$Do = void 0;
|
|
}
|
|
createRenderRoot() {
|
|
var e;
|
|
const t = super.createRenderRoot();
|
|
return (e = this.renderOptions).renderBefore ?? (e.renderBefore = t.firstChild), t;
|
|
}
|
|
update(t) {
|
|
const e = this.render();
|
|
this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(t), this._$Do = Jt(e, this.renderRoot, this.renderOptions);
|
|
}
|
|
connectedCallback() {
|
|
var t;
|
|
super.connectedCallback(), (t = this._$Do) == null || t.setConnected(!0);
|
|
}
|
|
disconnectedCallback() {
|
|
var t;
|
|
super.disconnectedCallback(), (t = this._$Do) == null || t.setConnected(!1);
|
|
}
|
|
render() {
|
|
return E;
|
|
}
|
|
}
|
|
var _t;
|
|
G._$litElement$ = !0, G.finalized = !0, (_t = y.litElementHydrateSupport) == null || _t.call(y, { LitElement: G });
|
|
const Z = y.litElementPolyfillSupport;
|
|
Z == null || Z({ LitElement: G });
|
|
(y.litElementVersions ?? (y.litElementVersions = [])).push("4.2.2");
|
|
const mt = [
|
|
["more-info", "More info"],
|
|
["navigate", "Navigate"],
|
|
["url", "URL"],
|
|
["call-service", "Call service"],
|
|
["assist", "Assist"],
|
|
["none", "None"]
|
|
];
|
|
class K extends G {
|
|
setConfig(t) {
|
|
this._config = {
|
|
...S,
|
|
...t
|
|
}, this._openSections || (this._openSections = {
|
|
general: !0,
|
|
preset: !0,
|
|
grouping: !1,
|
|
filters: !1,
|
|
groupTitleOverrides: !1,
|
|
sorting: !1,
|
|
appearance: !1,
|
|
actions: !1
|
|
});
|
|
}
|
|
render() {
|
|
if (!this._config) return u``;
|
|
const t = this._config.preset || "spoolman";
|
|
return u`
|
|
<div class="editor">
|
|
${this.renderExpandableSection(
|
|
"general",
|
|
"General",
|
|
this.renderGeneralSection(t),
|
|
!0
|
|
)}
|
|
|
|
${t === "spoolman" ? this.renderSpoolmanOptions() : ""}
|
|
${t === "custom_attributes" ? this.renderCustomAttributeOptions() : ""}
|
|
${t === "custom_entities" ? this.renderCustomEntityOptions() : ""}
|
|
${t === "custom_label" ? this.renderCustomLabelOptions() : ""}
|
|
|
|
${this.renderExpandableSection(
|
|
"appearance",
|
|
"Appearance",
|
|
this.renderAppearanceOptions(),
|
|
!0
|
|
)}
|
|
|
|
${this.renderExpandableSection(
|
|
"actions",
|
|
"Actions",
|
|
this.renderActionOptions(),
|
|
!1
|
|
)}
|
|
</div>
|
|
`;
|
|
}
|
|
toggleSection(t) {
|
|
var e;
|
|
this._openSections = {
|
|
...this._openSections || {},
|
|
[t]: !((e = this._openSections) != null && e[t])
|
|
};
|
|
}
|
|
renderExpandableSection(t, e, n, i = !1) {
|
|
var s;
|
|
const r = ((s = this._openSections) == null ? void 0 : s[t]) ?? i;
|
|
return u`
|
|
<div class="expandable-section">
|
|
<div
|
|
class="expandable-header"
|
|
@click=${() => this.toggleSection(t)}
|
|
>
|
|
<span>${e}</span>
|
|
<ha-icon icon=${r ? "mdi:chevron-up" : "mdi:chevron-down"}></ha-icon>
|
|
</div>
|
|
|
|
${r ? u`
|
|
<div class="expandable-content">
|
|
${n}
|
|
</div>
|
|
` : ""}
|
|
</div>
|
|
`;
|
|
}
|
|
renderGeneralSection(t) {
|
|
return u`
|
|
<div class="section-title">General</div>
|
|
|
|
${this.renderSelect(
|
|
t,
|
|
"Choose Preset",
|
|
[
|
|
["spoolman", "Spoolman"],
|
|
["custom_attributes", "Custom: Attributes"],
|
|
["custom_entities", "Custom: Multiple entities"],
|
|
["custom_label", "Custom: HA Label"]
|
|
],
|
|
(e) => this.updatePreset(e)
|
|
)}
|
|
|
|
${this.renderPresetHint(t)}
|
|
|
|
${this.renderTextField("title", "Title")}
|
|
`;
|
|
}
|
|
renderSpoolmanOptions() {
|
|
return u`
|
|
${this.renderExpandableSection(
|
|
"grouping",
|
|
"Grouping",
|
|
u`
|
|
${this.renderSelect(
|
|
this._config.group_by || "material",
|
|
"Group by",
|
|
[
|
|
["material", "Material"],
|
|
["color", "Color"],
|
|
["vendor", "Vendor"],
|
|
["none", "Don't group"]
|
|
],
|
|
(t) => this.updateGroupBy(t)
|
|
)}
|
|
|
|
${this.renderGroupingDetails("Spool count")}
|
|
${this.renderGroupFilters()}
|
|
${this.renderGroupTitleOverrides()}
|
|
`,
|
|
!0
|
|
)}
|
|
|
|
${this.renderExpandableSection(
|
|
"sorting",
|
|
"Sorting",
|
|
u`
|
|
${this.renderSelect(
|
|
this._config.sort_by || "remaining_weight",
|
|
"Sort by",
|
|
[
|
|
["remaining_weight", "Remaining weight"],
|
|
["filament_name", "Filament name"],
|
|
["filament_material", "Material"],
|
|
["filament_vendor_name", "Vendor"],
|
|
["filament_color_hex", "Color"]
|
|
],
|
|
(t) => this.updateConfigValue("sort_by", t)
|
|
)}
|
|
|
|
${this.renderSortDirection()}
|
|
|
|
${this.renderNumberField("max_weight", "Max weight fallback")}
|
|
${this.renderHint("Used only if no filament weight is available.")}
|
|
|
|
${this.renderSwitch("hide_archived", "Hide archived spools")}
|
|
${this.renderSwitch("use_filament_color", "Use filament color")}
|
|
`,
|
|
!0
|
|
)}
|
|
`;
|
|
}
|
|
renderCustomAttributeOptions() {
|
|
return u`
|
|
${this.renderExpandableSection(
|
|
"preset",
|
|
"Custom Attributes",
|
|
u`
|
|
${this.renderEntityPicker(
|
|
this._config.custom_attribute_entities || [],
|
|
"Entities with attributes",
|
|
(t) => this.updateConfigValue("custom_attribute_entities", t),
|
|
!0
|
|
)}
|
|
|
|
${this.renderHint(
|
|
"Each selected entity should provide attributes like group, vendor, color, max_value and unit."
|
|
)}
|
|
|
|
${this.renderCustomDefaults()}
|
|
`,
|
|
!0
|
|
)}
|
|
|
|
${this.renderCustomSharedOptions()}
|
|
`;
|
|
}
|
|
renderCustomEntityOptions() {
|
|
const t = this._config.custom_items || [];
|
|
return u`
|
|
${this.renderExpandableSection(
|
|
"preset",
|
|
"Custom Multiple Entities",
|
|
u`
|
|
${this.renderHint(
|
|
"Create one item per spool. Each item can use separate entities for value, max value, color, group and vendor."
|
|
)}
|
|
|
|
${t.map((e, n) => this.renderCustomItem(e, n))}
|
|
|
|
<button
|
|
class="editor-button"
|
|
type="button"
|
|
@click=${() => this.addCustomItem()}
|
|
>
|
|
<ha-icon icon="mdi:plus"></ha-icon>
|
|
Add spool
|
|
</button>
|
|
|
|
${this.renderCustomDefaults()}
|
|
`,
|
|
!0
|
|
)}
|
|
|
|
${this.renderCustomSharedOptions()}
|
|
`;
|
|
}
|
|
renderCustomItem(t, e) {
|
|
return u`
|
|
<div class="custom-item">
|
|
<div class="section-title">Spool ${e + 1}</div>
|
|
|
|
${this.renderTextForm(
|
|
t.name || "",
|
|
"Name",
|
|
(n) => this.updateCustomItem(e, "name", n)
|
|
)}
|
|
|
|
${this.renderEntityPicker(
|
|
t.value_entity || "",
|
|
"Value entity",
|
|
(n) => this.updateCustomItem(e, "value_entity", n)
|
|
)}
|
|
|
|
${this.renderEntityPicker(
|
|
t.max_entity || "",
|
|
"Max entity",
|
|
(n) => this.updateCustomItem(e, "max_entity", n)
|
|
)}
|
|
|
|
${this.renderEntityPicker(
|
|
t.color_entity || "",
|
|
"Color entity",
|
|
(n) => this.updateCustomItem(e, "color_entity", n)
|
|
)}
|
|
|
|
${this.renderEntityPicker(
|
|
t.group_entity || "",
|
|
"Group entity",
|
|
(n) => this.updateCustomItem(e, "group_entity", n)
|
|
)}
|
|
|
|
${this.renderEntityPicker(
|
|
t.vendor_entity || "",
|
|
"Vendor entity",
|
|
(n) => this.updateCustomItem(e, "vendor_entity", n)
|
|
)}
|
|
|
|
${this.renderEntityPicker(
|
|
t.name_entity || "",
|
|
"Name entity",
|
|
(n) => this.updateCustomItem(e, "name_entity", n)
|
|
)}
|
|
|
|
${this.renderTextForm(
|
|
t.unit || this._config.custom_unit || "g",
|
|
"Unit",
|
|
(n) => this.updateCustomItem(e, "unit", n)
|
|
)}
|
|
|
|
<button
|
|
class="editor-button danger"
|
|
type="button"
|
|
@click=${() => this.removeCustomItem(e)}
|
|
>
|
|
<ha-icon icon="mdi:delete"></ha-icon>
|
|
Remove spool
|
|
</button>
|
|
</div>
|
|
`;
|
|
}
|
|
renderCustomLabelOptions() {
|
|
return u`
|
|
${this.renderExpandableSection(
|
|
"preset",
|
|
"Custom HA Label",
|
|
u`
|
|
${this.renderHint(
|
|
"All entities with the selected Home Assistant label will be used automatically. They should provide the same attributes as Custom Attributes."
|
|
)}
|
|
|
|
${this.renderLabelPicker(
|
|
this._config.custom_label_id || "",
|
|
"HA Label",
|
|
(t) => this.updateConfigValue("custom_label_id", t)
|
|
)}
|
|
|
|
${this.renderCustomDefaults()}
|
|
`,
|
|
!0
|
|
)}
|
|
|
|
${this.renderCustomSharedOptions()}
|
|
`;
|
|
}
|
|
renderCustomDefaults() {
|
|
return u`
|
|
${this.renderTextForm(
|
|
this._config.custom_max_value ?? 1e3,
|
|
"Default max value",
|
|
(t) => this.updateConfigValue("custom_max_value", Number(t))
|
|
)}
|
|
|
|
${this.renderHint("Used when an item does not provide its own maximum value.")}
|
|
|
|
${this.renderTextForm(
|
|
this._config.custom_unit || "g",
|
|
"Default unit",
|
|
(t) => this.updateConfigValue("custom_unit", t)
|
|
)}
|
|
`;
|
|
}
|
|
renderCustomSharedOptions() {
|
|
return u`
|
|
${this.renderExpandableSection(
|
|
"grouping",
|
|
"Grouping",
|
|
u`
|
|
${this.renderSelect(
|
|
this._config.group_by || "material",
|
|
"Group by",
|
|
[
|
|
["material", "Group"],
|
|
["color", "Color"],
|
|
["vendor", "Vendor"],
|
|
["none", "Don't group"]
|
|
],
|
|
(t) => this.updateGroupBy(t)
|
|
)}
|
|
|
|
${this.renderGroupingDetails("Item count")}
|
|
${this.renderGroupFilters()}
|
|
${this.renderGroupTitleOverrides()}
|
|
`,
|
|
!0
|
|
)}
|
|
|
|
${this.renderExpandableSection(
|
|
"sorting",
|
|
"Sorting",
|
|
u`
|
|
${this.renderSelect(
|
|
this._config.sort_by || "remaining_weight",
|
|
"Sort by",
|
|
[
|
|
["remaining_weight", "Value"],
|
|
["filament_name", "Name"],
|
|
["filament_material", "Group"],
|
|
["filament_vendor_name", "Vendor"],
|
|
["filament_color_hex", "Color"]
|
|
],
|
|
(t) => this.updateConfigValue("sort_by", t)
|
|
)}
|
|
|
|
${this.renderSortDirection()}
|
|
|
|
${this.renderSwitch("use_filament_color", "Use item color")}
|
|
`,
|
|
!0
|
|
)}
|
|
`;
|
|
}
|
|
renderGroupFilters() {
|
|
var r, s;
|
|
if (this._config.group_by === "none")
|
|
return u``;
|
|
const t = this.getAvailableGroups();
|
|
if (!t.length)
|
|
return this.renderExpandableSection(
|
|
"filters",
|
|
"Filters",
|
|
u`
|
|
${this.renderHint(
|
|
"No filter values found yet. Values will appear once matching entities are available."
|
|
)}
|
|
`,
|
|
!1
|
|
);
|
|
const e = Array.isArray((r = this._config.filters) == null ? void 0 : r.include) ? this._config.filters.include : [], n = Array.isArray((s = this._config.filters) == null ? void 0 : s.exclude) ? this._config.filters.exclude : [], i = this.getFilterTypeLabel();
|
|
return this.renderExpandableSection(
|
|
"filters",
|
|
"Filters",
|
|
u`
|
|
${this.renderHint(
|
|
`Filter the card by the currently selected grouping: ${i}.`
|
|
)}
|
|
|
|
${this.renderMultiSelect(
|
|
e,
|
|
`Include only ${i}`,
|
|
t.map((o) => [o, o]),
|
|
(o) => this.updateFilterValues("include", o)
|
|
)}
|
|
|
|
${this.renderHint(
|
|
"When values are selected here, only matching items are displayed."
|
|
)}
|
|
|
|
${this.renderMultiSelect(
|
|
n,
|
|
`Exclude ${i}`,
|
|
t.map((o) => [o, o]),
|
|
(o) => this.updateFilterValues("exclude", o)
|
|
)}
|
|
|
|
${this.renderHint(
|
|
"Excluded values are hidden. The visual editor automatically removes them from the include list."
|
|
)}
|
|
`,
|
|
!1
|
|
);
|
|
}
|
|
renderGroupTitleOverrides() {
|
|
if (this._config.group_by === "none") return u``;
|
|
const t = this.getAvailableGroups();
|
|
return t.length ? this.renderExpandableSection(
|
|
"groupTitleOverrides",
|
|
"Group Title Overrides",
|
|
u`
|
|
${this.renderHint(
|
|
"Configure individual icons, colors and actions for specific group titles."
|
|
)}
|
|
|
|
${t.map((e) => this.renderGroupTitleOverride(e))}
|
|
`,
|
|
!1
|
|
) : this.renderExpandableSection(
|
|
"groupTitleOverrides",
|
|
"Group Title Overrides",
|
|
u`
|
|
${this.renderHint(
|
|
"No groups found yet. Groups will appear here once matching entities are available."
|
|
)}
|
|
`,
|
|
!1
|
|
);
|
|
}
|
|
getFilterTypeLabel() {
|
|
return {
|
|
material: "materials",
|
|
vendor: "vendors",
|
|
color: "colors"
|
|
}[this._config.group_by] || "groups";
|
|
}
|
|
getAvailableGroups() {
|
|
if (!this.hass || !this._config || this._config.group_by === "none")
|
|
return [];
|
|
const t = this._config.preset || "spoolman", e = this.getPreviewItemsForGroups(t);
|
|
let n = [...new Set(
|
|
e.map((r) => C(this._config, r)).filter(Boolean)
|
|
)];
|
|
n = gt(this._config, n, e);
|
|
const i = Array.isArray(this._config.group_order) ? this._config.group_order : [];
|
|
return [
|
|
...i.filter((r) => n.includes(r)),
|
|
...n.filter((r) => !i.includes(r))
|
|
];
|
|
}
|
|
getPreviewItemsForGroups(t) {
|
|
return t === "custom_entities" ? this.getCustomEntityPreviewItems() : t === "custom_attributes" || t === "custom_label" ? this.getCustomAttributePreviewItems(t) : this.getSpoolmanPreviewItems();
|
|
}
|
|
getSpoolmanPreviewItems() {
|
|
return Object.entries(this.hass.states).map(([t, e]) => ({ entity_id: t, state: e })).filter(({ state: t }) => {
|
|
var e;
|
|
return (e = t.attributes) == null ? void 0 : e.filament_material;
|
|
});
|
|
}
|
|
getCustomAttributePreviewItems(t) {
|
|
const e = t === "custom_label" ? this.getEntitiesFromSelectedLabel() : this._config.custom_attribute_entities || [], n = Number(this._config.custom_max_value || 1e3), i = this._config.custom_unit || "g";
|
|
return e.map((r) => {
|
|
const s = this.hass.states[r];
|
|
if (!s) return null;
|
|
const o = s.attributes || {}, l = Number(o.value ?? o.remaining_weight ?? s.state);
|
|
return Number.isNaN(l) ? null : this.createPreviewItem({
|
|
entity_id: r,
|
|
value: l,
|
|
max: Number(o.max_value ?? o.max ?? n),
|
|
name: o.name || o.friendly_name || r,
|
|
group: o.group || o.material || "Custom",
|
|
vendor: o.vendor || "",
|
|
color: o.color || o.filament_color_hex,
|
|
unit: o.unit || i
|
|
});
|
|
}).filter(Boolean);
|
|
}
|
|
getCustomEntityPreviewItems() {
|
|
const t = this._config.custom_items || [], e = Number(this._config.custom_max_value || 1e3), n = this._config.custom_unit || "g";
|
|
return t.map((i, r) => {
|
|
var m, g, N, O, P, H;
|
|
const s = this.hass.states[i.value_entity];
|
|
if (!s) return null;
|
|
const o = Number(s.state);
|
|
if (Number.isNaN(o)) return null;
|
|
const l = i.max_entity ? Number(((m = this.hass.states[i.max_entity]) == null ? void 0 : m.state) ?? e) : Number(i.max ?? i.max_value ?? e), c = i.color_entity ? (g = this.hass.states[i.color_entity]) == null ? void 0 : g.state : i.color, h = i.group_entity ? (N = this.hass.states[i.group_entity]) == null ? void 0 : N.state : i.group, d = i.vendor_entity ? (O = this.hass.states[i.vendor_entity]) == null ? void 0 : O.state : i.vendor, _ = i.name_entity ? (P = this.hass.states[i.name_entity]) == null ? void 0 : P.state : i.name;
|
|
return this.createPreviewItem({
|
|
entity_id: i.value_entity || `custom_item_${r}`,
|
|
value: o,
|
|
max: Number.isNaN(l) ? e : l,
|
|
name: _ || ((H = s.attributes) == null ? void 0 : H.friendly_name) || i.value_entity,
|
|
group: h || "Custom",
|
|
vendor: d || "",
|
|
color: c,
|
|
unit: i.unit || n
|
|
});
|
|
}).filter(Boolean);
|
|
}
|
|
getEntitiesFromSelectedLabel() {
|
|
var e;
|
|
const t = this._config.custom_label_id;
|
|
return !t || !((e = this.hass) != null && e.entities) ? [] : Object.entries(this.hass.entities).filter(([, n]) => {
|
|
var i;
|
|
return (i = n.labels) == null ? void 0 : i.includes(t);
|
|
}).map(([n]) => n);
|
|
}
|
|
createPreviewItem({ entity_id: t, value: e, max: n, name: i, group: r, vendor: s, color: o, unit: l }) {
|
|
return {
|
|
entity_id: t,
|
|
state: {
|
|
state: String(e),
|
|
attributes: {
|
|
friendly_name: i,
|
|
remaining_weight: e,
|
|
filament_weight: n,
|
|
filament_material: r,
|
|
filament_name: i,
|
|
filament_vendor_name: s,
|
|
filament_color_hex: o,
|
|
archived: !1,
|
|
custom_unit: l
|
|
}
|
|
}
|
|
};
|
|
}
|
|
renderGroupTitleOverride(t) {
|
|
var i, r;
|
|
const e = ((i = this._config.group_title_icons) == null ? void 0 : i[t]) || "", n = ((r = this._config.group_title_colors) == null ? void 0 : r[t]) || "";
|
|
return u`
|
|
<div class="custom-item">
|
|
<div class="section-title">${t}</div>
|
|
|
|
${this.renderIconPicker(
|
|
e,
|
|
"Group title icon",
|
|
(s) => this.updateGroupTitleValue("group_title_icons", t, s)
|
|
)}
|
|
|
|
${this.renderTextForm(
|
|
n,
|
|
"Group title color",
|
|
(s) => this.updateGroupTitleValue("group_title_colors", t, s)
|
|
)}
|
|
|
|
${this.renderGroupTitleActionFields(t, "tap_action", "Tap action")}
|
|
${this.renderGroupTitleActionFields(t, "double_tap_action", "Double tap action")}
|
|
${this.renderGroupTitleActionFields(t, "hold_action", "Hold action")}
|
|
</div>
|
|
`;
|
|
}
|
|
renderGroupingDetails(t) {
|
|
return this._config.group_by === "none" ? u`` : u`
|
|
${this.renderHint(this.groupOrderHint())}
|
|
|
|
<textarea
|
|
.value=${this.groupOrderValue()}
|
|
@input=${this.handleGroupOrderChanged}
|
|
></textarea>
|
|
|
|
${this.renderSelect(
|
|
this._config.group_sort_by || "name",
|
|
"Group sort by",
|
|
[
|
|
["name", "Name"],
|
|
["total_remaining_weight", "Total remaining weight"],
|
|
["max_remaining_weight", "Max remaining weight"],
|
|
["spool_count", t]
|
|
],
|
|
(e) => this.updateConfigValue("group_sort_by", e)
|
|
)}
|
|
|
|
${this.renderSelect(
|
|
this._config.group_sort_direction || "asc",
|
|
"Group sort direction",
|
|
[
|
|
["asc", "Ascending"],
|
|
["desc", "Descending"]
|
|
],
|
|
(e) => this.updateConfigValue("group_sort_direction", e)
|
|
)}
|
|
|
|
${this.renderSwitchValue(
|
|
this._config.group_icon !== "none",
|
|
"Show group icon",
|
|
(e) => this.updateGroupIconVisibility(e)
|
|
)}
|
|
|
|
${this._config.group_icon !== "none" ? this.renderIconPicker(
|
|
this._config.group_icon || "mdi:printer-3d-nozzle",
|
|
"Group icon",
|
|
(e) => this.updateConfigValue("group_icon", e || "none")
|
|
) : ""}
|
|
|
|
${this.renderSwitch("show_group_title", "Show group title")}
|
|
`;
|
|
}
|
|
renderGroupTitleActionFields(t, e, n) {
|
|
var o, l;
|
|
const r = (((o = this._config.group_title_actions) == null ? void 0 : o[t]) || {})[e] || { action: "none" }, s = r.action || "none";
|
|
return u`
|
|
${this.renderSelect(
|
|
s,
|
|
n,
|
|
mt,
|
|
(c) => {
|
|
const h = { action: c };
|
|
c === "assist" && (h.pipeline_id = "preferred", h.start_listening = !0), this.updateGroupTitleAction(t, e, h);
|
|
}
|
|
)}
|
|
|
|
${s === "navigate" ? this.renderTextForm(
|
|
r.navigation_path || "",
|
|
"Navigation path",
|
|
(c) => this.updateGroupTitleAction(t, e, {
|
|
...r,
|
|
action: s,
|
|
navigation_path: c
|
|
})
|
|
) : ""}
|
|
|
|
${s === "url" ? this.renderTextForm(
|
|
r.url_path || "",
|
|
"URL path",
|
|
(c) => this.updateGroupTitleAction(t, e, {
|
|
...r,
|
|
action: s,
|
|
url_path: c
|
|
})
|
|
) : ""}
|
|
|
|
${s === "call-service" ? u`
|
|
<div class="hint">Service</div>
|
|
|
|
<ha-service-picker
|
|
.hass=${this.hass}
|
|
.value=${r.service || ""}
|
|
@value-changed=${(c) => this.updateGroupTitleAction(t, e, {
|
|
...r,
|
|
action: s,
|
|
service: c.detail.value
|
|
})}
|
|
></ha-service-picker>
|
|
|
|
<div class="hint">Target entity</div>
|
|
|
|
<ha-entity-picker
|
|
.hass=${this.hass}
|
|
.value=${((l = r.target) == null ? void 0 : l.entity_id) || ""}
|
|
@value-changed=${(c) => this.updateGroupTitleAction(t, e, {
|
|
...r,
|
|
action: s,
|
|
target: c.detail.value ? { entity_id: c.detail.value } : void 0
|
|
})}
|
|
></ha-entity-picker>
|
|
` : ""}
|
|
|
|
${s === "assist" ? u`
|
|
${this.renderTextForm(
|
|
r.pipeline_id || "preferred",
|
|
"Pipeline ID",
|
|
(c) => this.updateGroupTitleAction(t, e, {
|
|
...r,
|
|
action: s,
|
|
pipeline_id: c
|
|
})
|
|
)}
|
|
|
|
${this.renderSwitchValue(
|
|
r.start_listening !== !1,
|
|
"Start listening",
|
|
(c) => this.updateGroupTitleAction(t, e, {
|
|
...r,
|
|
action: s,
|
|
start_listening: c
|
|
})
|
|
)}
|
|
` : ""}
|
|
`;
|
|
}
|
|
renderSortDirection() {
|
|
return this.renderSelect(
|
|
this._config.sort_direction || "asc",
|
|
"Sort direction",
|
|
[
|
|
["asc", "Ascending"],
|
|
["desc", "Descending"]
|
|
],
|
|
(t) => this.updateConfigValue("sort_direction", t)
|
|
);
|
|
}
|
|
renderAppearanceOptions() {
|
|
return u`
|
|
|
|
${this.renderSelect(
|
|
this._config.bar_direction || "vertical",
|
|
"Bar direction",
|
|
[
|
|
["vertical", "Vertical"],
|
|
["horizontal", "Horizontal"]
|
|
],
|
|
(t) => {
|
|
const e = {
|
|
...this._config,
|
|
bar_direction: t
|
|
};
|
|
this.normalizePositions(e), this.setAndDispatchConfig(e);
|
|
}
|
|
)}
|
|
|
|
${this.renderSelect(
|
|
this._config.name_position || "bottom",
|
|
"Name position",
|
|
this.namePositionOptions(),
|
|
(t) => this.updateConfigValue("name_position", t)
|
|
)}
|
|
|
|
${this.renderSelect(
|
|
this._config.value_position || "center",
|
|
"Value position",
|
|
this.valuePositionOptions(),
|
|
(t) => this.updateConfigValue("value_position", t)
|
|
)}
|
|
|
|
${this.renderSwitch("show_name", "Show name")}
|
|
|
|
`;
|
|
}
|
|
renderActionOptions() {
|
|
return u`
|
|
|
|
${this.renderActionSelect("tap_action", "Tap action", "more-info")}
|
|
${this.renderActionSelect("double_tap_action", "Double tap action", "none")}
|
|
${this.renderActionSelect("hold_action", "Hold action", "none")}
|
|
`;
|
|
}
|
|
renderActionSelect(t, e, n) {
|
|
const i = this._config[t] || {}, r = i.action || n;
|
|
return u`
|
|
${this.renderSelect(
|
|
r,
|
|
e,
|
|
mt,
|
|
(s) => {
|
|
const o = { action: s };
|
|
s === "assist" && (o.pipeline_id = "preferred", o.start_listening = !0), this.updateConfigValue(t, o);
|
|
}
|
|
)}
|
|
|
|
${this.renderActionExtraFields(t, i, r)}
|
|
`;
|
|
}
|
|
renderActionExtraFields(t, e, n) {
|
|
var i;
|
|
return n === "navigate" ? this.renderTextForm(
|
|
e.navigation_path || "",
|
|
"Navigation path",
|
|
(r) => this.updateActionConfigValue(t, "navigation_path", r)
|
|
) : n === "url" ? this.renderTextForm(
|
|
e.url_path || "",
|
|
"URL path",
|
|
(r) => this.updateActionConfigValue(t, "url_path", r)
|
|
) : n === "call-service" ? u`
|
|
<div class="hint">Service</div>
|
|
|
|
<ha-service-picker
|
|
.hass=${this.hass}
|
|
.value=${e.service || ""}
|
|
@value-changed=${(r) => this.updateActionConfigValue(t, "service", r.detail.value)}
|
|
></ha-service-picker>
|
|
|
|
<div class="hint">Target entity</div>
|
|
|
|
<ha-entity-picker
|
|
.hass=${this.hass}
|
|
.value=${((i = e.target) == null ? void 0 : i.entity_id) || ""}
|
|
@value-changed=${(r) => this.updateActionTargetEntity(t, r.detail.value)}
|
|
></ha-entity-picker>
|
|
` : n === "assist" ? u`
|
|
${this.renderTextForm(
|
|
e.pipeline_id || "preferred",
|
|
"Pipeline ID",
|
|
(r) => this.updateActionConfigValue(t, "pipeline_id", r)
|
|
)}
|
|
|
|
${this.renderSwitchValue(
|
|
e.start_listening !== !1,
|
|
"Start listening",
|
|
(r) => this.updateActionConfigValue(t, "start_listening", r)
|
|
)}
|
|
` : u``;
|
|
}
|
|
updateGroupTitleValue(t, e, n) {
|
|
const i = { ...this._config }, r = { ...i[t] || {} };
|
|
n ? r[e] = n : delete r[e], i[t] = r, this.setAndDispatchConfig(i);
|
|
}
|
|
updateGroupTitleAction(t, e, n) {
|
|
const i = { ...this._config }, r = { ...i.group_title_actions || {} }, s = { ...r[t] || {} };
|
|
!n || n.action === "none" ? delete s[e] : s[e] = n, Object.keys(s).length ? r[t] = s : delete r[t], i.group_title_actions = r, this.setAndDispatchConfig(i);
|
|
}
|
|
updateActionConfigValue(t, e, n) {
|
|
const i = { ...this._config }, r = { ...i[t] || {} }, s = typeof n == "string" ? n.trim() : n;
|
|
s ? r[e] = s : delete r[e], i[t] = r, this.setAndDispatchConfig(i);
|
|
}
|
|
updateActionTargetEntity(t, e) {
|
|
const n = { ...this._config }, i = { ...n[t] || {} };
|
|
e ? i.target = {
|
|
...i.target || {},
|
|
entity_id: e
|
|
} : delete i.target, n[t] = i, this.setAndDispatchConfig(n);
|
|
}
|
|
renderPresetHint(t) {
|
|
const e = {
|
|
spoolman: "Automatically discovers Spoolman filament entities.",
|
|
custom_attributes: "Use entities that provide all display data through attributes.",
|
|
custom_entities: "Build each spool from multiple Home Assistant entities.",
|
|
custom_label: "Automatically use entities assigned to a Home Assistant label."
|
|
};
|
|
return this.renderHint(e[t] || "");
|
|
}
|
|
renderHint(t) {
|
|
return t ? u`
|
|
<div class="hint">${t}</div>
|
|
` : u``;
|
|
}
|
|
renderTextField(t, e) {
|
|
return u`
|
|
<ha-textfield
|
|
label=${e}
|
|
.value=${this._config[t] ?? S[t] ?? ""}
|
|
@input=${(n) => this.updateConfigValue(t, n.target.value)}
|
|
></ha-textfield>
|
|
`;
|
|
}
|
|
renderNumberField(t, e) {
|
|
return u`
|
|
<ha-textfield
|
|
label=${e}
|
|
type="number"
|
|
.value=${String(this._config[t] ?? S[t] ?? 0)}
|
|
@input=${(n) => this.updateConfigValue(t, Number(n.target.value))}
|
|
></ha-textfield>
|
|
`;
|
|
}
|
|
renderTextForm(t, e, n) {
|
|
const i = [
|
|
{
|
|
name: "value",
|
|
selector: {
|
|
text: {}
|
|
}
|
|
}
|
|
];
|
|
return u`
|
|
<ha-form
|
|
.hass=${this.hass}
|
|
.data=${{ value: t }}
|
|
.schema=${i}
|
|
.computeLabel=${() => e}
|
|
@value-changed=${(r) => {
|
|
var s;
|
|
n(((s = r.detail.value) == null ? void 0 : s.value) ?? "");
|
|
}}
|
|
></ha-form>
|
|
`;
|
|
}
|
|
renderSelect(t, e, n, i) {
|
|
const r = [
|
|
{
|
|
name: "value",
|
|
selector: {
|
|
select: {
|
|
mode: "dropdown",
|
|
options: n.map(([s, o]) => ({
|
|
value: s,
|
|
label: o
|
|
}))
|
|
}
|
|
}
|
|
}
|
|
];
|
|
return u`
|
|
<ha-form
|
|
.hass=${this.hass}
|
|
.data=${{ value: t }}
|
|
.schema=${r}
|
|
.computeLabel=${() => e}
|
|
@value-changed=${(s) => {
|
|
var l;
|
|
const o = (l = s.detail.value) == null ? void 0 : l.value;
|
|
o !== void 0 && o !== t && i(o);
|
|
}}
|
|
></ha-form>
|
|
`;
|
|
}
|
|
renderMultiSelect(t, e, n, i) {
|
|
const r = Array.isArray(t) ? t : [], s = [
|
|
{
|
|
name: "value",
|
|
selector: {
|
|
select: {
|
|
multiple: !0,
|
|
mode: "dropdown",
|
|
options: n.map(([o, l]) => ({
|
|
value: o,
|
|
label: l
|
|
}))
|
|
}
|
|
}
|
|
}
|
|
];
|
|
return u`
|
|
<ha-form
|
|
.hass=${this.hass}
|
|
.data=${{ value: r }}
|
|
.schema=${s}
|
|
.computeLabel=${() => e}
|
|
@value-changed=${(o) => {
|
|
var c;
|
|
const l = (c = o.detail.value) == null ? void 0 : c.value;
|
|
i(Array.isArray(l) ? l : []);
|
|
}}
|
|
></ha-form>
|
|
`;
|
|
}
|
|
renderEntityPicker(t, e, n, i = !1) {
|
|
const r = [
|
|
{
|
|
name: "value",
|
|
selector: {
|
|
entity: {
|
|
multiple: i
|
|
}
|
|
}
|
|
}
|
|
];
|
|
return u`
|
|
<ha-form
|
|
.hass=${this.hass}
|
|
.data=${{ value: t }}
|
|
.schema=${r}
|
|
.computeLabel=${() => e}
|
|
@value-changed=${(s) => {
|
|
var o;
|
|
n(((o = s.detail.value) == null ? void 0 : o.value) || (i ? [] : ""));
|
|
}}
|
|
></ha-form>
|
|
`;
|
|
}
|
|
renderLabelPicker(t, e, n) {
|
|
const i = [
|
|
{
|
|
name: "value",
|
|
selector: {
|
|
label: {}
|
|
}
|
|
}
|
|
];
|
|
return u`
|
|
<ha-form
|
|
.hass=${this.hass}
|
|
.data=${{ value: t }}
|
|
.schema=${i}
|
|
.computeLabel=${() => e}
|
|
@value-changed=${(r) => {
|
|
var s;
|
|
n(((s = r.detail.value) == null ? void 0 : s.value) || "");
|
|
}}
|
|
></ha-form>
|
|
`;
|
|
}
|
|
renderIconPicker(t, e, n) {
|
|
const i = [
|
|
{
|
|
name: "value",
|
|
selector: {
|
|
icon: {}
|
|
}
|
|
}
|
|
];
|
|
return u`
|
|
<ha-form
|
|
.hass=${this.hass}
|
|
.data=${{ value: t }}
|
|
.schema=${i}
|
|
.computeLabel=${() => e}
|
|
@value-changed=${(r) => {
|
|
var s;
|
|
n(((s = r.detail.value) == null ? void 0 : s.value) || "");
|
|
}}
|
|
></ha-form>
|
|
`;
|
|
}
|
|
renderSwitch(t, e, n = null) {
|
|
const i = this._config[t] !== !1;
|
|
return u`
|
|
<div class="switch-row">
|
|
<ha-switch
|
|
.checked=${i}
|
|
@change=${(r) => {
|
|
n ? n(r.target.checked) : this.updateConfigValue(t, r.target.checked);
|
|
}}
|
|
></ha-switch>
|
|
<span class="switch-label">${e}</span>
|
|
</div>
|
|
`;
|
|
}
|
|
renderSwitchValue(t, e, n) {
|
|
return u`
|
|
<div class="switch-row">
|
|
<ha-switch
|
|
.checked=${t}
|
|
@change=${(i) => n(i.target.checked)}
|
|
></ha-switch>
|
|
<span class="switch-label">${e}</span>
|
|
</div>
|
|
`;
|
|
}
|
|
updatePreset(t) {
|
|
const e = {
|
|
...this._config,
|
|
preset: t
|
|
};
|
|
t === "spoolman" && (delete e.custom_attribute_entities, delete e.custom_items, delete e.custom_label_id, delete e.custom_max_value, delete e.custom_unit), t === "custom_attributes" && (delete e.custom_items, delete e.custom_label_id), t === "custom_entities" && (delete e.custom_attribute_entities, delete e.custom_label_id), t === "custom_label" && (delete e.custom_attribute_entities, delete e.custom_items), this.setAndDispatchConfig(e);
|
|
}
|
|
updateConfigValue(t, e) {
|
|
const n = {
|
|
...this._config,
|
|
[t]: e
|
|
};
|
|
this.setAndDispatchConfig(n);
|
|
}
|
|
updateCustomItem(t, e, n) {
|
|
const i = [...this._config.custom_items || []];
|
|
i[t] = {
|
|
...i[t],
|
|
[e]: n
|
|
}, this.updateConfigValue("custom_items", i);
|
|
}
|
|
updateGroupIconVisibility(t) {
|
|
const e = {
|
|
...this._config,
|
|
group_icon: t ? "mdi:printer-3d-nozzle" : "none"
|
|
};
|
|
this.setAndDispatchConfig(e);
|
|
}
|
|
updateGroupBy(t) {
|
|
const e = {
|
|
...this._config,
|
|
group_by: t
|
|
};
|
|
delete e.filters, this.setAndDispatchConfig(e);
|
|
}
|
|
updateFilterValues(t, e) {
|
|
var l, c;
|
|
const n = Array.isArray(e) ? [...new Set(e.filter(Boolean))] : [], i = t === "include" ? "exclude" : "include", r = {
|
|
...this._config.filters || {},
|
|
[t]: n
|
|
}, s = Array.isArray(r[i]) ? r[i] : [];
|
|
r[i] = s.filter(
|
|
(h) => !n.includes(h)
|
|
), (l = r.include) != null && l.length || delete r.include, (c = r.exclude) != null && c.length || delete r.exclude;
|
|
const o = {
|
|
...this._config
|
|
};
|
|
Object.keys(r).length ? o.filters = r : delete o.filters, this.setAndDispatchConfig(o);
|
|
}
|
|
addCustomItem() {
|
|
const t = [
|
|
...this._config.custom_items || [],
|
|
{
|
|
name: "",
|
|
value_entity: "",
|
|
max_entity: "",
|
|
color_entity: "",
|
|
group_entity: "",
|
|
vendor_entity: "",
|
|
name_entity: "",
|
|
unit: this._config.custom_unit || "g"
|
|
}
|
|
];
|
|
this.updateConfigValue("custom_items", t);
|
|
}
|
|
removeCustomItem(t) {
|
|
const e = [...this._config.custom_items || []];
|
|
e.splice(t, 1), this.updateConfigValue("custom_items", e);
|
|
}
|
|
handleGroupOrderChanged(t) {
|
|
const e = t.target.value.split(`
|
|
`).map((n) => n.trim()).filter(Boolean);
|
|
this.setAndDispatchConfig({
|
|
...this._config,
|
|
group_order: e
|
|
});
|
|
}
|
|
groupOrderValue() {
|
|
return Array.isArray(this._config.group_order) ? this._config.group_order.join(`
|
|
`) : "";
|
|
}
|
|
groupOrderHint() {
|
|
return this._config.group_by === "color" ? "One color per line. Unknown colors are appended automatically." : this._config.group_by === "vendor" ? "One vendor per line. Unknown vendors are appended automatically." : "One group per line. Unknown groups are appended automatically.";
|
|
}
|
|
namePositionOptions() {
|
|
return this._config.bar_direction === "horizontal" ? [
|
|
["top", "Top"],
|
|
["bottom", "Bottom"],
|
|
["left", "Left"],
|
|
["right", "Right"]
|
|
] : [
|
|
["top", "Top"],
|
|
["bottom", "Bottom"]
|
|
];
|
|
}
|
|
valuePositionOptions() {
|
|
return this._config.bar_direction === "horizontal" ? [
|
|
["left", "Left"],
|
|
["center", "Center"],
|
|
["right", "Right"]
|
|
] : [
|
|
["top", "Top"],
|
|
["center", "Center"],
|
|
["bottom", "Bottom"]
|
|
];
|
|
}
|
|
normalizePositions(t) {
|
|
t.bar_direction === "vertical" && (["top", "bottom"].includes(t.name_position) || (t.name_position = "bottom"), ["top", "center", "bottom"].includes(t.value_position) || (t.value_position = "center")), t.bar_direction === "horizontal" && (["top", "bottom", "left", "right"].includes(t.name_position) || (t.name_position = "bottom"), ["left", "center", "right"].includes(t.value_position) || (t.value_position = "center"));
|
|
}
|
|
setAndDispatchConfig(t) {
|
|
this._config = t, this.dispatchEvent(
|
|
new CustomEvent("config-changed", {
|
|
detail: { config: t },
|
|
bubbles: !0,
|
|
composed: !0
|
|
})
|
|
);
|
|
}
|
|
}
|
|
j(K, "properties", {
|
|
hass: { attribute: !1 },
|
|
_config: { state: !0 },
|
|
_openSections: { state: !0 }
|
|
}), j(K, "styles", Ht`
|
|
.editor {
|
|
display: grid;
|
|
gap: 16px;
|
|
padding: 16px;
|
|
}
|
|
|
|
.section-title {
|
|
margin-top: 12px;
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.section-title:first-child {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.hint {
|
|
color: var(--secondary-text-color);
|
|
font-size: 12px;
|
|
line-height: 1.4;
|
|
margin-top: -6px;
|
|
}
|
|
|
|
ha-textfield,
|
|
ha-select {
|
|
width: 100%;
|
|
}
|
|
|
|
textarea {
|
|
width: 100%;
|
|
min-height: 80px;
|
|
box-sizing: border-box;
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
border: 1px solid var(--divider-color);
|
|
background: var(--card-background-color);
|
|
color: var(--primary-text-color);
|
|
font: inherit;
|
|
resize: vertical;
|
|
}
|
|
|
|
.switch-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.switch-label {
|
|
font-size: 14px;
|
|
}
|
|
|
|
.custom-item {
|
|
display: grid;
|
|
gap: 12px;
|
|
padding: 12px;
|
|
border: 1px solid var(--divider-color);
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.button-row {
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
|
|
.editor-button {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 6px;
|
|
width: fit-content;
|
|
padding: 8px 14px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
background: var(--primary-color);
|
|
color: var(--text-primary-color);
|
|
font: inherit;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
}
|
|
|
|
.editor-button:hover {
|
|
filter: brightness(1.08);
|
|
}
|
|
|
|
.editor-button.secondary {
|
|
background: var(--secondary-background-color);
|
|
color: var(--primary-text-color);
|
|
border: 1px solid var(--divider-color);
|
|
}
|
|
|
|
.editor-button.danger {
|
|
background: var(--error-color);
|
|
color: var(--text-primary-color);
|
|
}
|
|
|
|
.expandable-section {
|
|
border: 1px solid var(--divider-color);
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.expandable-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 8px;
|
|
padding: 12px;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
font-weight: 500;
|
|
background: var(--secondary-background-color);
|
|
}
|
|
|
|
.expandable-header:hover {
|
|
filter: brightness(1.03);
|
|
}
|
|
|
|
.expandable-content {
|
|
display: grid;
|
|
gap: 12px;
|
|
padding: 12px;
|
|
}
|
|
|
|
`);
|
|
customElements.get(Q) || customElements.define(Q, K);
|
|
window.customCards = window.customCards || [];
|
|
window.customCards.push({
|
|
type: J,
|
|
name: "Filament Card",
|
|
description: "Shows filament stock grouped by material, color, or vendor."
|
|
});
|