197 files
This commit is contained in:
+145
-8
@@ -66,11 +66,17 @@ interface Overview {
|
||||
needs_soon: Record<string, number>;
|
||||
types: string[];
|
||||
excluded?: { entity_id: string; device_name: string }[];
|
||||
// #135 follow-up: fleet-wide "track self-charging devices" opt-in.
|
||||
track_self_charging?: boolean;
|
||||
}
|
||||
|
||||
export class MaintenanceBatteryFleetSection extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
/** Flat mode drops the section's own card chrome (border/background) —
|
||||
* set by the Lovelace card wrapper, whose ha-card provides the chrome. */
|
||||
@property({ type: Boolean }) public flat = false;
|
||||
|
||||
@state() private _ov: Overview | null = null;
|
||||
@state() private _loading = false;
|
||||
@state() private _marking = false;
|
||||
@@ -198,6 +204,26 @@ export class MaintenanceBatteryFleetSection extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
// #135 follow-up: fleet-wide opt-in that keeps self-charging devices
|
||||
// (phones, vacuums, smart rings) in the roster as rechargeables.
|
||||
private async _setTrackSelf(e: Event): Promise<void> {
|
||||
const enabled = (e.target as HTMLInputElement).checked;
|
||||
if (this._marking) return;
|
||||
this._marking = true;
|
||||
this._error = "";
|
||||
try {
|
||||
await this.hass.connection.sendMessagePromise({
|
||||
type: "maintenance_supporter/battery_fleet/set_track_self_charging",
|
||||
enabled,
|
||||
});
|
||||
await this._load();
|
||||
} catch (e2) {
|
||||
this._error = describeWsError(e2, this._lang);
|
||||
} finally {
|
||||
this._marking = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Lazy: the recorder-backed history is fetched once, when the roster is
|
||||
* first expanded — most panel visits never open it. */
|
||||
private _loadHistory = async (e: Event): Promise<void> => {
|
||||
@@ -517,6 +543,16 @@ export class MaintenanceBatteryFleetSection extends LitElement {
|
||||
></ha-selector>
|
||||
<div class="bf-roster-hint">${t("battery_fleet_add_hint", L)}</div>
|
||||
</div>
|
||||
<label class="bf-track-self">
|
||||
<input
|
||||
type="checkbox"
|
||||
.checked=${!!ov.track_self_charging}
|
||||
.disabled=${this._marking}
|
||||
@change=${this._setTrackSelf}
|
||||
/>
|
||||
${t("battery_fleet_track_self", L)}
|
||||
</label>
|
||||
<div class="bf-roster-hint">${t("battery_fleet_track_self_hint", L)}</div>
|
||||
</details>
|
||||
`
|
||||
: nothing}
|
||||
@@ -558,6 +594,13 @@ export class MaintenanceBatteryFleetSection extends LitElement {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
:host([flat]) .bf-card {
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.bf-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -614,22 +657,69 @@ export class MaintenanceBatteryFleetSection extends LitElement {
|
||||
.bf-list {
|
||||
font-weight: 500;
|
||||
}
|
||||
/* Cross-row column alignment (same subgrid pattern as the task table,
|
||||
* issue 66): the LIST owns one column template, every row spans it via
|
||||
* subgrid, and each element is PINNED to its column below - so an
|
||||
* optional element (sparkline, percentage, forecast date) leaves its
|
||||
* column empty instead of letting the rest of the row drift. max-content
|
||||
* columns collapse to 0 when a whole list never fills them (the low list
|
||||
* has no status chip, no sparkline, no date). */
|
||||
.bf-rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) repeat(9, max-content);
|
||||
column-gap: 8px;
|
||||
}
|
||||
.bf-row {
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-columns: subgrid;
|
||||
grid-column: 1 / -1;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
}
|
||||
/* Column pinning: 1 name, 2 status/offline chip, 3 type, 4 charging
|
||||
* icon, 5 sparkline, 6 level bar, 7 percentage, 8 row action
|
||||
* (mark-one / record-swap), 9 forecast date, 10 exclude eye. */
|
||||
.bf-dev {
|
||||
flex: 1;
|
||||
grid-column: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.bf-offline,
|
||||
.bf-status {
|
||||
grid-column: 2;
|
||||
justify-self: end;
|
||||
}
|
||||
.bf-type {
|
||||
grid-column: 3;
|
||||
}
|
||||
.bf-recharge {
|
||||
grid-column: 4;
|
||||
}
|
||||
.bf-spark {
|
||||
grid-column: 5;
|
||||
}
|
||||
.bf-bar {
|
||||
grid-column: 6;
|
||||
}
|
||||
.bf-level {
|
||||
grid-column: 7;
|
||||
justify-self: end;
|
||||
}
|
||||
.bf-row .bf-mark {
|
||||
grid-column: 8;
|
||||
}
|
||||
.bf-predicted {
|
||||
grid-column: 9;
|
||||
justify-self: end;
|
||||
}
|
||||
.bf-row .bf-mark.bf-exclude {
|
||||
grid-column: 10;
|
||||
}
|
||||
.bf-offline {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
.bf-type {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 13px;
|
||||
@@ -648,13 +738,48 @@ export class MaintenanceBatteryFleetSection extends LitElement {
|
||||
flex: 0 0 auto;
|
||||
cursor: help;
|
||||
}
|
||||
/* On phones the row cannot fit name + chips + curve + bar + date: the
|
||||
* decorations yield (the percentage still carries the number). */
|
||||
/* On phones the row cannot fit name + chips + curve + bar + date in ONE
|
||||
* line: the decorations yield (the percentage still carries the number)
|
||||
* and the row wraps to two lines - the name spans the full width, the
|
||||
* status chip moves under it (left, into the name column) and the rest
|
||||
* keeps its pinned subgrid column, so type / percentage / date / eye
|
||||
* stay aligned across rows. Without this the fixed max-content columns
|
||||
* overflowed 400 px and the chips overlapped the wrapped names. */
|
||||
@media (max-width: 640px) {
|
||||
.bf-spark,
|
||||
.bf-bar {
|
||||
display: none;
|
||||
}
|
||||
.bf-row {
|
||||
row-gap: 2px;
|
||||
}
|
||||
.bf-dev {
|
||||
grid-column: 1 / 9;
|
||||
grid-row: 1;
|
||||
}
|
||||
.bf-offline,
|
||||
.bf-status {
|
||||
/* Line 1, RIGHT - over the date+eye columns, which are wide enough
|
||||
* for any chip. Pinning the chip into the 1fr rest column instead
|
||||
* overlapped the type text (the rest column shrinks below chip
|
||||
* width, and a span onto an fr track never grows fixed tracks). */
|
||||
grid-column: 9 / 11;
|
||||
grid-row: 1;
|
||||
justify-self: end;
|
||||
}
|
||||
.bf-type {
|
||||
grid-row: 2;
|
||||
max-width: 44vw;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.bf-recharge,
|
||||
.bf-level,
|
||||
.bf-predicted,
|
||||
.bf-row .bf-mark {
|
||||
grid-row: 2;
|
||||
}
|
||||
}
|
||||
.bf-spark-line {
|
||||
fill: none;
|
||||
@@ -834,6 +959,18 @@ export class MaintenanceBatteryFleetSection extends LitElement {
|
||||
border-radius: 10px;
|
||||
padding: 1px 4px 1px 10px;
|
||||
}
|
||||
.bf-track-self {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bf-track-self input {
|
||||
accent-color: var(--primary-color);
|
||||
margin: 0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user