291 files

This commit is contained in:
Home Assistant Version Control
2026-10-14 18:10:18 +00:00
parent c4e0178d8a
commit 280501d2e8
291 changed files with 32540 additions and 3280 deletions
@@ -0,0 +1,127 @@
/*! maintenance_supporter frontend 2.103.0 */
import{a as w,b as $}from"./chunk-3P2KHV56.js";import{C as u,a as h,b as o,d as m,f as y,g as v,h as l,i as g,j as _,k as f,l as x,o as p}from"./chunk-ZALBVT7T.js";import{a as n,h as i}from"./chunk-ORLIHI47.js";var E=80,s=class extends y{constructor(){super(...arguments);this._config={type:""};this._status=null;this._busy=!1;this._error="";this._localMonthly="";this._localYearly="";this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return f(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),_(this,t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load())}async _load(){let t=await u(this,{type:"maintenance_supporter/budget_status"},{onError:e=>{this._error=e}});t&&(this._status=t,x(t),this._localMonthly=t.monthly_budget?String(t.monthly_budget):"",this._localYearly=t.yearly_budget?String(t.yearly_budget):"",this._dirty=!1)}async _save(){if(!this._isAdmin)return;this._error="";let t=this._localMonthly.trim()===""?0:parseFloat(this._localMonthly),e=this._localYearly.trim()===""?0:parseFloat(this._localYearly),a={};!isNaN(t)&&t>=0&&(a.budget_monthly=t),!isNaN(e)&&e>=0&&(a.budget_yearly=e),await u(this,{type:"maintenance_supporter/global/update",settings:a},{busy:d=>{this._busy=d},reload:()=>this._load(),onError:d=>{this._error=d}})}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_budget"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,e=this._status;if(!e)return o`<ha-card><div class="loading">${i("loading",t)}</div></ha-card>`;let a=g(e),d=e.alert_threshold_pct??E,k=[{label:i("budget_monthly",t),spent:e.monthly_spent||0,budget:e.monthly_budget||0},{label:i("budget_yearly",t),spent:e.yearly_spent||0,budget:e.yearly_budget||0}];return o`
<ha-card>
<div class="card-content">
<div class="header">
<div class="title">
<span class="emoji">💰</span>
<span>${this._config.title||i("settings_budget",t)}</span>
</div>
<span class="currency">${a}</span>
</div>
${this._error?o`<div class="error">${this._error}</div>`:m}
${k.map(r=>{if(!(r.budget>0))return o`
<div class="track spent-only">
<div class="track-label-row">
<label>${r.label}</label>
<span class="track-numbers ok">${p(r.spent,a,t)}</span>
</div>
</div>
`;let c=Math.min(100,Math.max(0,r.spent/r.budget*100)),b=c>=100?"danger":c>=d?"warning":"ok";return o`
<div class="track">
<div class="track-label-row">
<label>${r.label}</label>
<span class="track-numbers ${b}">
${p(r.spent,void 0,t)} / ${p(r.budget,a,t)}
</span>
</div>
<div class="bar"><div class="bar-fill ${b}" style="width:${c}%"></div></div>
</div>
`})}
${this._isAdmin?o`
<div class="inputs-row">
<div class="input-field">
<label>${i("budget_monthly_set",t)}</label>
<div class="input-wrap">
<input type="number" min="0" step="1"
.value=${this._localMonthly}
?disabled=${this._busy}
@input=${r=>{this._localMonthly=r.target.value,this._dirty=!0}} />
<span class="input-suffix">${a}</span>
</div>
</div>
<div class="input-field">
<label>${i("budget_yearly_set",t)}</label>
<div class="input-wrap">
<input type="number" min="0" step="1"
.value=${this._localYearly}
?disabled=${this._busy}
@input=${r=>{this._localYearly=r.target.value,this._dirty=!0}} />
<span class="input-suffix">${a}</span>
</div>
</div>
</div>
<div class="actions">
<button class="btn ${this._dirty?"primary":"muted"}"
@click=${this._save}
?disabled=${this._busy||!this._dirty}>
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
${this._dirty?i("save",t):i("saved",t)}
</button>
<button class="btn link" @click=${this._onDeepLink}>
${i("budget_advanced",t)}
</button>
</div>
`:o`
<button class="btn link" @click=${this._onDeepLink}>
${i("budget_open_panel",t)}
</button>
`}
</div>
</ha-card>
`}};s.styles=[$,h`
.currency {
font-size: 14px; font-weight: 600;
color: var(--secondary-text-color);
background: var(--secondary-background-color);
padding: 2px 10px; border-radius: 999px;
}
.track { display: flex; flex-direction: column; gap: 4px; }
.track-label-row {
display: flex; align-items: center; justify-content: space-between;
}
.track-label-row label {
font-size: 12px; color: var(--secondary-text-color);
text-transform: uppercase; letter-spacing: 0.5px;
}
.track-numbers { font-size: 13px; font-weight: 600; }
.track-numbers.ok { color: var(--primary-text-color); }
.track-numbers.warning { color: #ff9800; }
.track-numbers.danger { color: var(--error-color, #f44336); }
.bar {
height: 6px; background: var(--secondary-background-color);
border-radius: 3px; overflow: hidden;
}
.bar-fill { height: 100%; transition: width 0.3s; border-radius: 3px; }
.bar-fill.ok { background: var(--primary-color); }
.bar-fill.warning { background: #ff9800; }
.bar-fill.danger { background: var(--error-color, #f44336); }
/* minmax(0, …): a bare 1fr never shrinks below the number inputs'
natural width — the row was 420 px wide on a phone (2026-09-27). */
.inputs-row {
display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
padding-top: 4px; border-top: 1px solid var(--divider-color);
}
.input-field { display: flex; flex-direction: column; gap: 4px; }
.input-field label {
font-size: 11px; color: var(--secondary-text-color);
text-transform: uppercase; letter-spacing: 0.3px;
}
.input-wrap { position: relative; display: flex; align-items: center; }
.input-wrap input {
flex: 1; min-width: 0; width: 100%; box-sizing: border-box; padding: 6px 32px 6px 8px; font-size: 13px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
font-family: inherit;
}
.input-suffix {
position: absolute; right: 8px;
color: var(--secondary-text-color); font-size: 13px;
pointer-events: none;
}
.actions { display: flex; gap: 8px; align-items: center; }
`],n([v({attribute:!1})],s.prototype,"hass",2),n([l()],s.prototype,"_config",2),n([l()],s.prototype,"_status",2),n([l()],s.prototype,"_busy",2),n([l()],s.prototype,"_error",2),n([l()],s.prototype,"_localMonthly",2),n([l()],s.prototype,"_localYearly",2),n([l()],s.prototype,"_dirty",2);customElements.get("maintenance-budget-section-card")||customElements.define("maintenance-budget-section-card",s);w({type:"maintenance-budget-section-card",name:"Maintenance Supporter \u2014 Budget",description:"Edit the monthly and yearly budget right on the dashboard.",preview:!1});export{s as MaintenanceBudgetSectionCard};
@@ -0,0 +1,88 @@
/*! maintenance_supporter frontend 2.103.0 */
import{a as y,b as s,d,f as g,g as o,h as f,r as m}from"./chunk-ZALBVT7T.js";import{a,h as l}from"./chunk-ORLIHI47.js";function $(n){let t=m("2001-02-03",n).match(/\d+/g)||[],e=v=>t.findIndex(_=>Number(_)===v),h=e(2001),c=e(2),u=e(3);return h===0?"YMD":c>=0&&u>=0&&c<u?"MDY":"DMY"}function p(n,i,t){if(n<1e3||n>9999||i<1||i>12||t<1||t>31)return null;let e=new Date(n,i-1,t);return e.getFullYear()!==n||e.getMonth()!==i-1||e.getDate()!==t?null:`${n}-${String(i).padStart(2,"0")}-${String(t).padStart(2,"0")}`}function b(n,i){let t=n.trim(),e;if(e=t.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/))return p(+e[1],+e[2],+e[3]);if(e=t.match(/^(\d{4})$/))return p(+e[1],1,1);if(e=t.match(/^(\d{1,2})[./](\d{4})$/))return p(+e[2],+e[1],1);if(e=t.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/))return p(+e[3],+e[2],+e[1]);if(e=t.match(/^(\d{1,2})[/-](\d{1,2})[/-](\d{4})$/)){let h=+e[1],c=+e[2],u=+e[3];return $(i)==="MDY"?p(u,h,c):p(u,c,h)}return null}function x(n,i){if(i)switch(n){case"date":return i.split("T")[0];case"time":return i.length===5?`${i}:00`:i;case"datetime":{let[t,e="00:00:00"]=i.split("T");return`${t} ${e.length===5?`${e}:00`:e}`}}}function k(n,i){if(typeof i!="string"||!i)return"";switch(n){case"date":return i.slice(0,10);case"time":return i.slice(0,5);case"datetime":{let[t,e="00:00:00"]=i.split(" ");return`${t}T${e.length===5?`${e}:00`:e}`}}}var r=class extends g{constructor(){super(...arguments);this.kind="date";this.label="";this.value="";this.clearable=!1;this.disabled=!1;this.required=!1;this.lang="en";this._typing=!1;this._typed="";this._typedInvalid=!1}_startTyping(){this._typed=this.value,this._typedInvalid=!1,this._typing=!0,this.updateComplete.then(()=>this.shadowRoot?.querySelector("input.typed")?.focus())}_commitTyped(){if(!this._typed.trim()){this._typing=!1;return}let t=b(this._typed,this.lang);if(!t){this._typedInvalid=!0;return}this._typing=!1,this._typedInvalid=!1,this._emit(t)}_onTypedKey(t){t.key==="Enter"?(t.preventDefault(),this._commitTyped()):t.key==="Escape"&&(t.preventDefault(),this._typing=!1,this._typedInvalid=!1)}_selector(){switch(this.kind){case"date":return{date:{}};case"time":return{time:{no_second:!0}};case"datetime":return{datetime:{}}}}_onSelectorChange(t){t.stopPropagation(),this._emit(k(this.kind,t.detail?.value))}_clear(){this._emit("")}_emit(t){t!==this.value&&(this.value=t,this.dispatchEvent(new CustomEvent("value-changed",{bubbles:!0,composed:!0,detail:{value:t}})))}render(){return s`
<div class="field">
${this.label?s`<span class="label">${this.label}${this.required?s`<span class="req">*</span>`:d}</span>`:d}
<div class="row">
${this._typing?s`<input class="typed" type="text" inputmode="numeric" autocomplete="off"
.value=${this._typed}
placeholder=${m("1978-03-15",this.lang)}
aria-invalid=${this._typedInvalid?"true":"false"}
@input=${t=>{this._typed=t.target.value,this._typedInvalid=!1}}
@keydown=${this._onTypedKey}
@blur=${this._commitTyped} />`:s`<ha-selector
.hass=${this.hass}
.selector=${this._selector()}
.value=${x(this.kind,this.value)}
.required=${this.required}
.disabled=${this.disabled}
@value-changed=${this._onSelectorChange}
></ha-selector>`}
${this.kind==="date"&&!this.disabled&&!this._typing?s`<button type="button" class="type-toggle" title=${l("date_type_toggle",this.lang)} aria-label=${l("date_type_toggle",this.lang)} @click=${this._startTyping}>
<ha-icon icon="mdi:keyboard-outline"></ha-icon>
</button>`:d}
${this.clearable&&this.value&&!this.disabled&&!this._typing?s`<button type="button" class="clear" title=${l("clear",this.lang)} aria-label=${l("clear",this.lang)} @click=${this._clear}>
<ha-icon icon="mdi:close"></ha-icon>
</button>`:d}
</div>
${this._typedInvalid?s`<span class="helper invalid">${l("date_type_invalid",this.lang)}</span>`:this.helper?s`<span class="helper">${this.helper}</span>`:d}
</div>
`}};r.styles=y`
:host { display: block; }
.field {
display: flex;
flex-direction: column;
gap: 4px;
}
.label {
font-size: 12px;
color: var(--secondary-text-color, #888);
font-weight: 500;
}
.req { color: var(--error-color, #f44336); margin-left: 2px; }
.row {
display: flex;
align-items: center;
gap: 4px;
}
ha-selector {
flex: 1;
min-width: 0;
}
.clear, .type-toggle {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
padding: 0;
border: none;
border-radius: 50%;
background: transparent;
color: var(--secondary-text-color);
cursor: pointer;
--mdc-icon-size: 20px;
}
.clear:hover, .type-toggle:hover { background: rgba(var(--rgb-primary-text-color, 0, 0, 0), 0.08); }
.clear:focus-visible, .type-toggle:focus-visible { outline: 2px solid var(--primary-color); }
.helper {
font-size: 11px;
color: var(--secondary-text-color);
font-style: italic;
}
.helper.invalid { color: var(--error-color, #f44336); font-style: normal; }
input.typed {
flex: 1;
min-width: 0;
height: 40px;
box-sizing: border-box;
padding: 0 12px;
border: 1px solid var(--divider-color, #ccc);
border-radius: 4px;
background: var(--card-background-color, #fff);
color: var(--primary-text-color);
font: inherit;
}
input.typed[aria-invalid="true"] { border-color: var(--error-color, #f44336); }
input.typed:focus { outline: 2px solid var(--primary-color); outline-offset: -1px; }
`,a([o({attribute:!1})],r.prototype,"hass",2),a([o()],r.prototype,"kind",2),a([o()],r.prototype,"label",2),a([o()],r.prototype,"value",2),a([o()],r.prototype,"helper",2),a([o({type:Boolean})],r.prototype,"clearable",2),a([o({type:Boolean})],r.prototype,"disabled",2),a([o({type:Boolean})],r.prototype,"required",2),a([o()],r.prototype,"lang",2),a([f()],r.prototype,"_typing",2),a([f()],r.prototype,"_typed",2),a([f()],r.prototype,"_typedInvalid",2);customElements.get("ms-date-field")||customElements.define("ms-date-field",r);
@@ -0,0 +1,60 @@
/*! maintenance_supporter frontend 2.103.0 */
import{a as t}from"./chunk-ZALBVT7T.js";function e(o){let r=window;r.customCards=r.customCards||[],r.customCards.some(a=>a.type===o.type)||r.customCards.push(o)}var d=t`
ha-card { overflow: hidden; }
.card-content {
padding: 16px;
display: flex; flex-direction: column;
gap: 12px;
}
.header {
display: flex; align-items: center; justify-content: space-between;
gap: 12px;
}
.title {
display: flex; align-items: center; gap: 8px;
font-size: 16px; font-weight: 500;
}
.emoji { font-size: 20px; }
/* Button family — primary action / muted-saved-state / link / icon-with-text */
.btn {
padding: 6px 12px; font-size: 13px;
border-radius: 6px; cursor: pointer;
border: 1px solid var(--divider-color);
background: var(--secondary-background-color, transparent);
color: var(--primary-text-color);
font-weight: 500;
display: inline-flex; align-items: center; gap: 4px;
}
.btn:hover { background: var(--state-icon-color, rgba(255,255,255,0.06)); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.btn.primary {
background: var(--primary-color);
color: var(--text-primary-color, white);
border-color: var(--primary-color);
}
.btn.primary[disabled] { opacity: 0.6; }
.btn.muted {
background: transparent;
color: var(--secondary-text-color);
border-style: dashed;
}
.btn.muted[disabled] { opacity: 1; cursor: default; }
.btn.muted ha-icon, .btn.primary ha-icon { --mdc-icon-size: 14px; }
.btn.link {
background: transparent; border: none; padding: 6px 4px;
color: var(--primary-color); margin-left: auto;
}
.btn.link:hover { background: transparent; text-decoration: underline; }
/* Error + loading states */
.error {
padding: 8px; border-radius: 6px;
background: rgba(211, 47, 47, 0.1);
color: var(--error-color, #d32f2f); font-size: 13px;
}
.loading {
padding: 24px; text-align: center;
color: var(--secondary-text-color);
}
`;export{e as a,d as b};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.103.0 */
import{q as l}from"./chunk-ORLIHI47.js";function c(r){if(!r)return[];let n=[],i=r.photo_doc_id;typeof i=="string"&&n.push(i);let o=r.photo_doc_ids;Array.isArray(o)&&n.push(...o);let t=[];for(let e of n){if(typeof e!="string")continue;let s=e.trim();if(!(!s||t.includes(s))&&(t.push(s),t.length>=10))break}return t}var f=20;function _(){let r=new Uint8Array(4);return(globalThis.crypto??{getRandomValues:n=>n.map(()=>Math.floor(Math.random()*256))}).getRandomValues(r),Array.from(r,n=>n.toString(16).padStart(2,"0")).join("")}function d(r){let n=r?.reading_values;if(!Array.isArray(n))return[];let i=[],o=new Set;for(let t of n){if(!t||typeof t!="object")continue;let e=t;typeof e.id!="string"||!e.id||o.has(e.id)||typeof e.value!="number"||!Number.isFinite(e.value)||(o.add(e.id),i.push({id:e.id,name:typeof e.name=="string"?e.name:e.id,unit:typeof e.unit=="string"?e.unit:null,value:e.value}))}return i}function y(r){return r.filter(n=>n.type==="completed"&&(n.reading_value!=null||d(n).length>0)).sort((n,i)=>n.timestamp.localeCompare(i.timestamp))}function R(r){return y(r??[]).map(n=>({timestamp:n.timestamp,values:d(n)})).filter(n=>n.values.length>0)}function h(r,n,i){let o;for(let t of r){if(i!==void 0){let s=l(t.timestamp);if(!isNaN(s)&&s>=i)break}let e=t.values.find(s=>s.id===n);e&&(o=e)}return o}function k(r,n,i){let o=d(n).find(e=>e.id===i);if(!o)return null;let t=null;for(let e of y(r)){if(e.timestamp>=n.timestamp)break;let s=d(e).find(a=>a.id===i);s&&(t=s.value)}return t==null?null:o.value-t}function w(r){let n=new Set,i=new Set;for(let o of r){let t=(o.name||"").trim().toLowerCase();t&&(n.has(t)?i.add(o.id):n.add(t))}return i}function S(r){let n=[],i=new Set,o=new Set;for(let t of r){let e=(t.name||"").trim();if(!(!e||i.has(t.id)||o.has(e.toLowerCase()))&&(i.add(t.id),o.add(e.toLowerCase()),n.push({id:t.id,name:e,unit:(t.unit||"").trim()||null}),n.length>=f))break}return n}function g(r,n,i,o){let t=i,e=u=>typeof u=="string"?u:null,s=u=>typeof u=="number"?u:null,a=e(t.timestamp)??"";return{entry_id:r,task_id:n,original_timestamp:a,type:e(t.type)||"completed",timestamp:a,notes:e(t.notes),cost:s(t.cost),duration:s(t.duration),completed_by:e(t.completed_by),used_parts:Array.isArray(t.used_parts)?t.used_parts:null,photo_doc_ids:c(t),reading_value:s(t.reading_value),reading_values:d(t),readings:o?.readings??[],task_type:o?.type??null,reading_unit:o?.reading_unit??null}}async function v(r,n,i,o){let e=(await r.connection.sendMessagePromise({type:"maintenance_supporter/object",entry_id:n})).tasks?.find(a=>a.id===i);if(!e)return null;let s=e.history?.find(a=>a.timestamp===o);return s||(s=(await r.connection.sendMessagePromise({type:"maintenance_supporter/task/history",entry_id:n,task_id:i})).history?.find(u=>u.timestamp===o)),s?g(n,i,s,e):null}export{c as a,f as b,_ as c,d,R as e,h as f,k as g,w as h,S as i,g as j,v as k};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.103.0 */
var w=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var B=(n,e,t,r)=>{for(var o=r>1?void 0:r?y(e,t):e,s=n.length-1,i;s>=0;s--)(i=n[s])&&(o=(r?i(e,t,o):i(o))||o);return r&&o&&w(e,t,o),o};var W={ok:"var(--success-color, #4caf50)",due_soon:"var(--warning-color, #ff9800)",overdue:"var(--error-color, #f44336)",triggered:"var(--deep-orange-color, #ff5722)",archived:"var(--disabled-color, #9e9e9e)",paused:"var(--info-color, #2196f3)"},C=["overdue","triggered","due_soon","ok"],j=["overdue","triggered","due_soon"],V=Object.fromEntries(C.map((n,e)=>[n,e]));var Y={ok:"mdi:check-circle",due_soon:"mdi:alert-circle",overdue:"mdi:alert-octagon",triggered:"mdi:bell-alert",archived:"mdi:archive-outline",paused:"mdi:pause-circle-outline",completed:"mdi:check-circle",skipped:"mdi:skip-next",missed:"mdi:calendar-remove",reset:"mdi:refresh"};var D="2.103.0";function H(n){return n?.restart_pending&&n.installed_version?n.installed_version:null}var _="en",x=(()=>{let n=window;return n.__msLocales||(n.__msLocales={store:{},inflight:{}}),n.__msLocales})(),l=x.store,d=x.inflight;function J(n){l.en=Object.assign({},n,l.en??{})}var O=new Set(["de","nl","fr","it","es","pt","pt-br","ru","uk","pl","cs","sv","zh","da","fi","nb","ja","hi","hu","ko","tr"]),R="/maintenance_supporter_locales";function b(n){let e=(n||_).toLowerCase();return e.startsWith("pt")&&e.endsWith("br")?"pt-br":e.substring(0,2)}function Q(n,e,t){let r=b(e);return l[r]?.[n]??l.en?.[n]??t??n}function X(n){let e=b(n);return e===_||e in l}function nn(n){let e=b(n);return e===_||e in l||!O.has(e)?Promise.resolve():(e in d||(d[e]=fetch(`${R}/${e}.json?v=${D}`).then(t=>t.ok?t.json():null).then(t=>{t?l[e]=t:delete d[e]}).catch(()=>{delete d[e]})),d[e])}var A=window.__msDateTimePrefs??={},v=864e5,a=(n,e=2)=>String(n).padStart(e,"0"),$=new Map;function m(n){let e=$.get(n);if(e===void 0){try{e=new Intl.DateTimeFormat("en-US",{timeZone:n,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch{e=null}$.set(n,e)}return e}var S;function L(){if(S===void 0){let n;try{n=new Intl.DateTimeFormat().resolvedOptions().timeZone}catch{}S=n&&m(n)?n:null}return S}function E(){return L()??"UTC"}function f(){let n=A.serverTimeZone;return n&&m(n)?n:E()}function tn(){let n=L();return A.timeZone!=="server"&&n?n:f()}function p(n,e){let t=m(e)??m(E())??m("UTC"),r={};for(let o of t.formatToParts(n))o.type!=="literal"&&(r[o.type]=Number(o.value));return{y:r.year,mo:r.month,d:r.day,h:r.hour%24,mi:r.minute,s:r.second}}var N=n=>`${a(n.y,4)}-${a(n.mo)}-${a(n.d)}`;function M(n,e){return N(p(+n,e))}function I(n,e){let t=p(+n,e);return`${N(t)}T${a(t.h)}:${a(t.mi)}`}function rn(){return M(Date.now(),f())}function on(){return I(Date.now(),f())}function h(n,e){let t=p(n,e);return Date.UTC(t.y,t.mo-1,t.d,t.h,t.mi,t.s)-Math.floor(n/1e3)*1e3}function P(n,e,t,r,o,s,i){let u=Date.UTC(n,e-1,t,r,o,s),c=h(u-v,i),g=h(u+v,i);for(let T of c===g?[c]:[c,g])if(h(u-T,i)===T)return u-T;return u-c}var U=/^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?)?$/;var Z=new Map,F=2e4;function k(n,e,t){if(n.has(e))return n.get(e);n.size>=F&&n.clear();let r=t();return n.set(e,r),r}function sn(n){if(typeof n!="string"||!n)return NaN;let e=U.exec(n);if(!e)return Date.parse(n);let t=f();return k(Z,`${t}|${n}`,()=>{let[r,o,s,i,u,c]=[e[1],e[2],e[3],e[4]??"0",e[5]??"0",e[6]??"0"].map(Number);if(o<1||o>12||new Date(Date.UTC(r,o-1,s)).getUTCDate()!==s||i>23||u>59||c>59)return NaN;let g=e[7]?Math.floor(+`0.${e[7]}`*1e3):0;return P(r,o,s,i,u,c,t)+g})}function un(n){if(typeof n!="string"||!n)return"";let e=U.exec(n);if(e)return`${e[1]}-${e[2]}-${e[3]}T${e[4]??"00"}:${e[5]??"00"}:${e[6]??"00"}`;let t=Date.parse(n);if(!Number.isFinite(t))return"";let r=p(t,f());return`${N(r)}T${a(r.h)}:${a(r.mi)}:${a(r.s)}`}export{B as a,W as b,j as c,Y as d,H as e,J as f,b as g,Q as h,X as i,nn as j,f as k,tn as l,M as m,I as n,rn as o,on as p,sn as q,un as r};
@@ -0,0 +1,66 @@
/*! maintenance_supporter frontend 2.103.0 */
import{A as c,a as u,b as s,d as r,f as _,g as m,h as o,k as d}from"./chunk-ZALBVT7T.js";import{a as i,h as p}from"./chunk-ORLIHI47.js";var g={default_warning_days:[0,365],default_consumable_threshold:[1,90],battery_low_percent:[1,90],battery_recovered_percent:[20,100],archive_oneoff_days:[0,3650],delete_archived_oneoff_days:[0,3650],notify_due_soon_interval_hours:[0,720],notify_overdue_interval_hours:[0,720],notify_triggered_interval_hours:[0,720],max_notifications_per_day:[0,1e3],notification_bundle_threshold:[2,20],snooze_duration_hours:[1,168],warranty_reminder_days:[1,365],budget_alert_threshold:[10,100],currency_decimals:[0,3]};var b=[0,14],x=[0,1440],y=[1,1e4],R=[0,365],A=15,E=[.1,.9],T=[0,365],$=[.01,1e4],G=[.01,1e5];var n=class extends _{constructor(){super(...arguments);this._open=!1;this._title="";this._message="";this._confirmText="";this._danger=!1;this._inputLabel="";this._inputType="";this._options=null;this._inputValue="";this._resolve=null;this._promptResolve=null}confirm(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel="",this._inputType="",this._options=null,this._inputValue="",this._open=!0,new Promise(t=>{this._resolve=t,this._promptResolve=null})}prompt(e){return this._title=e.title,this._message=e.message,this._confirmText=e.confirmText||"OK",this._danger=e.danger||!1,this._inputLabel=e.inputLabel||"",this._inputType=e.inputType||"text",this._options=e.options&&e.options.length?e.options:null,this._inputValue=e.inputValue||"",this._open=!0,new Promise(t=>{this._promptResolve=t,this._resolve=null})}_cancel(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!1,value:""}),this._promptResolve=null),this._resolve?.(!1),this._resolve=null}_confirmAction(){this._open=!1,this._promptResolve&&(this._promptResolve({confirmed:!0,value:this._inputValue}),this._promptResolve=null),this._resolve?.(!0),this._resolve=null}render(){if(!this._open)return r;let e=d(this.hass);return s`
<ha-dialog open @closed=${this._cancel}>
<div class="dialog-title">${this._title}</div>
<div class="content">
${this._message}
${this._inputLabel?s`
<!-- Native <input> rather than <ha-textfield>: HA loads
ha-textfield lazily for its own panels, so inside this custom
panel it can be unregistered and render with zero height —
the prompt then shows no field at all (caught live testing
the pause/replace prompts; same fix as complete-dialog). -->
<label class="field">
<span class="field-label">${this._inputLabel}</span>
${this._options?s`<select class="field-input field-select"
@change=${t=>this._inputValue=t.target.value}>
${this._options.map(t=>s`<option value=${t.value} ?selected=${t.value===this._inputValue}>${t.label}</option>`)}
</select>`:s`<input class="field-input"
type="${this._inputType||"text"}"
.value=${this._inputValue}
@input=${t=>this._inputValue=t.target.value} />`}
</label>
`:r}
</div>
<div class="dialog-actions">
<ha-button appearance="plain" @click=${this._cancel}>
${p("cancel",e)}
</ha-button>
<ha-button
class="${this._danger?"danger":""}"
@click=${this._confirmAction}
>
${this._confirmText}
</ha-button>
</div>
</ha-dialog>
`}};n.styles=[c,u`
.dialog-title {
font-size: 18px;
font-weight: 500;
padding-bottom: 12px;
}
/* shared native-field scaffold from nativeFieldStyles; the prompt input
follows the message text, hence the extra top margin here */
.field { margin-top: 12px; }
.content {
padding: 8px 0;
min-width: 280px;
line-height: 1.5;
display: flex;
flex-direction: column;
gap: 12px;
}
.dialog-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
padding-top: 16px;
}
ha-textfield {
display: block;
}
ha-button.danger {
--mdc-theme-primary: var(--error-color, #f44336);
}
`],i([m({attribute:!1})],n.prototype,"hass",2),i([o()],n.prototype,"_open",2),i([o()],n.prototype,"_title",2),i([o()],n.prototype,"_message",2),i([o()],n.prototype,"_confirmText",2),i([o()],n.prototype,"_danger",2),i([o()],n.prototype,"_inputLabel",2),i([o()],n.prototype,"_inputType",2),i([o()],n.prototype,"_options",2),i([o()],n.prototype,"_inputValue",2);customElements.get("maintenance-confirm-dialog")||customElements.define("maintenance-confirm-dialog",n);var h="maintenance-confirm-dialog",f="data-ms-lovelace-confirm";function v(){return document.querySelector("home-assistant")?.shadowRoot??document.body}function V(l,a){let e=v(),t=e.querySelector(`${h}[${f}]`);return t||(t=document.createElement(h),t.setAttribute(f,""),e.appendChild(t)),t.hass=l,t.confirm(a)}export{g as a,b,x as c,y as d,R as e,A as f,E as g,T as h,$ as i,G as j,V as k};
@@ -0,0 +1,2 @@
/*! maintenance_supporter frontend 2.103.0 */
import{a as i}from"./chunk-SYZTQIIC.js";var r={operatorWriteEnabled:!1,operatorIds:[]};function f(e,t=r){return e?e.is_admin?!0:t.operatorWriteEnabled&&t.operatorIds.includes(e.id):!1}function l(e){return e==="use"?"use":"purchase"}var c=e=>typeof e=="number"&&Number.isFinite(e)?e:null;function b(e){let t=c(e?.cost);if(t===null)return null;let n=c(e?.package_size);return n&&n>0?t/n:t}var d=["buttons_compact","buttons","icons"];function _(e){let[t,n]=i.default_warning_days,s=e?.general?.default_warning_days,a=e?.general?.row_action_style;return{features:{...o.features,...e?.features??{}},defaultWarningDays:typeof s=="number"&&Number.isFinite(s)&&s>=t&&s<=n?s:o.defaultWarningDays,rowActionStyle:d.includes(a??"")?a:o.rowActionStyle,access:{operatorWriteEnabled:e?.operator_write_enabled===!0,operatorIds:Array.isArray(e?.admin_panel_user_ids)?e.admin_panel_user_ids.filter(p=>typeof p=="string"):[]},budget:e?.budget??null,rowActionNoticePending:e?.general?.row_action_notice_pending===!0,refsInLists:e?.general?.ref_numbers_in_lists===!0,objectsTableColumns:Array.isArray(e?.objects_table_columns)?e.objects_table_columns:void 0,partsCostMode:l(e?.budget?.parts_cost_mode)}}var o={features:{adaptive:!1,seasonal:!1,environmental:!1,budget:!1,groups:!1,checklists:!1,schedule_time:!1,completion_actions:!1,places:!1},defaultWarningDays:7,rowActionStyle:"buttons_compact",access:r,budget:null,rowActionNoticePending:!1,refsInLists:!1,objectsTableColumns:void 0,partsCostMode:"purchase"};function u(){let e=window;return e.__msSettingsCache??={promise:null}}function w(e){let t=u();if(t.promise)return t.promise;let n=e.connection.sendMessagePromise({type:"maintenance_supporter/settings"}).then(s=>_(s)).catch(()=>(t.promise===n&&(t.promise=null),o));return t.promise=n,n}function h(){u().promise=null}export{r as a,f as b,b as c,w as d,h as e};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,137 @@
/*! maintenance_supporter frontend 2.103.0 */
import{a as v,b as y}from"./chunk-3P2KHV56.js";import{a as f,b as x,d as k}from"./chunk-URDMAXW6.js";import{k as b}from"./chunk-SYZTQIIC.js";import{C as l,a as h,b as a,d as c,f as g,g as _,h as o,k as m}from"./chunk-ZALBVT7T.js";import{a as n,h as i,j as u}from"./chunk-ORLIHI47.js";var e=class extends g{constructor(){super(...arguments);this._config={type:""};this._groups={};this._loaded=!1;this._busy=!1;this._error="";this._newName="";this._editingId=null;this._editingName="";this._access=f;this._hasInitiallyLoaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return m(this.hass)}get _canWrite(){return x(this.hass?.user,this._access)}updated(t){super.updated(t),t.has("hass")&&this.hass&&!this._hasInitiallyLoaded&&(this._hasInitiallyLoaded=!0,this._load(),k(this.hass).then(r=>{this._access=r.access}),u(this._lang).then(()=>this.requestUpdate()))}async _load(){let t=await l(this,{type:"maintenance_supporter/groups"},{onError:r=>{this._error=r}});t!==void 0&&(this._groups=t?.groups||{},this._loaded=!0)}async _act(t,r){this._error="",await l(this,t,{busy:s=>{this._busy=s},reload:async()=>{r?.(),await this._load()},onError:s=>{this._error=s}})}async _addGroup(){if(!this._canWrite)return;let t=this._newName.trim();t&&await this._act({type:"maintenance_supporter/group/create",name:t},()=>{this._newName=""})}_startEdit(t){this._editingId=t,this._editingName=this._groups[t]?.name||""}async _saveEdit(){if(!this._canWrite||!this._editingId)return;let t=this._editingName.trim();t&&await this._act({type:"maintenance_supporter/group/update",group_id:this._editingId,name:t},()=>{this._editingId=null,this._editingName=""})}async _deleteGroup(t,r){!this._canWrite||!await b(this.hass,{title:i("delete",this._lang),message:i("delete_group_confirm",this._lang).replace("{name}",r),confirmText:i("delete",this._lang),danger:!0})||await this._act({type:"maintenance_supporter/group/delete",group_id:t})}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_groups"),window.dispatchEvent(new CustomEvent("location-changed"))}_onKeyDown(t,r){t.key==="Enter"?(t.preventDefault(),r()):t.key==="Escape"&&(t.preventDefault(),this._editingId=null,this._editingName="")}render(){let t=this._lang;if(!this._loaded)return a`<ha-card><div class="loading">${i("loading",t)}</div></ha-card>`;let r=Object.keys(this._groups);return a`
<ha-card>
<div class="card-content">
<div class="header">
<div class="title">
<span class="emoji">🏷️</span>
<span>${this._config.title||i("groups",t)}</span>
<span class="count">${r.length}</span>
</div>
</div>
${this._error?a`<div class="error">${this._error}</div>`:c}
${r.length===0?a`<div class="empty">${i("groups_empty",t)}</div>`:a`
<div class="group-list">
${r.map(s=>{let d=this._groups[s],$=d.task_refs?.length??0,w=this._editingId===s;return a`
<div class="group-row">
${w?a`
<input class="edit-input" type="text"
.value=${this._editingName}
?disabled=${this._busy}
@input=${p=>{this._editingName=p.target.value}}
@keydown=${p=>this._onKeyDown(p,this._saveEdit.bind(this))} />
<button class="btn small primary"
@click=${this._saveEdit}
?disabled=${this._busy||!this._editingName.trim()}>
${i("save",t)}
</button>
<button class="btn small"
@click=${()=>{this._editingId=null}}>
${i("cancel",t)}
</button>
`:a`
<span class="group-name">${d.name||"Unnamed"}</span>
<span class="task-count">${$}</span>
${this._canWrite?a`
<button class="icon-btn"
title="${i("edit",t)}"
@click=${()=>this._startEdit(s)}
?disabled=${this._busy}>
<ha-icon icon="mdi:pencil"></ha-icon>
</button>
<button class="icon-btn danger"
title="${i("delete",t)}"
@click=${()=>this._deleteGroup(s,d.name||"Unnamed")}
?disabled=${this._busy}>
<ha-icon icon="mdi:delete"></ha-icon>
</button>
`:c}
`}
</div>
`})}
</div>
`}
${this._canWrite?a`
<div class="add-row">
<input type="text"
placeholder="${i("group_new_placeholder",t)}"
.value=${this._newName}
?disabled=${this._busy}
@input=${s=>{this._newName=s.target.value}}
@keydown=${s=>this._onKeyDown(s,this._addGroup.bind(this))} />
<button class="btn primary"
@click=${this._addGroup}
?disabled=${this._busy||!this._newName.trim()}>
<ha-icon icon="mdi:plus"></ha-icon>
${i("add",t)}
</button>
</div>
<button class="btn link" @click=${this._onDeepLink}>
${i("groups_manage_tasks",t)}
</button>
`:a`
<button class="btn link" @click=${this._onDeepLink}>
${i("groups_open_panel",t)}
</button>
`}
</div>
</ha-card>
`}};e.styles=[y,h`
.count {
font-size: 12px; color: var(--secondary-text-color);
background: var(--secondary-background-color);
padding: 2px 8px; border-radius: 999px;
}
.empty {
padding: 16px; text-align: center;
color: var(--secondary-text-color); font-style: italic;
}
.group-list { display: flex; flex-direction: column; gap: 4px; }
.group-row {
display: flex; align-items: center; gap: 8px;
padding: 6px 8px; border-radius: 6px;
background: var(--secondary-background-color, rgba(255,255,255,0.03));
}
.group-name { flex: 1; font-size: 14px; }
.task-count {
font-size: 11px; color: var(--secondary-text-color);
background: var(--card-background-color, rgba(0,0,0,0.2));
padding: 1px 8px; border-radius: 999px;
font-weight: 500;
}
.edit-input {
flex: 1; padding: 4px 8px; font-size: 14px;
background: var(--card-background-color, #1c1c1c);
color: var(--primary-text-color);
border: 1px solid var(--primary-color); border-radius: 4px;
font-family: inherit;
}
.icon-btn {
background: transparent; border: none; cursor: pointer;
color: var(--secondary-text-color); padding: 4px;
border-radius: 4px;
}
.icon-btn:hover {
background: var(--state-icon-color, rgba(255,255,255,0.06));
color: var(--primary-text-color);
}
.icon-btn.danger:hover { color: var(--error-color); }
.icon-btn ha-icon { --mdc-icon-size: 18px; }
.add-row {
display: flex; gap: 6px;
padding-top: 8px; border-top: 1px solid var(--divider-color);
}
.add-row input {
flex: 1; padding: 6px 8px; font-size: 13px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
font-family: inherit;
}
/* Card-specific overrides on the shared .btn */
.btn.small { padding: 4px 8px; font-size: 12px; }
.btn ha-icon { --mdc-icon-size: 16px; }
`],n([_({attribute:!1})],e.prototype,"hass",2),n([o()],e.prototype,"_config",2),n([o()],e.prototype,"_groups",2),n([o()],e.prototype,"_loaded",2),n([o()],e.prototype,"_busy",2),n([o()],e.prototype,"_error",2),n([o()],e.prototype,"_newName",2),n([o()],e.prototype,"_editingId",2),n([o()],e.prototype,"_editingName",2),n([o()],e.prototype,"_access",2);customElements.get("maintenance-groups-section-card")||customElements.define("maintenance-groups-section-card",e);v({type:"maintenance-groups-section-card",name:"Maintenance Supporter \u2014 Groups",description:"Create, rename and delete task groups right on the dashboard.",preview:!1});export{e as MaintenanceGroupsSectionCard};
@@ -0,0 +1,134 @@
/*! maintenance_supporter frontend 2.103.0 */
import{a as y,b as x}from"./chunk-3P2KHV56.js";import"./chunk-2AYG7EDK.js";import{b as p,k as $}from"./chunk-SYZTQIIC.js";import{C as u,a as v,b as r,d as c,f,g as m,h as n,j as b,k as g}from"./chunk-ZALBVT7T.js";import{a as s,h as a,j as h}from"./chunk-ORLIHI47.js";var i=class extends f{constructor(){super(...arguments);this._config={type:""};this._state=null;this._busy=!1;this._error="";this._localStart="";this._localEnd="";this._localBuffer="3";this._dirty=!1;this._loaded=!1}setConfig(t){this._config=t}getCardSize(){return 2}get _lang(){return g(this.hass)}get _isAdmin(){return this.hass?.user?.is_admin??!0}updated(t){super.updated(t),b(this,t),t.has("hass")&&this.hass&&!this._loaded&&(this._loaded=!0,this._load(),h(this._lang).then(()=>this.requestUpdate()))}async _load(){let t=await u(this,{type:"maintenance_supporter/vacation/state"},{onError:e=>{this._error=e}});t&&(this._state=t,this._localStart=t.start||"",this._localEnd=t.end||"",this._localBuffer=String(t.buffer_days??3),this._dirty=!1)}_act(t){return this._error="",u(this,t,{busy:e=>{this._busy=e},onError:e=>{this._error=e}})}async _toggleEnabled(t){let e=await this._act({type:"maintenance_supporter/vacation/update",enabled:t});e&&(this._state=e)}async _save(){if(!this._isAdmin)return;let[t,e]=p,o=Number(this._localBuffer);if(this._localBuffer.trim()===""||!Number.isInteger(o)||o<t||o>e){this._error=a("settings_value_out_of_range",this._lang).replace("{min}",String(t)).replace("{max}",String(e));return}let l=await this._act({type:"maintenance_supporter/vacation/update",start:this._localStart||null,end:this._localEnd||null,buffer_days:o});l&&(this._state=l,this._dirty=!1)}async _endNow(){if(!this._isAdmin||!await $(this.hass,{title:a("vacation_end_now",this._lang),message:a("vacation_end_now_confirm",this._lang),confirmText:a("vacation_end_now",this._lang)}))return;let e=await this._act({type:"maintenance_supporter/vacation/end_now"});e&&(this._state=e,this._localStart=e.start||"",this._localEnd=e.end||"")}_onDeepLink(){history.pushState(null,"","/maintenance-supporter?ms_action=open_vacation"),window.dispatchEvent(new CustomEvent("location-changed"))}render(){let t=this._lang,e=this._state;if(!e)return r`<ha-card><div class="loading">${a("loading",t)}</div></ha-card>`;let o=e.is_active===!0,l=e.enabled===!0,_=e.exempt_task_ids?.length??0,w=o?a("vacation_status_active",t):l?a("vacation_status_scheduled",t):a("vacation_status_inactive",t),k=o?"active":l?"scheduled":"inactive";return r`
<ha-card>
<div class="card-content">
<div class="header">
<div class="title">
<span class="emoji">🏖️</span>
<span>${this._config.title||a("vacation_mode",t)}</span>
</div>
<span class="status-pill ${k}">${w}</span>
</div>
${this._error?r`<div class="error">${this._error}</div>`:c}
${this._isAdmin?r`
<div class="row toggle-row">
<label>${a("enable",t)}</label>
<ha-switch
.checked=${l}
.disabled=${this._busy}
@change=${d=>this._toggleEnabled(d.target.checked)}
></ha-switch>
</div>
<div class="dates-row">
<div class="date-field">
<label>${a("vacation_start",t)}</label>
<ms-date-field
kind="date"
clearable
.hass=${this.hass}
.lang=${t}
.value=${this._localStart}
.disabled=${this._busy}
@value-changed=${d=>{this._localStart=d.detail.value,this._dirty=!0}}
></ms-date-field>
</div>
<div class="date-field">
<label>${a("vacation_end",t)}</label>
<ms-date-field
kind="date"
clearable
.hass=${this.hass}
.lang=${t}
.value=${this._localEnd}
.disabled=${this._busy}
@value-changed=${d=>{this._localEnd=d.detail.value,this._dirty=!0}}
></ms-date-field>
</div>
<div class="date-field buffer">
<label>${a("vacation_buffer",t)}</label>
<input type="number" min=${p[0]} max=${p[1]}
.value=${this._localBuffer}
?disabled=${this._busy}
@input=${d=>{this._localBuffer=d.target.value,this._dirty=!0}} />
</div>
</div>
<div class="actions">
<button class="btn ${this._dirty?"primary":"muted"}"
@click=${this._save}
?disabled=${this._busy||!this._dirty}>
<ha-icon icon="${this._dirty?"mdi:content-save":"mdi:check"}"></ha-icon>
${this._dirty?a("save",t):a("saved",t)}
</button>
${o?r`<button class="btn"
@click=${this._endNow}
?disabled=${this._busy}>
${a("vacation_end_now",t)}
</button>`:c}
${_>0?r`<button class="btn link"
@click=${this._onDeepLink}>
${_} ${a("vacation_exempt_count",t)}…
</button>`:r`<button class="btn link"
@click=${this._onDeepLink}>
${a("vacation_advanced",t)}
</button>`}
</div>
`:r`
<div class="readonly">
${l&&e.start&&e.end?r`<div>${e.start} → ${e.end}</div>`:c}
<button class="btn link" @click=${this._onDeepLink}>
${a("vacation_open_panel",t)}
</button>
</div>
`}
</div>
</ha-card>
`}};i.styles=[x,v`
.status-pill {
font-size: 11px; font-weight: 600;
padding: 3px 8px; border-radius: 999px;
text-transform: uppercase; letter-spacing: 0.5px;
}
.status-pill.active {
background: rgba(76, 175, 80, 0.15);
color: #4caf50;
}
.status-pill.scheduled {
background: rgba(255, 152, 0, 0.15);
color: #ff9800;
}
.status-pill.inactive {
background: rgba(158, 158, 158, 0.15);
color: var(--secondary-text-color);
}
.row.toggle-row {
display: flex; align-items: center; justify-content: space-between;
}
.row.toggle-row label {
font-size: 14px; color: var(--primary-text-color);
}
.dates-row {
display: grid; grid-template-columns: 1fr 1fr 100px; gap: 10px;
}
.date-field.buffer label { white-space: nowrap; }
.date-field { display: flex; flex-direction: column; gap: 4px; }
.date-field label {
font-size: 11px; color: var(--secondary-text-color);
text-transform: uppercase; letter-spacing: 0.3px;
}
.date-field input {
padding: 6px 8px; font-size: 13px;
background: var(--secondary-background-color, #2c2c2c);
color: var(--primary-text-color);
border: 1px solid var(--divider-color); border-radius: 6px;
font-family: inherit;
}
.date-field input:disabled { opacity: 0.5; cursor: not-allowed; }
.actions {
display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.readonly { display: flex; flex-direction: column; gap: 8px; }
`],s([m({attribute:!1})],i.prototype,"hass",2),s([n()],i.prototype,"_config",2),s([n()],i.prototype,"_state",2),s([n()],i.prototype,"_busy",2),s([n()],i.prototype,"_error",2),s([n()],i.prototype,"_localStart",2),s([n()],i.prototype,"_localEnd",2),s([n()],i.prototype,"_localBuffer",2),s([n()],i.prototype,"_dirty",2);customElements.get("maintenance-vacation-section-card")||customElements.define("maintenance-vacation-section-card",i);y({type:"maintenance-vacation-section-card",name:"Maintenance Supporter \u2014 Vacation",description:"Switch vacation mode on or off and set its dates right on the dashboard.",preview:!1});export{i as MaintenanceVacationSectionCard};
File diff suppressed because one or more lines are too long