test: cover help and feedback browser flows (#43)

Issue: #43
User-Visible: no
This commit is contained in:
Sergey Matyunin
2026-09-02 02:52:24 +03:00
parent 40d63080bd
commit 0e0ca3d4dc
25 changed files with 532 additions and 173 deletions
@@ -1,125 +1,125 @@
{
"schema": 1,
"fingerprint": "c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6",
"fingerprint": "6235a41ecc5f366d871f78c16e149901360ea2a58761e839b0f53c6527b5e9ed",
"entry": "houseplan-card.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-D2QbRkX7.js",
"houseplan-assets/houseplan-card-CZDS_78e.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 290374,
"initialViewGzipBytes": 290378,
"lazyFiles": [
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/fr-yr6HN0On.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
"houseplan-assets/backdrop-pick-BOES8LdP.js",
"houseplan-assets/de-CAtsunWz.js",
"houseplan-assets/editor-DCuNBi0k.js",
"houseplan-assets/fr-Bqax3ohv.js",
"houseplan-assets/houseplan-editor-runtime-DvhfS-p7.js",
"houseplan-assets/houseplan-onboarding-runtime-BeUYskCk.js"
],
"lazyGzipBytes": 205802,
"lazyGzipBytes": 205828,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js"
"houseplan-assets/backdrop-pick-BOES8LdP.js",
"houseplan-assets/editor-DCuNBi0k.js",
"houseplan-assets/houseplan-editor-runtime-DvhfS-p7.js"
],
"lazyEditorGzipBytes": 148714,
"lazyEditorGzipBytes": 148719,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
"houseplan-assets/backdrop-pick-BOES8LdP.js",
"houseplan-assets/houseplan-onboarding-runtime-BeUYskCk.js"
],
"lazyOnboardingGzipBytes": 14026,
"lazyOnboardingGzipBytes": 14029,
"lazyLocaleFiles": [
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/fr-yr6HN0On.js"
"houseplan-assets/de-CAtsunWz.js",
"houseplan-assets/fr-Bqax3ohv.js"
],
"lazyLocaleGzipBytes": 50132,
"lazyLocaleGzipBytes": 50151,
"files": [
{
"path": "houseplan-assets/backdrop-pick-y86gdzEv.js",
"sha256": "753369b21d0b9d1b2e5c780452c3b41ae29bbb00ef5787c859e2d11dac2aa6d8",
"path": "houseplan-assets/backdrop-pick-BOES8LdP.js",
"sha256": "aea5ea988e5aff3ffa8765511b0ed96acd7b4b3b5f3719242360716f3c6bd502",
"rawBytes": 20636,
"gzipBytes": 7070,
"gzipBytes": 7071,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D2QbRkX7.js"
"houseplan-assets/houseplan-card-CZDS_78e.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-5bH7Tqw5.js",
"sha256": "67422f19ed35403583f3b438f6f3efc83ede77164f79d612754660b19090ef58",
"path": "houseplan-assets/de-CAtsunWz.js",
"sha256": "883dd5ab7905636373de30c2793fc5418d867087644dc198f93576eb4b87cd3a",
"rawBytes": 83981,
"gzipBytes": 25337,
"gzipBytes": 25347,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-CXgHU1PF.js",
"sha256": "df251d831416ffa58a648577024f66f8e3f05a2890d338d0772870e7dff202fc",
"path": "houseplan-assets/editor-DCuNBi0k.js",
"sha256": "55ddef2226d3bc262b582216e556c667ad3dd8c2e793891afee33d1fb6687bdb",
"rawBytes": 3826,
"gzipBytes": 1580,
"gzipBytes": 1581,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D2QbRkX7.js"
"houseplan-assets/houseplan-card-CZDS_78e.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-yr6HN0On.js",
"sha256": "8a9bf182a81ea57869accbba27e97029f554d624b0fc68d59688279b023b2b3a",
"path": "houseplan-assets/fr-Bqax3ohv.js",
"sha256": "5f75459b58f7bd380c21eb6998b417e743f65270425b2bc1dc46e9785d71ac56",
"rawBytes": 86212,
"gzipBytes": 24795,
"gzipBytes": 24804,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-D2QbRkX7.js",
"sha256": "98224a3ef6c2b7fa837fd0771cee732a2e4ed88127dd7b83283728d93bc477ed",
"path": "houseplan-assets/houseplan-card-CZDS_78e.js",
"sha256": "7bac8a128b73c811e62484ce99a13a121b7bb25c1dfc8fa48a49715f1c4a3690",
"rawBytes": 1032271,
"gzipBytes": 289578,
"gzipBytes": 289581,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/fr-yr6HN0On.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
"houseplan-assets/de-CAtsunWz.js",
"houseplan-assets/editor-DCuNBi0k.js",
"houseplan-assets/fr-Bqax3ohv.js",
"houseplan-assets/houseplan-editor-runtime-DvhfS-p7.js",
"houseplan-assets/houseplan-onboarding-runtime-BeUYskCk.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"sha256": "0cece0a10a2d63fbd1dadfd1e0837049c79041c66662d1b63e71b4bd61669d72",
"path": "houseplan-assets/houseplan-editor-runtime-DvhfS-p7.js",
"sha256": "0d15c5f868b3684dbf6d81ebfbe925f874f08b3e8a68db12f160f3807d22ee20",
"rawBytes": 543272,
"gzipBytes": 140064,
"gzipBytes": 140067,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-card-D2QbRkX7.js"
"houseplan-assets/backdrop-pick-BOES8LdP.js",
"houseplan-assets/houseplan-card-CZDS_78e.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js",
"sha256": "9a654161d364ab4a9e40036401f400cb7ba39412a9024b4b4f30a7d5cec32da9",
"path": "houseplan-assets/houseplan-onboarding-runtime-BeUYskCk.js",
"sha256": "c119a22e0435de0f3e7ed8c62f5813f7aeee31e1da8698f3506ab19e4a7c87a1",
"rawBytes": 28088,
"gzipBytes": 6956,
"gzipBytes": 6958,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-card-D2QbRkX7.js"
"houseplan-assets/backdrop-pick-BOES8LdP.js",
"houseplan-assets/houseplan-card-CZDS_78e.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "eb53af1be3c6e20eb7a948f738a9efd1e11ae1322592b9f27955020cf70d983e",
"sha256": "d538bbccca6042eee23ee0df4506530c5bf121824167e6a30cac722ce6ba1b1c",
"rawBytes": 1183,
"gzipBytes": 796,
"gzipBytes": 797,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-D2QbRkX7.js"
"houseplan-assets/houseplan-card-CZDS_78e.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";import{b as e,l as o,t,d8 as s,A as a,d9 as i,da as l,db as n,E as r,c}from"./houseplan-card-D2QbRkX7.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="6235a41ecc5f366d871f78c16e149901360ea2a58761e839b0f53c6527b5e9ed";import{b as e,l as o,t,d8 as s,A as a,d9 as i,da as l,db as n,E as r,c}from"./houseplan-card-CZDS_78e.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
.hass=${this.hass}
.data=${this._formData}
.schema=${e}
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";import{l as t,ar as s,A as e,t as o,c as a,bW as l,bX as i,bY as h,bZ as c,ao as n,b_ as r,c3 as p,b$ as _,c0 as d,c1 as u,c2 as g,cY as m,an as b,ap as $,cZ as v}from"./houseplan-card-D2QbRkX7.js";import{i as f,c as y,e as w,r as D,a as k,b as S,s as C,t as M}from"./backdrop-pick-y86gdzEv.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?a`<hp-help data-help-key=${l}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="6235a41ecc5f366d871f78c16e149901360ea2a58761e839b0f53c6527b5e9ed";import{l as t,ar as s,A as e,t as o,c as a,bW as l,bX as i,bY as h,bZ as c,ao as n,b_ as r,c3 as p,b$ as _,c0 as d,c1 as u,c2 as g,cY as m,an as b,ap as $,cZ as v}from"./houseplan-card-CZDS_78e.js";import{i as f,c as y,e as w,r as D,a as k,b as S,s as C,t as M}from"./backdrop-pick-BOES8LdP.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="6235a41ecc5f366d871f78c16e149901360ea2a58761e839b0f53c6527b5e9ed";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?a`<hp-help data-help-key=${l}
.text=${o(h,l)} .ariaLabel=${o(h,i)}></hp-help>`:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const o=l(e),a=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?i(e.settings.custom_fill):null,p="none"===o.fill?{...a||h,a:0}:a;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:o.showBorders,showNames:o.showNames,zeroWallStyle:r(e),displayTouched:!0,hideDecor:o.hideDecor,hideOpenings:o.hideOpenings,roomColor:o.color,roomOpacity:o.opacity,fillMode:"none"===o.fill?"custom":o.fill,customFill:p,glowEnabled:o.glow,bgColor:o.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:n({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:o.tempMin,tempMax:o.tempMax,showLqi:o.showLqi??this.host._config?.show_signal??!0,cardFontScale:o.cardFontScale,labelTemp:o.labelTemp,labelHum:o.labelHum,labelLqi:o.labelLqi,labelLight:o.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:c(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...f(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:d,tempMax:_,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:c(e,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const o=await y(e);if("reject"===o.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===o.kind)return void(this.host._backdropGuard=o.state);const a=await w(e,o.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:a})}_renderBackdropGuard(){return D(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const o=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),a=this.host._spaceDialog,l=a?.saved?.find(s=>s.name===t);if(o&&a&&l&&l.url===e.url&&l.modified===e.modified&&!l.used_by.length&&l.url!==a.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return a`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return a`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return a`<div class="savedplans">
${s.map(s=>{return a`
<div class="savedplan ${s.url===t.planUrl?"cur":""}">
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";try{await import("./houseplan-assets/houseplan-card-D2QbRkX7.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale entry: the main chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="6235a41ecc5f366d871f78c16e149901360ea2a58761e839b0f53c6527b5e9ed";try{await import("./houseplan-assets/houseplan-card-CZDS_78e.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale entry: the main chunk is unavailable",e)}
+57 -2
View File
@@ -32,6 +32,9 @@ const spanOverDoorFixture = JSON.parse(readFileSync(
const wallUnionIsolationFixture = JSON.parse(readFileSync(
new URL('../../test/fixtures/278-wall-union-isolation.json', import.meta.url), 'utf8',
));
const cardVersion = JSON.parse(readFileSync(
new URL('../../package.json', import.meta.url), 'utf8',
)).version;
const fixtureFor = (scenario) => scenario.fixture === 'large'
? makeLargeHouseFixture()
@@ -733,7 +736,7 @@ export async function prepareGoldenScenario(page, scenario) {
await page.mouse.move(0, 0);
const fixture = prepareGoldenFixture(scenario);
const result = await page.evaluate(async ({ fixture, scenario }) => {
const result = await page.evaluate(async ({ fixture, scenario, cardVersion }) => {
const wait = (ms) => new Promise((done) => setTimeout(done, ms));
const frame = () => new Promise((done) => requestAnimationFrame(() => requestAnimationFrame(done)));
const until = async (predicate, timeout = 10000) => {
@@ -1599,6 +1602,58 @@ export async function prepareGoldenScenario(page, scenario) {
if (trigger.getAttribute('aria-expanded') !== 'true' || !inside(triggerRect)
|| !inside(surfaceRect) || dialog.scrollWidth > dialog.clientWidth + 1)
throw new Error(`golden general-settings help is clipped: ${scenario.openHelp}`);
} else if (scenario.dialog === 'support') {
card._haIntegrationVersion = cardVersion;
card._openSupportDialog();
await card.updateComplete;
const opened = card._supportDialog;
const text = '{"format":"houseplan-support-package","version":1}\n';
const preview = {
token: 'a'.repeat(48),
expiresAt: Date.now() + 300_000,
size: new TextEncoder().encode(text).byteLength,
sha256: 'b'.repeat(64),
spaces: 2,
format: 'houseplan-support-package',
version: 1,
text,
preparedAt: Date.now() - 60_000,
};
const patch = scenario.supportState === 'empty' ? {}
: scenario.supportState === 'preview' ? {
contact: 'user@example.test', message: 'The room light is not rendered.',
attach: true, status: 'ready', preview,
} : scenario.supportState === 'validation' ? {
status: 'error', errorCode: 'validation.message_required',
} : scenario.supportState === 'success' ? {
contact: 'user@example.test', message: 'The room light is not rendered.',
status: 'success', reportId: 'HP-43-GOLDEN',
} : scenario.supportState === 'relay-error' ? {
contact: '@houseplan-user', message: 'The report relay timed out.',
attach: true, status: 'error', preview, errorCode: 'support_rate_limited',
} : null;
if (!opened || !patch) {
throw new Error(`invalid golden support state: ${scenario.id}`);
}
card._supportDialog = { ...opened, ...patch };
card.requestUpdate();
await card.updateComplete;
await frame();
const dialog = card.renderRoot.querySelector('#support-dialog');
const body = dialog?.querySelector('.supportbody');
const expected = scenario.supportState === 'preview' ? '.supportpreview'
: scenario.supportState === 'validation' || scenario.supportState === 'relay-error'
? '#support-error'
: scenario.supportState === 'success' ? '#support-receipt' : '.supportform';
const focus = dialog?.querySelector(expected);
focus?.scrollIntoView({ block: 'center', inline: 'nearest' });
await frame();
if (!dialog || !body || !focus || body.scrollWidth > body.clientWidth + 1
|| dialog.scrollWidth > dialog.clientWidth + 1
|| !dialog.querySelector('.aboutver')
|| dialog.querySelectorAll('a.aboutlink').length < 3) {
throw new Error(`golden support dialog is incomplete or clipped: ${scenario.id}`);
}
} else if (scenario.dialog === 'device-ripple-color') {
card._setMode('devices');
await card.updateComplete;
@@ -1753,7 +1808,7 @@ export async function prepareGoldenScenario(page, scenario) {
cachedRays: card._sunRaysCache?.rays?.length || 0,
} } : {}),
};
}, { fixture, scenario });
}, { fixture, scenario, cardVersion });
if (scenario.tabDrag) {
const drag = await page.evaluate((placement) => {
const card = window.__goldenCard;
+22 -1
View File
@@ -1,7 +1,7 @@
import { fixtureWallKey } from '../fixtures/visual-matrix.mjs';
/** Data-only HP-QA-01 capture matrix. Bump when framing or scenarios change. */
export const GOLDEN_MATRIX_VERSION = 53;
export const GOLDEN_MATRIX_VERSION = 54;
const stage = { capture: 'stage', threshold: { maxChannelDelta: 10, maxDiffRatio: 0.0005 } };
const page = { capture: 'page', threshold: { maxChannelDelta: 10, maxDiffRatio: 0.0008 } };
@@ -824,6 +824,27 @@ export const GOLDEN_SCENARIOS = Object.freeze([
dialog: 'general-help', openHelp: 'gs.bg_mode.help', deviceScaleFactor: 2,
helpTextRegion: { key: 'gs.bg_mode.help', minPixels: 30 },
language: 'ru', theme: 'dark', viewport: { width: 390, height: 900 }, ...page },
// #43 AC14: the support dialog owns reviewed desktop, phone and tablet
// states. The six scenes deliberately cover both themes while keeping the
// individual states named in the specification independently reviewable.
{ id: 'support-desktop-empty-light-en', fixture: 'visual', space: 'golden-geometry',
dialog: 'support', supportState: 'empty', language: 'en', theme: 'light',
viewport: { width: 1000, height: 980 }, ...page },
{ id: 'support-desktop-preview-dark-en', fixture: 'visual', space: 'golden-geometry',
dialog: 'support', supportState: 'preview', language: 'en', theme: 'dark',
viewport: { width: 1000, height: 980 }, ...page },
{ id: 'support-phone-validation-light-ru', fixture: 'visual', space: 'golden-geometry',
dialog: 'support', supportState: 'validation', language: 'ru', theme: 'light',
viewport: { width: 320, height: 760 }, ...page },
{ id: 'support-phone-success-dark-en', fixture: 'visual', space: 'golden-geometry',
dialog: 'support', supportState: 'success', language: 'en', theme: 'dark',
viewport: { width: 390, height: 820 }, ...page },
{ id: 'support-relay-error-light-en', fixture: 'visual', space: 'golden-geometry',
dialog: 'support', supportState: 'relay-error', language: 'en', theme: 'light',
viewport: { width: 900, height: 900 }, ...page },
{ id: 'support-tablet-preview-dark-ru', fixture: 'visual', space: 'golden-geometry',
dialog: 'support', supportState: 'preview', language: 'ru', theme: 'dark',
viewport: { width: 768, height: 900 }, ...page },
{ id: 'device-ripple-color-popover-mobile-ru', fixture: 'visual', space: 'golden-lighting',
dialog: 'device-ripple-color', deviceId: 'golden-light-two',
language: 'ru', theme: 'dark', viewport: { width: 390, height: 1000 }, ...page },
+7 -26
View File
@@ -1,5 +1,4 @@
import { launch, check, checkAll, finish } from './serve.mjs';
import { readFileSync } from 'node:fs';
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch();
const res = await page.evaluate(async () => {
const out = {};
@@ -22,10 +21,10 @@ const res = await page.evaluate(async () => {
.find((row) => row.textContent.trim() === c._t('gs.wall_group'));
out.glowRadiusInsideGlowGroup = !!glowRadius && !!wallGroup
&& !!(glowRadius.compareDocumentPosition(wallGroup) & Node.DOCUMENT_POSITION_FOLLOWING);
// 1b) блок About: версия + две внешние ссылки (target=_blank rel=noopener)
out.aboutVersion = sr().querySelector('hp-dialog .aboutver')?.textContent.trim() ?? null;
out.aboutLinks = [...sr().querySelectorAll('hp-dialog a.aboutlink')].map((a) => ({
href: a.getAttribute('href'), target: a.getAttribute('target'), rel: a.getAttribute('rel') }));
// #43: About moved into the dedicated Help & Feedback dialog and must not
// survive as a duplicate at the bottom of General Settings.
out.aboutMovedOut = !sr().querySelector('hp-dialog .aboutver')
&& sr().querySelectorAll('hp-dialog a.aboutlink').length === 0;
// 2) сменить цвет light_on и сохранить
c._setFillColor('light_on', { c: '#ff00ff', a: 0.5 });
await c._saveSettingsDialog(); await c.updateComplete;
@@ -54,30 +53,12 @@ const res = await page.evaluate(async () => {
out.spaceLqiOverridesCardDefault = sr().querySelectorAll('.dev .lqi').length > 0;
return out;
});
// CARD_VERSION из собранного бандла (тот же текст уходит в console-баннер).
// terser либо инлайнит строку (v1.56.0), либо оставляет переменную (v${xx}) —
// во втором случае доразрешаем её по присваиванию xx="1.56.0".
// Версия — SemVer, у пре-релиза есть суффикс (1.58.0-beta.1), он тоже часть строки.
const assetsRoot = new URL('./srv/assets/', import.meta.url);
const assetManifest = JSON.parse(readFileSync(new URL('houseplan-assets.json', assetsRoot), 'utf8'));
const bundle = assetManifest.files
.filter((file) => file.path.endsWith('.js'))
.map((file) => readFileSync(new URL(file.path, assetsRoot), 'utf8'))
.join('\n');
const SEMVER = '\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?';
const m = bundle.match(new RegExp(`HOUSEPLAN-CARD %c v(?:(${SEMVER})|\\$\\{(\\w+)\\})`));
const BUNDLE_VERSION = m?.[1] ?? (m?.[2] && bundle.match(new RegExp(`[^\\w$]${m[2]}="(${SEMVER})"`))?.[1]);
check('bundleVersionFound', typeof BUNDLE_VERSION === 'string' && BUNDLE_VERSION.length > 0);
// значения зафиксированы прогоном на v1.43.1 и сверены с кодом (audit T1)
checkAll(res, {
"rows": 15, // 11 цветов (включая wall_fill) + радиус свечения + фон
// + «Оптимизировать планы» (docs/CANVAS.md §9)
"groups": ["Fill: lights", "Fill: temperature", "Fill: zigbee signal", "Light-source glow", "Walls", "Stage background", "Sun", "Backup and transfer", "Plan maintenance", "About"],
"aboutVersion": `Houseplan Card v${BUNDLE_VERSION}`, // та же константа, что в баннере
"aboutLinks": [
{ "href": "https://github.com/Matysh/houseplan-card", "target": "_blank", "rel": "noopener" },
{ "href": "https://t.me/ha_houseplan", "target": "_blank", "rel": "noopener" },
],
"groups": ["Fill: lights", "Fill: temperature", "Fill: zigbee signal", "Light-source glow", "Walls", "Stage background", "Sun", "Backup and transfer", "Plan maintenance"],
"aboutMovedOut": true,
"saved": {"c": "#ff00ff", "a": 0.5},
"newSpaceUsesDaynight": true,
"floorImportUsesDaynight": true,
+270
View File
@@ -0,0 +1,270 @@
import { createHash } from 'node:crypto';
import { readFileSync } from 'node:fs';
import { launch, checkAll, finish } from './serve.mjs';
const VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
const PREVIEW_TEXT = '{"format":"houseplan-support-package","version":1}\n';
const PREVIEW_SHA = createHash('sha256').update(PREVIEW_TEXT).digest('hex');
const { page, browser } = await launch({ width: 1000, height: 900 });
const result = await page.evaluate(async ({ version, previewText, previewSha }) => {
const card = window.__card;
const root = () => card.renderRoot || card.shadowRoot;
const wait = (ms = 0) => new Promise((resolve) => setTimeout(resolve, ms));
const frame = () => new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
const until = async (predicate, label, attempts = 100) => {
for (let index = 0; index < attempts; index++) {
if (predicate()) return;
await wait(10);
}
throw new Error(`support smoke timed out: ${label}`);
};
const update = async () => {
await card.updateComplete;
await frame();
};
const setInput = async (selector, value) => {
const input = root().querySelector(selector);
if (!input) throw new Error(`support smoke input missing: ${selector}`);
input.value = value;
input.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
await update();
};
const close = async () => {
await card._editorRuntime._closeSupportDialog();
await update();
};
const open = async () => {
const button = root().querySelector('.support-button');
if (!button) throw new Error('support button missing');
button.click();
await until(() => !!card._supportDialog, 'dialog open');
await update();
};
card._haIntegrationVersion = version;
const originalCallWS = card.hass.callWS.bind(card.hass);
const calls = [];
let submitMode = 'success';
card.hass = {
...card.hass,
callWS: async (message) => {
if (!String(message.type || '').startsWith('houseplan/support/')) {
return originalCallWS(message);
}
calls.push(structuredClone(message));
if (message.type === 'houseplan/support/preview') {
return {
text: previewText,
size: new TextEncoder().encode(previewText).byteLength,
expires_in: 300,
spaces: 2,
token: 'a'.repeat(48),
sha256: previewSha,
version: 1,
format: 'houseplan-support-package',
};
}
if (message.type === 'houseplan/support/submit') {
if (submitMode === 'rate') throw { code: 'support_rate_limited' };
if (submitMode === 'timeout') throw { code: 'support_unavailable' };
if (submitMode === 'unknown') throw { code: 'unknown_command' };
return { report_id: 'HP-43-SMOKE' };
}
return { ok: true };
},
};
await update();
const out = {};
const modeResults = [];
for (const mode of ['view', 'plan', 'devices', 'decor']) {
card._setMode(mode);
await until(() => card._mode === mode && !card._modeTransitionBusy, `mode ${mode}`);
await update();
const before = {
mode: card._mode,
zoom: card._zoom,
selectedDevice: card._selId,
selectedDecor: card._decorSel,
};
const button = root().querySelector('.support-button');
const settings = button?.previousElementSibling;
await open();
modeResults.push({
mode,
afterSettings: settings?.querySelector('ha-icon')?.getAttribute('icon') === 'mdi:cog-outline',
unchanged: JSON.stringify(before) === JSON.stringify({
mode: card._mode,
zoom: card._zoom,
selectedDevice: card._selId,
selectedDecor: card._decorSel,
}),
});
await close();
}
out.modeAndOrder = modeResults.every((item) => item.afterSettings && item.unchanged)
&& new Set(modeResults.map((item) => item.mode)).size === 4;
const originalConfig = card._config;
card._config = { ...card._config, kiosk: true };
card.requestUpdate();
await update();
const kioskButton = root().querySelector('.support-button');
out.kioskHidden = !kioskButton || getComputedStyle(kioskButton).display === 'none'
|| getComputedStyle(kioskButton.closest('.hdr')).display === 'none';
card._config = originalConfig;
card._serverCanWrite = false;
card.requestUpdate();
await update();
out.readonlyAbsent = !root().querySelector('.support-button');
card._serverCanWrite = true;
card.requestUpdate();
await update();
const supportCallsBeforeOpen = calls.length;
await open();
const dialog = root().querySelector('#support-dialog');
const touchRect = root().querySelector('.support-button').getBoundingClientRect();
const guide = dialog?.querySelector('#support-docs-heading + a');
out.openIsLocal = calls.length === supportCallsBeforeOpen;
out.aboutAndEnglishGuide = !!dialog?.querySelector('.aboutver')
&& dialog.querySelectorAll('.supportlinks a.aboutlink').length === 2
&& guide?.href.endsWith('/docs/USER-GUIDE.md');
out.freshDefaults = dialog?.querySelector('#support-contact')?.value === ''
&& dialog?.querySelector('#support-message')?.value === ''
&& dialog?.querySelector('.supportattach input')?.checked === false;
out.touchTarget = touchRect.width >= 44 && touchRect.height >= 44;
out.noHorizontalOverflow = dialog.scrollWidth <= dialog.clientWidth + 1
&& dialog.querySelector('.supportbody').scrollWidth
<= dialog.querySelector('.supportbody').clientWidth + 1;
await close();
card._config = { ...card._config, language: 'ru' };
await open();
out.russianGuide = root().querySelector('#support-docs-heading + a')?.href
.endsWith('/docs/USER-GUIDE.ru.md') === true;
await close();
card._config = { ...card._config, language: 'en' };
card._haIntegrationVersion = '0.0.0';
await open();
out.oldBackendDegrades = !!root().querySelector('#support-dialog .supportupdate')
&& !root().querySelector('#support-dialog .supportform')
&& !!root().querySelector('#support-dialog .aboutver')
&& root().querySelectorAll('#support-dialog a.aboutlink').length >= 3;
await close();
card._haIntegrationVersion = version;
await open();
const submitCallsBeforeValidation = calls.filter((call) => call.type === 'houseplan/support/submit').length;
await card._editorRuntime._submitSupport();
await update();
out.validation = card._supportDialog?.errorCode === 'validation.message_required'
&& root().activeElement?.id === 'support-message'
&& calls.filter((call) => call.type === 'houseplan/support/submit').length
=== submitCallsBeforeValidation;
await setInput('#support-contact', ' user@example.test ');
await setInput('#support-message', ' Exact support message. ');
root().querySelector('.supportattach input').click();
await until(() => card._supportDialog?.status === 'ready', 'preview ready');
await update();
const preview = card._supportDialog.preview;
root().querySelector('.supportpreview summary').click();
await update();
out.preview = !!root().querySelector('.supportwarning')
&& root().querySelector('.supportraw')?.value === previewText
&& preview?.text === previewText
&& preview?.sha256 === previewSha
&& root().querySelector('.supporthash code')?.textContent === previewSha;
let downloadedBlob = null;
let downloadedName = '';
const originalCreateObjectURL = URL.createObjectURL;
const originalRevokeObjectURL = URL.revokeObjectURL;
const originalAnchorClick = HTMLAnchorElement.prototype.click;
URL.createObjectURL = (blob) => { downloadedBlob = blob; return 'blob:houseplan-smoke'; };
URL.revokeObjectURL = () => {};
HTMLAnchorElement.prototype.click = function click() { downloadedName = this.download; };
card._editorRuntime._downloadSupportPreview();
const downloadedText = await downloadedBlob?.text();
URL.createObjectURL = originalCreateObjectURL;
URL.revokeObjectURL = originalRevokeObjectURL;
HTMLAnchorElement.prototype.click = originalAnchorClick;
out.downloadExact = downloadedText === previewText
&& downloadedName === `houseplan-support-${'a'.repeat(12)}.json`;
submitMode = 'success';
root().querySelector('#support-dialog .supportfooter .btn.on').click();
await until(() => card._supportDialog?.status === 'success', 'success submit');
await update();
const successRequest = calls.findLast((call) => call.type === 'houseplan/support/submit');
out.success = root().querySelector('#support-receipt')?.textContent.includes('HP-43-SMOKE') === true
&& root().activeElement?.id === 'support-receipt'
&& successRequest?.message === 'Exact support message.'
&& successRequest?.contact === 'user@example.test'
&& successRequest?.preview_token === 'a'.repeat(48);
await close();
await open();
out.freshAfterSuccess = card._supportDialog?.contact === ''
&& card._supportDialog?.message === '' && card._supportDialog?.attach === false;
await setInput('#support-message', 'Retry this exact message.');
const retryKey = card._supportDialog.idempotencyKey;
submitMode = 'rate';
root().querySelector('#support-dialog .supportfooter .btn.on').click();
await until(() => card._supportDialog?.status === 'error', 'rate limit error');
await update();
const ratePreserved = card._supportDialog.message === 'Retry this exact message.'
&& !!root().querySelector('.supportmanual')
&& !root().querySelector('#support-receipt');
submitMode = 'timeout';
root().querySelector('#support-dialog .supportfooter .btn.on').click();
await until(() => card._supportDialog?.errorCode === 'support_unavailable', 'timeout error');
submitMode = 'unknown';
root().querySelector('#support-dialog .supportfooter .btn.on').click();
await until(() => card._supportDialog?.status === 'error', 'unknown command error');
submitMode = 'success';
root().querySelector('#support-dialog .supportfooter .btn.on').click();
await until(() => card._supportDialog?.status === 'success', 'retry success');
await update();
const retryRequests = calls.filter((call) => call.type === 'houseplan/support/submit'
&& call.message === 'Retry this exact message.');
out.retryAndManualRecovery = ratePreserved && retryRequests.length === 4
&& retryRequests.every((call) => call.idempotency_key === retryKey)
&& root().querySelector('#support-receipt')?.textContent.includes('HP-43-SMOKE') === true;
return out;
}, { version: VERSION, previewText: PREVIEW_TEXT, previewSha: PREVIEW_SHA });
const responsive = async (viewport) => {
await page.setViewportSize(viewport);
return page.evaluate(async () => {
const card = window.__card;
if (card._supportDialog) await card._editorRuntime._closeSupportDialog();
card._setMode('view');
await card.updateComplete;
const button = card.renderRoot.querySelector('.support-button');
button?.click();
await card.updateComplete;
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
const dialog = card.renderRoot.querySelector('#support-dialog');
const body = dialog?.querySelector('.supportbody');
const footer = dialog?.querySelector('.supportfooter');
const dialogRect = dialog?.getBoundingClientRect();
const buttonRect = button?.getBoundingClientRect();
return !!dialog && !!body && !!footer && !!dialogRect && !!buttonRect
&& dialogRect.left >= -1 && dialogRect.right <= innerWidth + 1
&& dialogRect.top >= -1 && dialogRect.bottom <= innerHeight + 1
&& dialog.scrollWidth <= dialog.clientWidth + 1
&& body.scrollWidth <= body.clientWidth + 1
&& body.clientHeight > 0 && footer.getBoundingClientRect().height > 0
&& buttonRect.width >= 44 && buttonRect.height >= 44;
});
};
result.phonePortrait = await responsive({ width: 320, height: 760 });
result.phoneLandscape = await responsive({ width: 760, height: 320 });
checkAll(result);
await finish(browser, result);
+55 -55
View File
@@ -1,125 +1,125 @@
{
"schema": 1,
"fingerprint": "c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6",
"fingerprint": "6235a41ecc5f366d871f78c16e149901360ea2a58761e839b0f53c6527b5e9ed",
"entry": "houseplan-card.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-D2QbRkX7.js",
"houseplan-assets/houseplan-card-CZDS_78e.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 290374,
"initialViewGzipBytes": 290378,
"lazyFiles": [
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/fr-yr6HN0On.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
"houseplan-assets/backdrop-pick-BOES8LdP.js",
"houseplan-assets/de-CAtsunWz.js",
"houseplan-assets/editor-DCuNBi0k.js",
"houseplan-assets/fr-Bqax3ohv.js",
"houseplan-assets/houseplan-editor-runtime-DvhfS-p7.js",
"houseplan-assets/houseplan-onboarding-runtime-BeUYskCk.js"
],
"lazyGzipBytes": 205802,
"lazyGzipBytes": 205828,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js"
"houseplan-assets/backdrop-pick-BOES8LdP.js",
"houseplan-assets/editor-DCuNBi0k.js",
"houseplan-assets/houseplan-editor-runtime-DvhfS-p7.js"
],
"lazyEditorGzipBytes": 148714,
"lazyEditorGzipBytes": 148719,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
"houseplan-assets/backdrop-pick-BOES8LdP.js",
"houseplan-assets/houseplan-onboarding-runtime-BeUYskCk.js"
],
"lazyOnboardingGzipBytes": 14026,
"lazyOnboardingGzipBytes": 14029,
"lazyLocaleFiles": [
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/fr-yr6HN0On.js"
"houseplan-assets/de-CAtsunWz.js",
"houseplan-assets/fr-Bqax3ohv.js"
],
"lazyLocaleGzipBytes": 50132,
"lazyLocaleGzipBytes": 50151,
"files": [
{
"path": "houseplan-assets/backdrop-pick-y86gdzEv.js",
"sha256": "753369b21d0b9d1b2e5c780452c3b41ae29bbb00ef5787c859e2d11dac2aa6d8",
"path": "houseplan-assets/backdrop-pick-BOES8LdP.js",
"sha256": "aea5ea988e5aff3ffa8765511b0ed96acd7b4b3b5f3719242360716f3c6bd502",
"rawBytes": 20636,
"gzipBytes": 7070,
"gzipBytes": 7071,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D2QbRkX7.js"
"houseplan-assets/houseplan-card-CZDS_78e.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-5bH7Tqw5.js",
"sha256": "67422f19ed35403583f3b438f6f3efc83ede77164f79d612754660b19090ef58",
"path": "houseplan-assets/de-CAtsunWz.js",
"sha256": "883dd5ab7905636373de30c2793fc5418d867087644dc198f93576eb4b87cd3a",
"rawBytes": 83981,
"gzipBytes": 25337,
"gzipBytes": 25347,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-CXgHU1PF.js",
"sha256": "df251d831416ffa58a648577024f66f8e3f05a2890d338d0772870e7dff202fc",
"path": "houseplan-assets/editor-DCuNBi0k.js",
"sha256": "55ddef2226d3bc262b582216e556c667ad3dd8c2e793891afee33d1fb6687bdb",
"rawBytes": 3826,
"gzipBytes": 1580,
"gzipBytes": 1581,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-D2QbRkX7.js"
"houseplan-assets/houseplan-card-CZDS_78e.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-yr6HN0On.js",
"sha256": "8a9bf182a81ea57869accbba27e97029f554d624b0fc68d59688279b023b2b3a",
"path": "houseplan-assets/fr-Bqax3ohv.js",
"sha256": "5f75459b58f7bd380c21eb6998b417e743f65270425b2bc1dc46e9785d71ac56",
"rawBytes": 86212,
"gzipBytes": 24795,
"gzipBytes": 24804,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-D2QbRkX7.js",
"sha256": "98224a3ef6c2b7fa837fd0771cee732a2e4ed88127dd7b83283728d93bc477ed",
"path": "houseplan-assets/houseplan-card-CZDS_78e.js",
"sha256": "7bac8a128b73c811e62484ce99a13a121b7bb25c1dfc8fa48a49715f1c4a3690",
"rawBytes": 1032271,
"gzipBytes": 289578,
"gzipBytes": 289581,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-5bH7Tqw5.js",
"houseplan-assets/editor-CXgHU1PF.js",
"houseplan-assets/fr-yr6HN0On.js",
"houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js"
"houseplan-assets/de-CAtsunWz.js",
"houseplan-assets/editor-DCuNBi0k.js",
"houseplan-assets/fr-Bqax3ohv.js",
"houseplan-assets/houseplan-editor-runtime-DvhfS-p7.js",
"houseplan-assets/houseplan-onboarding-runtime-BeUYskCk.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-BbqROTi2.js",
"sha256": "0cece0a10a2d63fbd1dadfd1e0837049c79041c66662d1b63e71b4bd61669d72",
"path": "houseplan-assets/houseplan-editor-runtime-DvhfS-p7.js",
"sha256": "0d15c5f868b3684dbf6d81ebfbe925f874f08b3e8a68db12f160f3807d22ee20",
"rawBytes": 543272,
"gzipBytes": 140064,
"gzipBytes": 140067,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-card-D2QbRkX7.js"
"houseplan-assets/backdrop-pick-BOES8LdP.js",
"houseplan-assets/houseplan-card-CZDS_78e.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-CgH5Tq9K.js",
"sha256": "9a654161d364ab4a9e40036401f400cb7ba39412a9024b4b4f30a7d5cec32da9",
"path": "houseplan-assets/houseplan-onboarding-runtime-BeUYskCk.js",
"sha256": "c119a22e0435de0f3e7ed8c62f5813f7aeee31e1da8698f3506ab19e4a7c87a1",
"rawBytes": 28088,
"gzipBytes": 6956,
"gzipBytes": 6958,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-y86gdzEv.js",
"houseplan-assets/houseplan-card-D2QbRkX7.js"
"houseplan-assets/backdrop-pick-BOES8LdP.js",
"houseplan-assets/houseplan-card-CZDS_78e.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "eb53af1be3c6e20eb7a948f738a9efd1e11ae1322592b9f27955020cf70d983e",
"sha256": "d538bbccca6042eee23ee0df4506530c5bf121824167e6a30cac722ce6ba1b1c",
"rawBytes": 1183,
"gzipBytes": 796,
"gzipBytes": 797,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-D2QbRkX7.js"
"houseplan-assets/houseplan-card-CZDS_78e.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";import{b as e,l as o,t,d8 as s,A as a,d9 as i,da as l,db as n,E as r,c}from"./houseplan-card-D2QbRkX7.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="6235a41ecc5f366d871f78c16e149901360ea2a58761e839b0f53c6527b5e9ed";import{b as e,l as o,t,d8 as s,A as a,d9 as i,da as l,db as n,E as r,c}from"./houseplan-card-CZDS_78e.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
.hass=${this.hass}
.data=${this._formData}
.schema=${e}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";import{l as t,ar as s,A as e,t as o,c as a,bW as l,bX as i,bY as h,bZ as c,ao as n,b_ as r,c3 as p,b$ as _,c0 as d,c1 as u,c2 as g,cY as m,an as b,ap as $,cZ as v}from"./houseplan-card-D2QbRkX7.js";import{i as f,c as y,e as w,r as D,a as k,b as S,s as C,t as M}from"./backdrop-pick-y86gdzEv.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?a`<hp-help data-help-key=${l}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="6235a41ecc5f366d871f78c16e149901360ea2a58761e839b0f53c6527b5e9ed";import{l as t,ar as s,A as e,t as o,c as a,bW as l,bX as i,bY as h,bZ as c,ao as n,b_ as r,c3 as p,b$ as _,c0 as d,c1 as u,c2 as g,cY as m,an as b,ap as $,cZ as v}from"./houseplan-card-CZDS_78e.js";import{i as f,c as y,e as w,r as D,a as k,b as S,s as C,t as M}from"./backdrop-pick-BOES8LdP.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="6235a41ecc5f366d871f78c16e149901360ea2a58761e839b0f53c6527b5e9ed";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?a`<hp-help data-help-key=${l}
.text=${o(h,l)} .ariaLabel=${o(h,i)}></hp-help>`:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const o=l(e),a=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?i(e.settings.custom_fill):null,p="none"===o.fill?{...a||h,a:0}:a;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:o.showBorders,showNames:o.showNames,zeroWallStyle:r(e),displayTouched:!0,hideDecor:o.hideDecor,hideOpenings:o.hideOpenings,roomColor:o.color,roomOpacity:o.opacity,fillMode:"none"===o.fill?"custom":o.fill,customFill:p,glowEnabled:o.glow,bgColor:o.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:n({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:o.tempMin,tempMax:o.tempMax,showLqi:o.showLqi??this.host._config?.show_signal??!0,cardFontScale:o.cardFontScale,labelTemp:o.labelTemp,labelHum:o.labelHum,labelLqi:o.labelLqi,labelLight:o.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:c(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...f(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:d,tempMax:_,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:c(e,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const o=await y(e);if("reject"===o.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===o.kind)return void(this.host._backdropGuard=o.state);const a=await w(e,o.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:a})}_renderBackdropGuard(){return D(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),o=this.host._spaceDialog;return o&&o.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...o,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const o=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),a=this.host._spaceDialog,l=a?.saved?.find(s=>s.name===t);if(o&&a&&l&&l.url===e.url&&l.modified===e.modified&&!l.used_by.length&&l.url!==a.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return a`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return a`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return a`<div class="savedplans">
${s.map(s=>{return a`
<div class="savedplan ${s.url===t.planUrl?"cur":""}">
+1 -1
View File
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c79583791ed2babe6a8a4c84fc695fde2e0b419ba2eec3b7ea6f742350b79ea6";try{await import("./houseplan-assets/houseplan-card-D2QbRkX7.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale entry: the main chunk is unavailable",e)}
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="6235a41ecc5f366d871f78c16e149901360ea2a58761e839b0f53c6527b5e9ed";try{await import("./houseplan-assets/houseplan-card-CZDS_78e.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale entry: the main chunk is unavailable",e)}
+11 -11
View File
@@ -3,7 +3,7 @@
"fixture": "synthetic-only",
"chromium": "151.0.7922.34",
"oxipng": "oxipng 10.2.0",
"sourceFingerprint": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceFingerprint": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"captureScriptSha256": "135dd9a566653b05cae3010d7861fca6453daef0ecdcdf1ba10059e65f0d4de8",
"command": "npm run build && node demo/docs/capture.mjs",
"scenarios": {
@@ -15,7 +15,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceSha256": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"imageSha256": "f4ecb7fd1f107ccda6c8a1e90be1bce0f2690f93e5e42776ca783297f4143135"
},
"view-touch": {
@@ -26,7 +26,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceSha256": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"imageSha256": "946801f6475a40c0e31a70e4b67eaa34c6f70df5329a63915f445e6e4811ca6a"
},
"space-create": {
@@ -37,7 +37,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceSha256": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"imageSha256": "617b51b3648498787b5039980c9f3eceb75ba56ed63a1a20e616bc05bc304362"
},
"room-contour-close": {
@@ -48,7 +48,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceSha256": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"imageSha256": "9a79b7e517741e74701d1172ec3c66a340aaa9049a7f7a7b2fe86f4c3a2eccf0"
},
"plan-context-tray": {
@@ -59,7 +59,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceSha256": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"imageSha256": "8fb569f326627700e08156c1ca35a4042bcb529a955663b54228d04357c881d0"
},
"device-editor": {
@@ -70,7 +70,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceSha256": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"imageSha256": "720fc3aa2070d1fcf6907091941751c623f30cc6a001ff95e22de9be998136df"
},
"device-display-preview": {
@@ -81,7 +81,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceSha256": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"imageSha256": "b2294c6de0b18ef386b5a2d18422a866b84d095f133d31e56e307664e31e5bc0"
},
"background-editor": {
@@ -92,7 +92,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceSha256": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"imageSha256": "8dbc5864124c4bddbe076722a1503e666c40f432cfe7fff86e6d196c428365f3"
},
"room-card": {
@@ -103,7 +103,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceSha256": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"imageSha256": "d09709ae1479cfaa1902068cb2a6015dfee3b58f1bbd349bafaa2c0592812463"
},
"device-info": {
@@ -114,7 +114,7 @@
},
"theme": "dark",
"language": "en",
"sourceSha256": "7e950337dbe404c23c9e2b8bc593e04fe56c020dc2a8933353ed06e841ab5f6f",
"sourceSha256": "c3e3e7dba1910e09c702472e6ea09d7ef13b91e082c09d2f9474437c776fb26e",
"imageSha256": "c0b20a31c2987c8737e7b746c7d358e6c97231ea7e06d73050a2d3aebb216558"
}
},
+18
View File
@@ -4400,6 +4400,24 @@ const MUTANT_DEFINITIONS = [
replace: ' this._devicePositionHistory.clear();',
}],
},
{
id: 'support-timeout-claims-success',
guard: 'node demo/smoke_support_feedback.mjs',
because: 'a relay timeout, rate limit or unknown command must preserve the draft and expose '
+ 'manual recovery; claiming success loses the report while telling the user it was sent (#43)',
patches: [{
file: 'src/houseplan-editor-runtime.ts',
find: " } catch (error: unknown) {\n"
+ " if (!this._supportPatch(current.draftId, {\n"
+ " status: 'error',\n"
+ ' errorCode: supportErrorCode(error),',
replace: " } catch (error: unknown) {\n"
+ " if (!this._supportPatch(current.draftId, {\n"
+ " status: 'success',\n"
+ " reportId: 'HP-FALSE-SUCCESS',\n"
+ " errorCode: '',",
}],
},
];
const mutationCardSource = readFileSync(join(repoRoot, 'src/houseplan-card.ts'), 'utf8');
+15 -1
View File
@@ -373,7 +373,7 @@ test('sun-ray golden requires browser-painted light from a state-only sun entity
assert.ok(scenario);
const fixture = prepareGoldenFixture(scenario);
const space = fixture.config.spaces.find((item) => item.id === scenario.space);
assert.equal(GOLDEN_MATRIX_VERSION, 53);
assert.equal(GOLDEN_MATRIX_VERSION, 54);
assert.equal(space.settings.sun_rays, true);
assert.equal(scenario.northDeg, 90,
'the sign-sensitive golden must keep a non-zero north direction');
@@ -967,3 +967,17 @@ test('issue 86 help goldens render browser zoom 200% in both themes', () => {
assert.equal(scenario.capture, 'page');
}
});
test('issue 43 support dialog has the six reviewed responsive states', () => {
const support = GOLDEN_SCENARIOS.filter((scenario) => scenario.dialog === 'support');
assert.equal(support.length, 6);
assert.deepEqual(new Set(support.map((scenario) => scenario.supportState)), new Set([
'empty', 'preview', 'validation', 'success', 'relay-error',
]));
assert.deepEqual(new Set(support.map((scenario) => scenario.theme)), new Set(['light', 'dark']));
assert.equal(support.some((scenario) => scenario.viewport.width === 320), true);
assert.equal(support.some((scenario) => scenario.viewport.width === 390), true);
assert.equal(support.some((scenario) => scenario.viewport.width === 768), true);
assert.equal(support.filter((scenario) => scenario.viewport.width >= 900).length, 3);
for (const scenario of support) assert.equal(scenario.capture, 'page', scenario.id);
});