Compare commits

...

153 Commits

Author SHA1 Message Date
Paulus Schoutsen
1feb9f6a27 Bump version to 20181024.0 2018-10-24 22:14:06 +02:00
Paulus Schoutsen
337a760e73 Update translations 2018-10-24 22:13:49 +02:00
Thomas Lovén
54cd412107 Fix for some dev pages crashing on iOS. (#1850)
This should probably be reverted when the fixes in
https://bugs.webkit.org/show_bug.cgi?id=174629 has been rolled out.
2018-10-24 22:04:27 +02:00
Ian Richardson
cf2171ece1 Convert hui-vertical-stack-card to TypeScript/LitElement (#1846)
Failed to rebase previous branch and am taking my working changes and applying to a new branch based off of current master.

Updated tslint.json to allow for prefixed `_` to variable names
2018-10-24 12:11:09 +02:00
Paulus Schoutsen
47fb8a5513 Fix mixin names (#1849) 2018-10-24 12:10:58 +02:00
Ian Richardson
06bf134bd4 Remove extending of HassLocalizeMixin as it is not needed (#1847) 2018-10-24 11:42:09 +02:00
Timmo
cf8899fcbe ↕️ fix sorting of addons (#1845) 2018-10-24 09:58:44 +02:00
Charles Garwood
c05b77961e Reduces device registry card height to only show 4 entities before scrolling (#1844) 2018-10-23 17:40:31 +02:00
Paulus Schoutsen
19c365cd12 Update version to 20181023.0 2018-10-23 14:01:51 +02:00
Paulus Schoutsen
29f032087e Update translations 2018-10-23 14:01:22 +02:00
Paulus Schoutsen
d0cb7b9724 TS history data (#1839)
* Convert history data to TS

* Lint

* Extract cached history

* Move around
2018-10-23 13:54:52 +02:00
Thomas Lovén
ad162677a6 Introduce typescript to hui-conditional-card (#1831) 2018-10-23 12:11:06 +02:00
Thomas Lovén
fbbbe7d17d Add HomeAssistant object hass to LovelaceCard interface (#1843) 2018-10-23 10:53:42 +02:00
Ian Richardson
ef0d11c042 connection is being populated for HomeAssistant type, not conn (#1841) 2018-10-23 09:33:04 +02:00
Ian Richardson
fc2608980f Generate icons from `.ts. files (#1842) 2018-10-23 09:32:27 +02:00
Tom Raithel
cc97e82a78 Improve size of device cards and add max-width for entities (#1838)
fixes #1751
2018-10-23 00:12:39 +02:00
Paulus Schoutsen
54e3191de6 Reinstate first call true 2018-10-22 21:40:35 +02:00
Paulus Schoutsen
4f8c8762c7 Fix second visit to history panel (#1835) 2018-10-22 21:37:21 +02:00
Zack Arnett
c190f1986e Merge pull request #1834 from home-assistant/fix-chart-tooltip
Fix chart tooltip
2018-10-22 15:13:25 -04:00
Paulus Schoutsen
b418048bc9 Fix chart tooltip 2018-10-22 21:07:31 +02:00
Paulus Schoutsen
0fdd1c74f2 Always define localize func (#1830) 2018-10-22 20:31:43 +02:00
Thomas Lovén
3b1b2b95e7 Add option to pick number of columns for glance card (#1832) 2018-10-22 20:10:48 +02:00
Paulus Schoutsen
3bb5484b7f Bump version to 20181021.0 2018-10-21 20:32:05 +02:00
Paulus Schoutsen
d93c09b27b Fix reference to this.language (#1825) 2018-10-21 20:31:41 +02:00
Paulus Schoutsen
e7ec18d270 Fix lint 2018-10-21 20:31:24 +02:00
Paulus Schoutsen
3ebe21e135 Update translations 2018-10-21 20:16:09 +02:00
Ian Richardson
aca1ecf1ee Convert hui-markdown-card to TypeScript/LitElement (#1808)
* Convert hui-markdown-card to TypeScript/LitElement

* Addressed review comments

* Addressed review comments

* Addressed review comments
2018-10-21 20:09:11 +02:00
Charles Garwood
e8ef2fdc2c this.language -> this.hass.language (#1816) 2018-10-21 15:12:28 +02:00
Paulus Schoutsen
b129d5fb08 Refresh cloud status if paying sub info comes in (#1822) 2018-10-21 12:28:16 +02:00
Zack Arnett
11f4564465 Merge pull request #1807 from home-assistant/safer-icon-brightness
Safer brightness calculation for icons
2018-10-19 20:58:46 -04:00
Thomas Lovén
c9d140281b fix typo in variable name 2018-10-19 16:35:52 +02:00
PhracturedBlue
fa637a37d5 Fix mailbox issues with this.fire() and this.language undefined (#1809)
* Fix bug with this.fire and this.language

* Proper language variable
2018-10-19 16:15:31 +02:00
Thomas Lovén
1589c3fc51 Better error message 2018-10-19 15:29:05 +02:00
Thomas Lovén
bdc2b31202 Complain and ignore instead of fixing 2018-10-19 12:07:33 +02:00
Thomas Lovén
0970e1e33c Fix overflow of image elements. (#1811)
* Fix overflow of image elements.

* Positioning safeguards
2018-10-19 10:41:08 +02:00
Timmo
028003dffc Set attributes in input form controls (#1805)
* 🔨 add autocapitalize, autocomplete, autocorrect and spellcheck attributes

* 🔨 switch autocapitalize to none

* 🔨 add attributes to dev-state

* 🔨 add attributes to entity-picker
2018-10-19 09:13:45 +02:00
Thomas Lovén
1eb4ac7f34 Safer brightness calculation for icons 2018-10-19 00:01:23 +02:00
Zack Arnett
d97e356376 Merge pull request #1794 from zsarnett/glance-unavailable
Glance Card update to show when entity is unavailable
2018-10-18 11:21:08 -04:00
Zack Arnett
d36352af16 Removing Repeat 2018-10-18 10:26:42 -04:00
Zack Arnett
05ae92d5f8 Merge pull request #1786 from zsarnett/glance-column-change
Changing Glance Column Width default to fill card
2018-10-18 09:52:16 -04:00
Paulus Schoutsen
dce612f944 Trim whitespace 2018-10-18 15:40:37 +02:00
Ian Richardson
3a196203c3 Convert hui-iframe-card to LitElement/TypeScript (#1801)
* Convert hui-iframe-card to LitElement/TypeScript

* style cleanup

* Address review comments

* Addressed review comments
2018-10-18 15:37:01 +02:00
Zack Arnett
33578a6289 Updating from reviews 2018-10-18 09:28:49 -04:00
Zack Arnett
4c3db2119b Update to show when entity is unavailable 2018-10-18 09:14:32 -04:00
Zack Arnett
4a7ff3cd94 Removing Column width variable in interface 2018-10-18 09:06:29 -04:00
Paulus Schoutsen
5578580d78 Verison bump to 20181018.0 2018-10-18 13:39:45 +02:00
Paulus Schoutsen
dc1d8366a5 Fix automation editor (#1804) 2018-10-18 13:39:18 +02:00
Paulus Schoutsen
252f0692c8 Add hass on badge (#1802)
* Add hass on badge

* Add more hass everywhere
2018-10-18 13:21:06 +02:00
Thomas Lovén
9d13925280 Show currently selected language in profile settings. Resolves #1797 (#1800) 2018-10-18 09:55:28 +02:00
Thomas Lovén
5462a71f52 Use this.hass.language since this.language is removed from localize mixin. (#1799) 2018-10-18 09:54:01 +02:00
Josh McCarty
42953a0b62 Use title case for all configuration pages (#1793)
Localize translations will need to be updated separately.
2018-10-18 09:25:35 +02:00
Thomas Lovén
f146a1d80f Lovelace: Allow press-and-hold on picture-elements elements. (#1745)
* Allow press-and-hold on picture-elements elements.
2018-10-17 22:16:17 +02:00
Zack Arnett
a113c71de7 Merge branch 'master' into glance-column-change 2018-10-17 15:06:29 -04:00
Zack Arnett
1f642f436a Adding Theme option to Glance and Button Cards (#1783)
* Adding Theme option to Glance and Button Cards

* Updateing Theme default to `default`

* Prettier Update
2018-10-17 20:20:05 +02:00
Zack Arnett
62d27a17d5 Takes out column width variable 2018-10-17 13:06:57 -04:00
Zack Arnett
35941a58a5 Prettier Fixes 2018-10-17 11:11:29 -04:00
Paulus Schoutsen
2ace2165e0 version bump to 20181017.0 2018-10-17 14:06:59 +02:00
Paulus Schoutsen
1cfcacfa9a Update translations 2018-10-17 14:06:20 +02:00
Paulus Schoutsen
e020fd1154 👋 decorators (#1790) 2018-10-17 13:58:24 +02:00
Paulus Schoutsen
1dcc645fec Guard cloud info being null (#1788) 2018-10-17 13:48:31 +02:00
Thomas Lovén
87fba75860 Fix margins in vertical-stack (#1789) 2018-10-17 13:48:04 +02:00
Paulus Schoutsen
294360d35a Fix babel config 2018-10-17 09:20:41 +02:00
Paulus Schoutsen
a7684d7206 Add some decorators (#1784)
* Add some decorators

* Disable sort keys

* Add babel plugins

* Update typescript to 7.1
2018-10-16 23:30:13 +02:00
Paulus Schoutsen
af81ede100 Fix showing sub info (#1785) 2018-10-16 23:29:40 +02:00
Zack Arnett
698beedaa2 Changing Clance Column width default to fill card 2018-10-16 16:20:28 -04:00
Paulus Schoutsen
a6b4cce7f3 Upgrade MDI icons (#1781) 2018-10-16 20:02:09 +02:00
ehendrix23
ba66ff840f Added domain icon for homekit (#1782)
Added domain icon home-automation for domain homekit. With PR home-assistant/pull/17180 the homekit component will create entries within logbook. This PR is to set the icon displayed then for those logbook entries to be the home-automation icon.
2018-10-16 19:06:19 +02:00
Zack Arnett
c296f33ba1 Update Button Card to TS + Lit (#1778)
* Updating from Reviews - Reset commits and force pushing

* Removing Redundant check on config

* Checking Entity before setting config
2018-10-16 19:04:29 +02:00
Paulus Schoutsen
e7a49192bd Type check as part of lint (#1780)
* Type check as part of lint

* Lint

* Validate service exist for call-service action

* Fix for of
2018-10-16 17:21:05 +02:00
Thomas Lovén
5774d913af Lovelace: Add a label entity row (#1779)
* Add a label entity row

* Style fixes

* Allow blank label text

* Rename to section
2018-10-16 16:50:40 +02:00
Charles Garwood
b068db3f7a Hide Z-Wave "Remove/Replace Failed Node" Buttons unless nodes are failed (#1777)
* Hide failed node buttons if node isn't failed

* Cleanup
2018-10-16 09:05:15 +02:00
Paulus Schoutsen
8e49241e7c Add types to hass object (#1776) 2018-10-16 09:04:10 +02:00
Tom Raithel
b8cee5cc9c Fix Icon spacing in Logbook list (#1774) 2018-10-15 21:02:32 +02:00
Zack Arnett
794808d3a7 Button Card - Lovelace Addition (#1766)
* Initial Commit - Button Card

* Fixing Coloring Review

* Resolving Reviews

* Updating last Reviews
2018-10-15 20:07:13 +02:00
Zack Arnett
48f6d1dfec Adding Alarm Panel to Lovelace (#1758)
* Adding Alarm Panel

* Updating error in Lint

* Review Changes

* Using label-badge for upper right icon

* Resolving Reviews

* Prettier Fixes

* Updating style to fix overlapping state badge

* Adding Alarm Card back to create element

* Resolving reviews and reposition of Icon

* Updating to Localize Labels
2018-10-15 19:14:43 +02:00
Paulus Schoutsen
97e1aae9c0 Introduce TypeScript (#1773) 2018-10-15 19:07:08 +02:00
Paulus Schoutsen
e2511c5ed3 Remove default export fire event (#1772)
* Remove default export fire event

* Update provide_hass.js
2018-10-15 06:17:33 +02:00
Paulus Schoutsen
74bdfc8c2d Use style.setProperty instead of updateStyles 2018-10-14 22:53:33 +02:00
Paulus Schoutsen
fbccf23d36 Clean up localize mixin (#1771) 2018-10-14 22:40:43 +02:00
Paulus Schoutsen
906aaa15a3 20181014.0 2018-10-14 19:05:46 +02:00
Paulus Schoutsen
0ae1f9c754 Update Translations 2018-10-14 19:05:45 +02:00
Adam Mills
f1bd89fd02 Fix checking for syntax if for doesn't exist (#1769) 2018-10-14 19:04:51 +02:00
Paulus Schoutsen
3949b47e51 Introduce object rest spread (#1763) 2018-10-14 19:03:25 +02:00
Bram Kragten
2f6595bca7 add min-width to childeren of horizontal stack (#1761)
See https://css-tricks.com/flexbox-truncated-text/
2018-10-13 16:02:47 +02:00
Paulus Schoutsen
3bcd0ddc46 Migrate Babel 6 -> 7 (#1762)
* Migrate Babel 6 -> 7

* Update babel-eslint
2018-10-13 11:25:03 +02:00
Paulus Schoutsen
ca93c2cfcd Convert glance card to lit (#1760)
* Convert glance card to lit

* Guard for hass before config

* Lint

* better click listening

* Move config check

* Format HTML
2018-10-12 22:18:38 -07:00
Paulus Schoutsen
a633e3c553 version bump to 20181012.0 2018-10-12 14:49:33 +02:00
Paulus Schoutsen
bef2731207 Update translations 2018-10-12 14:49:15 +02:00
Paulus Schoutsen
ee53ee4077 Missing localize (#1757) 2018-10-12 12:50:58 +02:00
Paulus Schoutsen
34bfc12647 Prettier 💎 (#1737)
* Add prettier

* Apply Prettier
2018-10-11 12:22:11 +02:00
Nikolay Vasilchuk
3b425c3e14 Logbook: filter by entity and period (#1728)
* Filter logbook by entity_id

* Filter logbook by period

* Filter logbook styles

* CI Fix

* Review

* Review

* CI Fix
2018-10-11 11:46:16 +02:00
Zack Arnett
69eb007ea2 Adding Gauge Card to Lovelace (#1742)
* Commiting Only needed Files. Adds Gallery Entry

* Adding Attribute current_temperature to gallery entry config

* Fixing code from review and updating gallery

* Updating Gallery to show errors

* Resolving Reviews and updating gallery

* Deleting unused line

* Minor changes

* Address my own comments.
2018-10-11 10:30:56 +02:00
Jerad Meisner
90c3350d40 Fix error when only one state history entry. (#1750) 2018-10-09 11:12:04 +02:00
John Arild Berentsen
a7ddbd72b3 Fix non-working zwave log andriod PWA (#1714)
* Fix non-working andriod PWA

* Forgot clearing dialog setInterval

* Correctly identify pwa or browser interval clearing

* Move isPwa to common

* Stab at making imorted dialog

* Redone refresh

* Remove unused property
2018-10-09 11:10:32 +02:00
Paulus Schoutsen
5a2ee98ae2 Version bump to 20181007.0 2018-10-07 23:15:44 +02:00
Karl Kihlström
ea0b5d5e26 Add sensor-graph-card (#1744)
* Added sensor-graph-card

* Removed Object as type

* Removed unused attributes

* Fixed card config

* Changed svg rendering to lit html svg

* Fixed config conversion

* Changed to _config, _entity, _line as private

* Removed lit-element package

* Renamed to hui-sensor-card

* lit-html 0.6.2 changes

* Added logic for graph config option
2018-10-07 23:13:10 +02:00
Paulus Schoutsen
af2cb1be1a Update Lit to 0.6.2 (#1748) 2018-10-07 21:32:50 +02:00
Jerad Meisner
c30e7ac683 Add time created to persistent notifications. (#1733)
* Add time created to persistent notifications.

* Add tooltip to show actual date.

* Fix style rules.

* Fix duplicate ids.
2018-10-07 18:59:54 +02:00
Paulus Schoutsen
7fb5ac11fd Update translations 2018-10-07 18:52:30 +02:00
Paulus Schoutsen
b2dc0ac819 Proper fix for mjs to hassio too 2018-10-07 18:52:01 +02:00
Paulus Schoutsen
dbdf873ba4 transpile mjs (#1746) 2018-10-07 14:11:33 +02:00
Paulus Schoutsen
1b70b6e88c Introduce Lit Element (#1738) 2018-10-07 11:07:02 +02:00
Paulus Schoutsen
c90e13d35e Inline domain icon (#1739) 2018-10-05 21:29:50 +02:00
Paul Davis
442375f76e fix dockerfile for new setups (#1740) 2018-10-05 21:23:31 +02:00
Paulus Schoutsen
81d493e1d6 Version bump to 20181005.0 2018-10-05 17:46:49 +02:00
Paulus Schoutsen
151f16af47 Update translations 2018-10-05 17:46:34 +02:00
Adam Mills
606a220603 [WIP] Handle dict syntax in state trigger "for" (#1725)
* Handle dict syntax in state trigger "for"

* padStart polyfill
2018-10-05 11:33:27 +02:00
Thomas Lovén
362e758c40 Lovelace: Allow glance card to assume theme colors (#1732)
* Allow glance card to assume theme colors

* Better configuration options

* Added example to gallery

* Fixing problems from review
2018-10-05 10:26:31 +02:00
Paulus Schoutsen
2eb3a55f59 Remove last used from long lived access token list. (#1727) 2018-10-05 10:23:29 +02:00
Paulus Schoutsen
6720c03cbc Fix language reference (#1735) 2018-10-04 13:24:07 +02:00
Jerad Meisner
a76386b53b Fix console errors in LL when entities are unavailable. (#1734) 2018-10-04 09:44:01 +02:00
Thomas Lovén
0243632357 Remove margin from conditional if not shown (#1730) 2018-10-04 09:36:14 +02:00
Paulus Schoutsen
bb24b55a67 Update translations 2018-10-03 15:28:12 +02:00
Paulus Schoutsen
f47fd8eec4 Bump version to 20181002.0 2018-10-02 14:17:58 +02:00
Paulus Schoutsen
f1f9f13d82 Update translations 2018-10-02 14:17:44 +02:00
Paulus Schoutsen
d2dd82c0ec Use new LL command (#1702) 2018-10-02 14:16:52 +02:00
Paulus Schoutsen
e1738b625d Fix link color for Hass.io update panel (#1721) 2018-10-02 14:16:35 +02:00
William Scanlon
7aa37183b6 Convert climate water heaters to new water_heaters component (#1661)
* Water heater support

* Attempt to fix lint errors.

* Fixed another lint issue
2018-10-02 14:16:19 +02:00
Jason Hu
c91b28a850 L10N config-entries (#1718)
* L10N config-entries

* Lint

* Address review comment

* Add back parentheses
2018-10-02 13:27:18 +02:00
Adam Mills
70225c1a18 Expose state trigger For configuration in editor (#1723) 2018-10-02 13:26:56 +02:00
Jason Hu
3d9d7d899d Fix zero degree in weather card (#1720)
* Fix zero degree display in weather card

* Fix zero degree display in weather more-info dialog
2018-10-01 13:30:48 +02:00
Otto Winter
f0619c7d13 Add pressure sensor device class (#1713) 2018-10-01 12:32:03 +02:00
Jason Hu
305fa84d38 Apply user language preference on datetime formatting (#1719) 2018-10-01 12:08:21 +02:00
Jason Hu
edf0e2bedb Add l10n suppor for profile panel (#1717)
* L10N support for profile panel and mfa module

* L10N support for mfa setup flow

* Lint

* Lint

* Lint
2018-10-01 12:02:41 +02:00
Anders Melchiorsen
8be5561d19 Remove turn_off from brightness slider (#1715) 2018-10-01 10:56:08 +02:00
Paulus Schoutsen
f11ca53282 Version bump to 20180927.0 2018-09-27 23:03:17 +02:00
Paulus Schoutsen
2c25d6cc0a Update translations 2018-09-27 23:03:02 +02:00
Paulus Schoutsen
db6ab4d8ec Update Z-Wave icon (#1711) 2018-09-27 23:02:22 +02:00
Jerad Meisner
3961eff372 Extend paper-slider to fix rounding issue. (#1709) 2018-09-27 10:06:56 +02:00
Charles Garwood
458a7827f9 Fix for content appearing behind header in hassio and config panels (#1708)
* Call iron-resize on route change

* Add EventsMixin to hassio-main
2018-09-26 20:37:03 +02:00
Paulus Schoutsen
68d1c77a79 Bump version to 20180926.0 2018-09-26 11:10:46 +02:00
Paulus Schoutsen
aa97e30d51 Add card for entities without devices (#1706)
* Add card for entities without devices

* Better empty check
2018-09-26 11:09:33 +02:00
Paulus Schoutsen
9027d7d391 Update translations 2018-09-26 10:57:56 +02:00
Paulus Schoutsen
974fd5de0f Allow description when creating entry (#1704)
* Allow description when creating entry

* Lint
2018-09-25 16:32:45 +02:00
Paulus Schoutsen
f9d28fbf83 Add alert icon" (#1703) 2018-09-25 14:42:23 +02:00
Paulus Schoutsen
b944089087 Version bump 20180924.0 2018-09-24 11:46:26 +02:00
Paulus Schoutsen
7b6cf28459 Update translations 2018-09-24 11:46:10 +02:00
Paulus Schoutsen
be91688efb Add link to release notes (#1694) 2018-09-24 11:05:23 +02:00
Paulus Schoutsen
a5d47231aa Fix text color for system panel (#1695) 2018-09-24 11:05:16 +02:00
Paulus Schoutsen
01e833a399 Fix ha-paper-slider (#1700) 2018-09-24 11:05:03 +02:00
Charles Garwood
c363ba8056 Fix more-info graph when expanded (#1696) 2018-09-24 10:01:40 +02:00
schumpeter2
7cec39ba6c Fix more-info dialog call for groups of entities having a common domain (#1698) 2018-09-24 09:58:25 +02:00
PhracturedBlue
3f15cbd2bd Add support for multiple separate mailboxes (#1660) 2018-09-21 11:56:30 +02:00
Paulus Schoutsen
3235d33463 Add firmware 2018-09-21 10:41:25 +02:00
Paulus Schoutsen
140597c7f8 Minor CSS Fixes 2018-09-21 10:00:03 +02:00
Paulus Schoutsen
e1407a7d73 Use human readable description if possible (#1688)
* Use human readable description if possible

* lint
2018-09-21 09:20:07 +02:00
Paulus Schoutsen
03525c010f Allow toggling cloud integrations (#1690) 2018-09-21 09:02:24 +02:00
Paulus Schoutsen
8dc202af92 Version bump to 20180920.0 2018-09-20 10:53:41 +02:00
Paulus Schoutsen
369977f8f3 Update translations 2018-09-20 10:52:56 +02:00
randellhodges
7f8c092dfc Normalize more-info bottom padding (#1682) 2018-09-20 10:20:12 +02:00
randellhodges
d517cad6e6 fixed weather-lightning icon (#1684) 2018-09-20 10:19:04 +02:00
Paulus Schoutsen
62a68890d3 Show sub info (#1685)
* Show sub info

* Fix observer
2018-09-20 10:18:39 +02:00
Paulus Schoutsen
3d8a8cc77b Fix minifier (#1683) 2018-09-20 00:08:25 +02:00
530 changed files with 22937 additions and 12005 deletions

View File

@@ -1,5 +1,5 @@
{
"extends": "airbnb-base",
"extends": ["airbnb-base", "prettier"],
"parserOptions": {
"ecmaFeatures": {
"jsx": true,
@@ -67,13 +67,11 @@
"react/no-find-dom-node": 2,
"react/no-is-mounted": 2,
"react/jsx-no-comment-textnodes": 2,
"react/jsx-curly-spacing": 2,
"react/jsx-no-undef": 2,
"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"no-restricted-syntax": [0, "ForOfStatement"]
"no-restricted-syntax": [0, "ForOfStatement"],
"prettier/prettier": "error"
},
"plugins": [
"react"
]
"plugins": ["react", "prettier"]
}

View File

@@ -1,4 +1,4 @@
FROM node:8.9-alpine
FROM node:8.11.1-alpine
# install yarn
ENV PATH /root/.yarn/bin:$PATH

35
config/babel.js Normal file
View File

@@ -0,0 +1,35 @@
module.exports.babelLoaderConfig = ({ latestBuild }) => {
if (latestBuild === undefined) {
throw Error("latestBuild not defined for babel loader config");
}
return {
test: /\.m?js$|\.ts$/,
use: {
loader: "babel-loader",
options: {
presets: [
!latestBuild && [
require("@babel/preset-env").default,
{ modules: false },
],
require("@babel/preset-typescript").default,
].filter(Boolean),
plugins: [
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
[
"@babel/plugin-proposal-object-rest-spread",
{ loose: true, useBuiltIns: true },
],
// Only support the syntax, Webpack will handle it.
"@babel/syntax-dynamic-import",
[
"@babel/transform-react-jsx",
{
pragma: "h",
},
],
],
},
},
};
};

View File

@@ -1,12 +1,12 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import JsYaml from 'js-yaml';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import JsYaml from "js-yaml";
import HomeAssistant from '../data/hass.js';
import demoConfig from '../data/demo_config.js';
import demoResources from '../data/demo_resources.js';
import demoStates from '../data/demo_states.js';
import createCardElement from '../../../src/panels/lovelace/common/create-card-element.js';
import HomeAssistant from "../data/hass.js";
import demoConfig from "../data/demo_config.js";
import demoResources from "../data/demo_resources.js";
import demoStates from "../data/demo_states.js";
import createCardElement from "../../../src/panels/lovelace/common/create-card-element.js";
class DemoCard extends PolymerElement {
static get template() {
@@ -50,11 +50,11 @@ class DemoCard extends PolymerElement {
return {
hass: {
type: Object,
observer: '_hassChanged',
observer: "_hassChanged",
},
config: {
type: Object,
observer: '_configChanged'
observer: "_configChanged",
},
showConfig: Boolean,
};
@@ -74,7 +74,7 @@ class DemoCard extends PolymerElement {
const hass = new HomeAssistant(demoStates);
hass.config = demoConfig;
hass.resources = demoResources;
hass.language = 'en';
hass.language = "en";
hass.states = demoStates;
el.hass = hass;
}
@@ -92,4 +92,4 @@ class DemoCard extends PolymerElement {
}
}
customElements.define('demo-card', DemoCard);
customElements.define("demo-card", DemoCard);

View File

@@ -1,9 +1,9 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/paper-toggle-button/paper-toggle-button.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import "@polymer/paper-toggle-button/paper-toggle-button.js";
import './demo-card.js';
import "./demo-card.js";
class DemoCards extends PolymerElement {
static get template() {
@@ -50,9 +50,9 @@ class DemoCards extends PolymerElement {
_showConfig: {
type: Boolean,
value: false,
}
},
};
}
}
customElements.define('demo-cards', DemoCards);
customElements.define("demo-cards", DemoCards);

View File

@@ -1,10 +1,9 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../../src/state-summary/state-card-content.js';
import '../../../src/dialogs/more-info/controls/more-info-content.js';
import '../../../src/components/ha-card.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import "../../../src/state-summary/state-card-content.js";
import "../../../src/dialogs/more-info/controls/more-info-content.js";
import "../../../src/components/ha-card.js";
class DemoMoreInfo extends PolymerElement {
static get template() {
@@ -68,8 +67,8 @@ class DemoMoreInfo extends PolymerElement {
showConfig: Boolean,
_stateObj: {
type: Object,
computed: '_getState(entityId, hass.states)'
}
computed: "_getState(entityId, hass.states)",
},
};
}
@@ -82,7 +81,7 @@ class DemoMoreInfo extends PolymerElement {
// (it sucks, we will remove in the future)
const tmp = {};
Object.keys(stateObj).forEach((key) => {
if (key[0] !== '_') {
if (key[0] !== "_") {
tmp[key] = stateObj[key];
}
});
@@ -90,4 +89,4 @@ class DemoMoreInfo extends PolymerElement {
}
}
customElements.define('demo-more-info', DemoMoreInfo);
customElements.define("demo-more-info", DemoMoreInfo);

View File

@@ -1,9 +1,9 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/paper-toggle-button/paper-toggle-button.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import "@polymer/paper-toggle-button/paper-toggle-button.js";
import './demo-more-info.js';
import "./demo-more-info.js";
class DemoMoreInfos extends PolymerElement {
static get template() {
@@ -50,9 +50,9 @@ class DemoMoreInfos extends PolymerElement {
_showConfig: {
type: Boolean,
value: false,
}
},
};
}
}
customElements.define('demo-more-infos', DemoMoreInfos);
customElements.define("demo-more-infos", DemoMoreInfos);

View File

@@ -4,172 +4,106 @@ export default {
latitude: 51.5287352,
longitude: -0.381773,
unit_system: {
length: 'km',
mass: 'kg',
temperature: '°C',
volume: 'L'
}
length: "km",
mass: "kg",
temperature: "°C",
volume: "L",
},
},
services: {
configurator: [
'configure'
],
tts: [
'demo_say',
'clear_cache'
],
configurator: ["configure"],
tts: ["demo_say", "clear_cache"],
cover: [
'open_cover',
'close_cover',
'open_cover_tilt',
'close_cover_tilt',
'set_cover_tilt_position',
'set_cover_position',
'stop_cover_tilt',
'stop_cover'
],
group: [
'set',
'reload',
'remove',
'set_visibility'
"open_cover",
"close_cover",
"open_cover_tilt",
"close_cover_tilt",
"set_cover_tilt_position",
"set_cover_position",
"stop_cover_tilt",
"stop_cover",
],
group: ["set", "reload", "remove", "set_visibility"],
alarm_control_panel: [
'alarm_arm_night',
'alarm_disarm',
'alarm_trigger',
'alarm_arm_home',
'alarm_arm_away',
'alarm_arm_custom_bypass'
],
conversation: [
'process'
],
notify: [
'demo_test_target_name',
'notify'
],
lock: [
'open',
'lock',
'unlock'
"alarm_arm_night",
"alarm_disarm",
"alarm_trigger",
"alarm_arm_home",
"alarm_arm_away",
"alarm_arm_custom_bypass",
],
conversation: ["process"],
notify: ["demo_test_target_name", "notify"],
lock: ["open", "lock", "unlock"],
input_select: [
'select_previous',
'set_options',
'select_next',
'select_option'
],
recorder: [
'purge'
],
persistent_notification: [
'create',
'dismiss'
],
timer: [
'pause',
'cancel',
'finish',
'start'
],
input_boolean: [
'turn_off',
'toggle',
'turn_on'
"select_previous",
"set_options",
"select_next",
"select_option",
],
recorder: ["purge"],
persistent_notification: ["create", "dismiss"],
timer: ["pause", "cancel", "finish", "start"],
input_boolean: ["turn_off", "toggle", "turn_on"],
fan: [
'set_speed',
'turn_on',
'turn_off',
'set_direction',
'oscillate',
'toggle'
"set_speed",
"turn_on",
"turn_off",
"set_direction",
"oscillate",
"toggle",
],
climate: [
'set_humidity',
'set_operation_mode',
'set_aux_heat',
'turn_on',
'set_hold_mode',
'set_away_mode',
'turn_off',
'set_fan_mode',
'set_temperature',
'set_swing_mode'
],
switch: [
'turn_off',
'toggle',
'turn_on'
],
script: [
'turn_off',
'demo',
'reload',
'toggle',
'turn_on'
],
scene: [
'turn_on'
],
system_log: [
'clear',
'write'
],
camera: [
'disable_motion_detection',
'enable_motion_detection',
'snapshot'
],
image_processing: [
'scan'
"set_humidity",
"set_operation_mode",
"set_aux_heat",
"turn_on",
"set_hold_mode",
"set_away_mode",
"turn_off",
"set_fan_mode",
"set_temperature",
"set_swing_mode",
],
switch: ["turn_off", "toggle", "turn_on"],
script: ["turn_off", "demo", "reload", "toggle", "turn_on"],
scene: ["turn_on"],
system_log: ["clear", "write"],
camera: ["disable_motion_detection", "enable_motion_detection", "snapshot"],
image_processing: ["scan"],
media_player: [
'media_previous_track',
'clear_playlist',
'shuffle_set',
'media_seek',
'turn_on',
'media_play_pause',
'media_next_track',
'media_pause',
'volume_down',
'volume_set',
'media_stop',
'toggle',
'media_play',
'play_media',
'volume_mute',
'turn_off',
'select_sound_mode',
'select_source',
'volume_up'
],
input_number: [
'set_value',
'increment',
'decrement'
],
device_tracker: [
'see'
"media_previous_track",
"clear_playlist",
"shuffle_set",
"media_seek",
"turn_on",
"media_play_pause",
"media_next_track",
"media_pause",
"volume_down",
"volume_set",
"media_stop",
"toggle",
"media_play",
"play_media",
"volume_mute",
"turn_off",
"select_sound_mode",
"select_source",
"volume_up",
],
input_number: ["set_value", "increment", "decrement"],
device_tracker: ["see"],
homeassistant: [
'stop',
'check_config',
'reload_core_config',
'turn_on',
'turn_off',
'restart',
'toggle'
"stop",
"check_config",
"reload_core_config",
"turn_on",
"turn_off",
"restart",
"toggle",
],
light: [
'turn_off',
'toggle',
'turn_on'
],
input_text: [
'set_value'
]
}
light: ["turn_off", "toggle", "turn_on"],
input_text: ["set_value"],
},
};

View File

@@ -1,253 +1,264 @@
export default {
en: {
'state.default.off': 'Off',
'state.default.on': 'On',
'state.default.unknown': 'Unknown',
'state.default.unavailable': 'Unavailable',
'state.alarm_control_panel.armed': 'Armed',
'state.alarm_control_panel.disarmed': 'Disarmed',
'state.alarm_control_panel.armed_home': 'Armed home',
'state.alarm_control_panel.armed_away': 'Armed away',
'state.alarm_control_panel.armed_night': 'Armed night',
'state.alarm_control_panel.armed_custom_bypass': 'Armed custom bypass',
'state.alarm_control_panel.pending': 'Pending',
'state.alarm_control_panel.arming': 'Arming',
'state.alarm_control_panel.disarming': 'Disarming',
'state.alarm_control_panel.triggered': 'Triggered',
'state.automation.off': 'Off',
'state.automation.on': 'On',
'state.binary_sensor.default.off': 'Off',
'state.binary_sensor.default.on': 'On',
'state.binary_sensor.battery.off': 'Normal',
'state.binary_sensor.battery.on': 'Low',
'state.binary_sensor.cold.off': 'Normal',
'state.binary_sensor.cold.on': 'Cold',
'state.binary_sensor.connectivity.off': 'Disconnected',
'state.binary_sensor.connectivity.on': 'Connected',
'state.binary_sensor.door.off': 'Closed',
'state.binary_sensor.door.on': 'Open',
'state.binary_sensor.garage_door.off': 'Closed',
'state.binary_sensor.garage_door.on': 'Open',
'state.binary_sensor.gas.off': 'Clear',
'state.binary_sensor.gas.on': 'Detected',
'state.binary_sensor.heat.off': 'Normal',
'state.binary_sensor.heat.on': 'Hot',
'state.binary_sensor.lock.off': 'Locked',
'state.binary_sensor.lock.on': 'Unlocked',
'state.binary_sensor.moisture.off': 'Dry',
'state.binary_sensor.moisture.on': 'Wet',
'state.binary_sensor.motion.off': 'Clear',
'state.binary_sensor.motion.on': 'Detected',
'state.binary_sensor.occupancy.off': 'Clear',
'state.binary_sensor.occupancy.on': 'Detected',
'state.binary_sensor.opening.off': 'Closed',
'state.binary_sensor.opening.on': 'Open',
'state.binary_sensor.presence.off': 'Away',
'state.binary_sensor.presence.on': 'Home',
'state.binary_sensor.problem.off': 'OK',
'state.binary_sensor.problem.on': 'Problem',
'state.binary_sensor.safety.off': 'Safe',
'state.binary_sensor.safety.on': 'Unsafe',
'state.binary_sensor.smoke.off': 'Clear',
'state.binary_sensor.smoke.on': 'Detected',
'state.binary_sensor.sound.off': 'Clear',
'state.binary_sensor.sound.on': 'Detected',
'state.binary_sensor.vibration.off': 'Clear',
'state.binary_sensor.vibration.on': 'Detected',
'state.binary_sensor.window.off': 'Closed',
'state.binary_sensor.window.on': 'Open',
'state.calendar.off': 'Off',
'state.calendar.on': 'On',
'state.camera.recording': 'Recording',
'state.camera.streaming': 'Streaming',
'state.camera.idle': 'Idle',
'state.climate.off': 'Off',
'state.climate.on': 'On',
'state.climate.heat': 'Heat',
'state.climate.cool': 'Cool',
'state.climate.idle': 'Idle',
'state.climate.auto': 'Auto',
'state.climate.dry': 'Dry',
'state.climate.fan_only': 'Fan only',
'state.climate.eco': 'Eco',
'state.climate.electric': 'Electric',
'state.climate.performance': 'Performance',
'state.climate.high_demand': 'High demand',
'state.climate.heat_pump': 'Heat pump',
'state.climate.gas': 'Gas',
'state.configurator.configure': 'Configure',
'state.configurator.configured': 'Configured',
'state.cover.open': 'Open',
'state.cover.opening': 'Opening',
'state.cover.closed': 'Closed',
'state.cover.closing': 'Closing',
'state.cover.stopped': 'Stopped',
'state.device_tracker.home': 'Home',
'state.device_tracker.not_home': 'Away',
'state.fan.off': 'Off',
'state.fan.on': 'On',
'state.group.off': 'Off',
'state.group.on': 'On',
'state.group.home': 'Home',
'state.group.not_home': 'Away',
'state.group.open': 'Open',
'state.group.opening': 'Opening',
'state.group.closed': 'Closed',
'state.group.closing': 'Closing',
'state.group.stopped': 'Stopped',
'state.group.locked': 'Locked',
'state.group.unlocked': 'Unlocked',
'state.group.ok': 'OK',
'state.group.problem': 'Problem',
'state.input_boolean.off': 'Off',
'state.input_boolean.on': 'On',
'state.light.off': 'Off',
'state.light.on': 'On',
'state.lock.locked': 'Locked',
'state.lock.unlocked': 'Unlocked',
'state.media_player.off': 'Off',
'state.media_player.on': 'On',
'state.media_player.playing': 'Playing',
'state.media_player.paused': 'Paused',
'state.media_player.idle': 'Idle',
'state.media_player.standby': 'Standby',
'state.plant.ok': 'OK',
'state.plant.problem': 'Problem',
'state.remote.off': 'Off',
'state.remote.on': 'On',
'state.scene.scening': 'Scening',
'state.script.off': 'Off',
'state.script.on': 'On',
'state.sensor.off': 'Off',
'state.sensor.on': 'On',
'state.sun.above_horizon': 'Above horizon',
'state.sun.below_horizon': 'Below horizon',
'state.switch.off': 'Off',
'state.switch.on': 'On',
'state.weather.clear-night': 'Clear, night',
'state.weather.cloudy': 'Cloudy',
'state.weather.fog': 'Fog',
'state.weather.hail': 'Hail',
'state.weather.lightning': 'Lightning',
'state.weather.lightning-rainy': 'Lightning, rainy',
'state.weather.partlycloudy': 'Partly cloudy',
'state.weather.pouring': 'Pouring',
'state.weather.rainy': 'Rainy',
'state.weather.snowy': 'Snowy',
'state.weather.snowy-rainy': 'Snowy, rainy',
'state.weather.sunny': 'Sunny',
'state.weather.windy': 'Windy',
'state.weather.windy-variant': 'Windy',
'state.zwave.default.initializing': 'Initializing',
'state.zwave.default.dead': 'Dead',
'state.zwave.default.sleeping': 'Sleeping',
'state.zwave.default.ready': 'Ready',
'state.zwave.query_stage.initializing': 'Initializing ({query_stage})',
'state.zwave.query_stage.dead': 'Dead ({query_stage})',
'state_badge.default.unknown': 'Unk',
'state_badge.default.unavailable': 'Unavai',
'state_badge.alarm_control_panel.armed': 'Armed',
'state_badge.alarm_control_panel.disarmed': 'Disarm',
'state_badge.alarm_control_panel.armed_home': 'Armed',
'state_badge.alarm_control_panel.armed_away': 'Armed',
'state_badge.alarm_control_panel.armed_night': 'Armed',
'state_badge.alarm_control_panel.armed_custom_bypass': 'Armed',
'state_badge.alarm_control_panel.pending': 'Pend',
'state_badge.alarm_control_panel.arming': 'Arming',
'state_badge.alarm_control_panel.disarming': 'Disarm',
'state_badge.alarm_control_panel.triggered': 'Trig',
'state_badge.device_tracker.home': 'Home',
'state_badge.device_tracker.not_home': 'Away',
'ui.card.alarm_control_panel.code': 'Code',
'ui.card.alarm_control_panel.clear_code': 'Clear',
'ui.card.alarm_control_panel.disarm': 'Disarm',
'ui.card.alarm_control_panel.arm_home': 'Arm home',
'ui.card.alarm_control_panel.arm_away': 'Arm away',
'ui.card.automation.last_triggered': 'Last triggered',
'ui.card.automation.trigger': 'Trigger',
'ui.card.camera.not_available': 'Image not available',
'ui.card.climate.currently': 'Currently',
'ui.card.climate.on_off': 'On / off',
'ui.card.climate.target_temperature': 'Target temperature',
'ui.card.climate.target_humidity': 'Target humidity',
'ui.card.climate.operation': 'Operation',
'ui.card.climate.fan_mode': 'Fan mode',
'ui.card.climate.swing_mode': 'Swing mode',
'ui.card.climate.away_mode': 'Away mode',
'ui.card.climate.aux_heat': 'Aux heat',
'ui.card.cover.position': 'Position',
'ui.card.cover.tilt_position': 'Tilt position',
'ui.card.fan.speed': 'Speed',
'ui.card.fan.oscillate': 'Oscillate',
'ui.card.fan.direction': 'Direction',
'ui.card.light.brightness': 'Brightness',
'ui.card.light.color_temperature': 'Color temperature',
'ui.card.light.white_value': 'White value',
'ui.card.light.effect': 'Effect',
'ui.card.lock.code': 'Code',
'ui.card.lock.lock': 'Lock',
'ui.card.lock.unlock': 'Unlock',
'ui.card.media_player.source': 'Source',
'ui.card.media_player.sound_mode': 'Sound mode',
'ui.card.media_player.text_to_speak': 'Text to speak',
'ui.card.persistent_notification.dismiss': 'Dismiss',
'ui.card.scene.activate': 'Activate',
'ui.card.script.execute': 'Execute',
'ui.card.weather.attributes.air_pressure': 'Air pressure',
'ui.card.weather.attributes.humidity': 'Humidity',
'ui.card.weather.attributes.temperature': 'Temperature',
'ui.card.weather.attributes.visibility': 'Visibility',
'ui.card.weather.attributes.wind_speed': 'Wind speed',
'ui.card.weather.cardinal_direction.e': 'E',
'ui.card.weather.cardinal_direction.ene': 'ENE',
'ui.card.weather.cardinal_direction.ese': 'ESE',
'ui.card.weather.cardinal_direction.n': 'N',
'ui.card.weather.cardinal_direction.ne': 'NE',
'ui.card.weather.cardinal_direction.nne': 'NNE',
'ui.card.weather.cardinal_direction.nw': 'NW',
'ui.card.weather.cardinal_direction.nnw': 'NNW',
'ui.card.weather.cardinal_direction.s': 'S',
'ui.card.weather.cardinal_direction.se': 'SE',
'ui.card.weather.cardinal_direction.sse': 'SSE',
'ui.card.weather.cardinal_direction.ssw': 'SSW',
'ui.card.weather.cardinal_direction.sw': 'SW',
'ui.card.weather.cardinal_direction.w': 'W',
'ui.card.weather.cardinal_direction.wnw': 'WNW',
'ui.card.weather.cardinal_direction.wsw': 'WSW',
'ui.card.weather.forecast': 'Forecast',
'ui.common.loading': 'Loading',
'ui.common.cancel': 'Cancel',
'ui.components.entity.entity-picker.entity': 'Entity',
'ui.components.relative_time.past': '{time} ago',
'ui.components.relative_time.future': 'In {time}',
'ui.components.relative_time.never': 'Never',
'ui.components.relative_time.duration.second': '{count} {count, plural,\n one {second}\n other {seconds}\n}',
'ui.components.relative_time.duration.minute': '{count} {count, plural,\n one {minute}\n other {minutes}\n}',
'ui.components.relative_time.duration.hour': '{count} {count, plural,\n one {hour}\n other {hours}\n}',
'ui.components.relative_time.duration.day': '{count} {count, plural,\n one {day}\n other {days}\n}',
'ui.components.relative_time.duration.week': '{count} {count, plural,\n one {week}\n other {weeks}\n}',
'ui.components.history_charts.loading_history': 'Loading state history...',
'ui.components.history_charts.no_history_found': 'No state history found.',
'ui.components.service-picker.service': 'Service',
'ui.dialogs.more_info_settings.save': 'Save',
'ui.dialogs.more_info_settings.name': 'Name',
'ui.duration.second': '{count} {count, plural,\n one {second}\n other {seconds}\n}',
'ui.duration.minute': '{count} {count, plural,\n one {minute}\n other {minutes}\n}',
'ui.duration.hour': '{count} {count, plural,\n one {hour}\n other {hours}\n}',
'ui.duration.day': '{count} {count, plural,\n one {day}\n other {days}\n}',
'ui.duration.week': '{count} {count, plural,\n one {week}\n other {weeks}\n}',
'ui.login-form.password': 'Password',
'ui.login-form.remember': 'Remember',
'ui.login-form.log_in': 'Log in',
'ui.notification_toast.entity_turned_on': 'Turned on {entity}.',
'ui.notification_toast.entity_turned_off': 'Turned off {entity}.',
'ui.notification_toast.service_called': 'Service {service} called.',
'ui.notification_toast.service_call_failed': 'Failed to call service {service}.',
'ui.notification_toast.connection_lost': 'Connection lost. Reconnecting…',
'ui.sidebar.developer_tools': 'Developer tools',
'ui.sidebar.log_out': 'Log out',
'attribute.weather.humidity': 'Humidity',
'attribute.weather.visibility': 'Visibility',
'attribute.weather.wind_speed': 'Wind speed',
}
"state.default.off": "Off",
"state.default.on": "On",
"state.default.unknown": "Unknown",
"state.default.unavailable": "Unavailable",
"state.alarm_control_panel.armed": "Armed",
"state.alarm_control_panel.disarmed": "Disarmed",
"state.alarm_control_panel.armed_home": "Armed home",
"state.alarm_control_panel.armed_away": "Armed away",
"state.alarm_control_panel.armed_night": "Armed night",
"state.alarm_control_panel.armed_custom_bypass": "Armed custom bypass",
"state.alarm_control_panel.pending": "Pending",
"state.alarm_control_panel.arming": "Arming",
"state.alarm_control_panel.disarming": "Disarming",
"state.alarm_control_panel.triggered": "Triggered",
"state.automation.off": "Off",
"state.automation.on": "On",
"state.binary_sensor.default.off": "Off",
"state.binary_sensor.default.on": "On",
"state.binary_sensor.battery.off": "Normal",
"state.binary_sensor.battery.on": "Low",
"state.binary_sensor.cold.off": "Normal",
"state.binary_sensor.cold.on": "Cold",
"state.binary_sensor.connectivity.off": "Disconnected",
"state.binary_sensor.connectivity.on": "Connected",
"state.binary_sensor.door.off": "Closed",
"state.binary_sensor.door.on": "Open",
"state.binary_sensor.garage_door.off": "Closed",
"state.binary_sensor.garage_door.on": "Open",
"state.binary_sensor.gas.off": "Clear",
"state.binary_sensor.gas.on": "Detected",
"state.binary_sensor.heat.off": "Normal",
"state.binary_sensor.heat.on": "Hot",
"state.binary_sensor.lock.off": "Locked",
"state.binary_sensor.lock.on": "Unlocked",
"state.binary_sensor.moisture.off": "Dry",
"state.binary_sensor.moisture.on": "Wet",
"state.binary_sensor.motion.off": "Clear",
"state.binary_sensor.motion.on": "Detected",
"state.binary_sensor.occupancy.off": "Clear",
"state.binary_sensor.occupancy.on": "Detected",
"state.binary_sensor.opening.off": "Closed",
"state.binary_sensor.opening.on": "Open",
"state.binary_sensor.presence.off": "Away",
"state.binary_sensor.presence.on": "Home",
"state.binary_sensor.problem.off": "OK",
"state.binary_sensor.problem.on": "Problem",
"state.binary_sensor.safety.off": "Safe",
"state.binary_sensor.safety.on": "Unsafe",
"state.binary_sensor.smoke.off": "Clear",
"state.binary_sensor.smoke.on": "Detected",
"state.binary_sensor.sound.off": "Clear",
"state.binary_sensor.sound.on": "Detected",
"state.binary_sensor.vibration.off": "Clear",
"state.binary_sensor.vibration.on": "Detected",
"state.binary_sensor.window.off": "Closed",
"state.binary_sensor.window.on": "Open",
"state.calendar.off": "Off",
"state.calendar.on": "On",
"state.camera.recording": "Recording",
"state.camera.streaming": "Streaming",
"state.camera.idle": "Idle",
"state.climate.off": "Off",
"state.climate.on": "On",
"state.climate.heat": "Heat",
"state.climate.cool": "Cool",
"state.climate.idle": "Idle",
"state.climate.auto": "Auto",
"state.climate.dry": "Dry",
"state.climate.fan_only": "Fan only",
"state.climate.eco": "Eco",
"state.climate.electric": "Electric",
"state.climate.performance": "Performance",
"state.climate.high_demand": "High demand",
"state.climate.heat_pump": "Heat pump",
"state.climate.gas": "Gas",
"state.configurator.configure": "Configure",
"state.configurator.configured": "Configured",
"state.cover.open": "Open",
"state.cover.opening": "Opening",
"state.cover.closed": "Closed",
"state.cover.closing": "Closing",
"state.cover.stopped": "Stopped",
"state.device_tracker.home": "Home",
"state.device_tracker.not_home": "Away",
"state.fan.off": "Off",
"state.fan.on": "On",
"state.group.off": "Off",
"state.group.on": "On",
"state.group.home": "Home",
"state.group.not_home": "Away",
"state.group.open": "Open",
"state.group.opening": "Opening",
"state.group.closed": "Closed",
"state.group.closing": "Closing",
"state.group.stopped": "Stopped",
"state.group.locked": "Locked",
"state.group.unlocked": "Unlocked",
"state.group.ok": "OK",
"state.group.problem": "Problem",
"state.input_boolean.off": "Off",
"state.input_boolean.on": "On",
"state.light.off": "Off",
"state.light.on": "On",
"state.lock.locked": "Locked",
"state.lock.unlocked": "Unlocked",
"state.media_player.off": "Off",
"state.media_player.on": "On",
"state.media_player.playing": "Playing",
"state.media_player.paused": "Paused",
"state.media_player.idle": "Idle",
"state.media_player.standby": "Standby",
"state.plant.ok": "OK",
"state.plant.problem": "Problem",
"state.remote.off": "Off",
"state.remote.on": "On",
"state.scene.scening": "Scening",
"state.script.off": "Off",
"state.script.on": "On",
"state.sensor.off": "Off",
"state.sensor.on": "On",
"state.sun.above_horizon": "Above horizon",
"state.sun.below_horizon": "Below horizon",
"state.switch.off": "Off",
"state.switch.on": "On",
"state.weather.clear-night": "Clear, night",
"state.weather.cloudy": "Cloudy",
"state.weather.fog": "Fog",
"state.weather.hail": "Hail",
"state.weather.lightning": "Lightning",
"state.weather.lightning-rainy": "Lightning, rainy",
"state.weather.partlycloudy": "Partly cloudy",
"state.weather.pouring": "Pouring",
"state.weather.rainy": "Rainy",
"state.weather.snowy": "Snowy",
"state.weather.snowy-rainy": "Snowy, rainy",
"state.weather.sunny": "Sunny",
"state.weather.windy": "Windy",
"state.weather.windy-variant": "Windy",
"state.zwave.default.initializing": "Initializing",
"state.zwave.default.dead": "Dead",
"state.zwave.default.sleeping": "Sleeping",
"state.zwave.default.ready": "Ready",
"state.zwave.query_stage.initializing": "Initializing ({query_stage})",
"state.zwave.query_stage.dead": "Dead ({query_stage})",
"state_badge.default.unknown": "Unk",
"state_badge.default.unavailable": "Unavai",
"state_badge.alarm_control_panel.armed": "Armed",
"state_badge.alarm_control_panel.disarmed": "Disarm",
"state_badge.alarm_control_panel.armed_home": "Armed",
"state_badge.alarm_control_panel.armed_away": "Armed",
"state_badge.alarm_control_panel.armed_night": "Armed",
"state_badge.alarm_control_panel.armed_custom_bypass": "Armed",
"state_badge.alarm_control_panel.pending": "Pend",
"state_badge.alarm_control_panel.arming": "Arming",
"state_badge.alarm_control_panel.disarming": "Disarm",
"state_badge.alarm_control_panel.triggered": "Trig",
"state_badge.device_tracker.home": "Home",
"state_badge.device_tracker.not_home": "Away",
"ui.card.alarm_control_panel.code": "Code",
"ui.card.alarm_control_panel.clear_code": "Clear",
"ui.card.alarm_control_panel.disarm": "Disarm",
"ui.card.alarm_control_panel.arm_home": "Arm home",
"ui.card.alarm_control_panel.arm_away": "Arm away",
"ui.card.automation.last_triggered": "Last triggered",
"ui.card.automation.trigger": "Trigger",
"ui.card.camera.not_available": "Image not available",
"ui.card.climate.currently": "Currently",
"ui.card.climate.on_off": "On / off",
"ui.card.climate.target_temperature": "Target temperature",
"ui.card.climate.target_humidity": "Target humidity",
"ui.card.climate.operation": "Operation",
"ui.card.climate.fan_mode": "Fan mode",
"ui.card.climate.swing_mode": "Swing mode",
"ui.card.climate.away_mode": "Away mode",
"ui.card.climate.aux_heat": "Aux heat",
"ui.card.cover.position": "Position",
"ui.card.cover.tilt_position": "Tilt position",
"ui.card.fan.speed": "Speed",
"ui.card.fan.oscillate": "Oscillate",
"ui.card.fan.direction": "Direction",
"ui.card.light.brightness": "Brightness",
"ui.card.light.color_temperature": "Color temperature",
"ui.card.light.white_value": "White value",
"ui.card.light.effect": "Effect",
"ui.card.lock.code": "Code",
"ui.card.lock.lock": "Lock",
"ui.card.lock.unlock": "Unlock",
"ui.card.media_player.source": "Source",
"ui.card.media_player.sound_mode": "Sound mode",
"ui.card.media_player.text_to_speak": "Text to speak",
"ui.card.persistent_notification.dismiss": "Dismiss",
"ui.card.scene.activate": "Activate",
"ui.card.script.execute": "Execute",
"ui.card.weather.attributes.air_pressure": "Air pressure",
"ui.card.weather.attributes.humidity": "Humidity",
"ui.card.weather.attributes.temperature": "Temperature",
"ui.card.weather.attributes.visibility": "Visibility",
"ui.card.weather.attributes.wind_speed": "Wind speed",
"ui.card.weather.cardinal_direction.e": "E",
"ui.card.weather.cardinal_direction.ene": "ENE",
"ui.card.weather.cardinal_direction.ese": "ESE",
"ui.card.weather.cardinal_direction.n": "N",
"ui.card.weather.cardinal_direction.ne": "NE",
"ui.card.weather.cardinal_direction.nne": "NNE",
"ui.card.weather.cardinal_direction.nw": "NW",
"ui.card.weather.cardinal_direction.nnw": "NNW",
"ui.card.weather.cardinal_direction.s": "S",
"ui.card.weather.cardinal_direction.se": "SE",
"ui.card.weather.cardinal_direction.sse": "SSE",
"ui.card.weather.cardinal_direction.ssw": "SSW",
"ui.card.weather.cardinal_direction.sw": "SW",
"ui.card.weather.cardinal_direction.w": "W",
"ui.card.weather.cardinal_direction.wnw": "WNW",
"ui.card.weather.cardinal_direction.wsw": "WSW",
"ui.card.weather.forecast": "Forecast",
"ui.common.loading": "Loading",
"ui.common.cancel": "Cancel",
"ui.components.entity.entity-picker.entity": "Entity",
"ui.components.relative_time.past": "{time} ago",
"ui.components.relative_time.future": "In {time}",
"ui.components.relative_time.never": "Never",
"ui.components.relative_time.duration.second":
"{count} {count, plural,\n one {second}\n other {seconds}\n}",
"ui.components.relative_time.duration.minute":
"{count} {count, plural,\n one {minute}\n other {minutes}\n}",
"ui.components.relative_time.duration.hour":
"{count} {count, plural,\n one {hour}\n other {hours}\n}",
"ui.components.relative_time.duration.day":
"{count} {count, plural,\n one {day}\n other {days}\n}",
"ui.components.relative_time.duration.week":
"{count} {count, plural,\n one {week}\n other {weeks}\n}",
"ui.components.history_charts.loading_history": "Loading state history...",
"ui.components.history_charts.no_history_found": "No state history found.",
"ui.components.service-picker.service": "Service",
"ui.dialogs.more_info_settings.save": "Save",
"ui.dialogs.more_info_settings.name": "Name",
"ui.duration.second":
"{count} {count, plural,\n one {second}\n other {seconds}\n}",
"ui.duration.minute":
"{count} {count, plural,\n one {minute}\n other {minutes}\n}",
"ui.duration.hour":
"{count} {count, plural,\n one {hour}\n other {hours}\n}",
"ui.duration.day":
"{count} {count, plural,\n one {day}\n other {days}\n}",
"ui.duration.week":
"{count} {count, plural,\n one {week}\n other {weeks}\n}",
"ui.login-form.password": "Password",
"ui.login-form.remember": "Remember",
"ui.login-form.log_in": "Log in",
"ui.notification_toast.entity_turned_on": "Turned on {entity}.",
"ui.notification_toast.entity_turned_off": "Turned off {entity}.",
"ui.notification_toast.service_called": "Service {service} called.",
"ui.notification_toast.service_call_failed":
"Failed to call service {service}.",
"ui.notification_toast.connection_lost": "Connection lost. Reconnecting…",
"ui.sidebar.developer_tools": "Developer tools",
"ui.sidebar.log_out": "Log out",
"attribute.weather.humidity": "Humidity",
"attribute.weather.visibility": "Visibility",
"attribute.weather.wind_speed": "Wind speed",
},
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
const now = () => new Date().toISOString();
const randomTime = () =>
new Date(new Date().getTime() - (Math.random() * 80 * 60 * 1000)).toISOString();
new Date(new Date().getTime() - Math.random() * 80 * 60 * 1000).toISOString();
/* eslint-disable no-unused-vars */
@@ -18,19 +18,23 @@ export class Entity {
}
async handleService(domain, service, data) {
console.log(`Unmocked service for ${this.entityId}: ${domain}/${service}`, data);
console.log(
`Unmocked service for ${this.entityId}: ${domain}/${service}`,
data
);
}
update(state, attributes = {}) {
this.state = state;
this.lastUpdated = now();
this.lastChanged = state === this.state ? this.lastChanged : this.lastUpdated;
this.lastChanged =
state === this.state ? this.lastChanged : this.lastUpdated;
this.attributes = Object.assign({}, this.baseAttributes, attributes);
console.log('update', this.entityId, this);
console.log("update", this.entityId, this);
this.hass.updateStates({
[this.entityId]: this.toState()
[this.entityId]: this.toState(),
});
}
@@ -47,22 +51,25 @@ export class Entity {
export class LightEntity extends Entity {
async handleService(domain, service, data) {
if (!['homeassistant', this.domain].includes(domain)) return;
if (!["homeassistant", this.domain].includes(domain)) return;
if (service === 'turn_on') {
if (service === "turn_on") {
// eslint-disable-next-line
const { brightness, hs_color } = data;
this.update('on', Object.assign(this.attributes, {
brightness,
hs_color,
}));
} else if (service === 'turn_off') {
this.update('off');
} else if (service === 'toggle') {
if (this.state === 'on') {
this.handleService(domain, 'turn_off', data);
this.update(
"on",
Object.assign(this.attributes, {
brightness,
hs_color,
})
);
} else if (service === "turn_off") {
this.update("off");
} else if (service === "toggle") {
if (this.state === "on") {
this.handleService(domain, "turn_off", data);
} else {
this.handleService(domain, 'turn_on', data);
this.handleService(domain, "turn_on", data);
}
}
}
@@ -72,10 +79,10 @@ export class LockEntity extends Entity {
async handleService(domain, service, data) {
if (domain !== this.domain) return;
if (service === 'lock') {
this.update('locked');
} else if (service === 'unlock') {
this.update('unlocked');
if (service === "lock") {
this.update("locked");
} else if (service === "unlock") {
this.update("unlocked");
}
}
}
@@ -84,24 +91,26 @@ export class CoverEntity extends Entity {
async handleService(domain, service, data) {
if (domain !== this.domain) return;
if (service === 'open_cover') {
this.update('open');
} else if (service === 'close_cover') {
this.update('closing');
if (service === "open_cover") {
this.update("open");
} else if (service === "close_cover") {
this.update("closing");
}
}
}
export class GroupEntity extends Entity {
async handleService(domain, service, data) {
if (!['homeassistant', this.domain].includes(domain)) return;
if (!["homeassistant", this.domain].includes(domain)) return;
await Promise.all(this.attributes.entity_id.map((ent) => {
const entity = this.hass.mockEntities[ent];
return entity.handleService(entity.domain, service, data);
}));
await Promise.all(
this.attributes.entity_id.map((ent) => {
const entity = this.hass.mockEntities[ent];
return entity.handleService(entity.domain, service, data);
})
);
this.update(service === 'turn_on' ? 'on' : 'off');
this.update(service === "turn_on" ? "on" : "off");
}
}

View File

@@ -9,16 +9,18 @@ export default class FakeHass {
}
async callService(domain, service, serviceData) {
console.log('callService', { domain, service, serviceData });
console.log("callService", { domain, service, serviceData });
return Promise.resolve();
}
async callWS(msg) {
const callback = this._wsCommands[msg.type];
return callback ? callback(msg) : Promise.reject({
code: 'command_not_mocked',
message: 'This command is not implemented in the gallery.',
});
return callback
? callback(msg)
: Promise.reject({
code: "command_not_mocked",
message: "This command is not implemented in the gallery.",
});
}
async sendWS(msg) {
@@ -29,6 +31,6 @@ export default class FakeHass {
} else {
console.error(`Unknown command: ${msg.type}`);
}
console.log('sendWS', msg);
console.log("sendWS", msg);
}
}

View File

@@ -1,9 +1,9 @@
import fireEvent from '../../../src/common/dom/fire_event.js';
import { fireEvent } from "../../../src/common/dom/fire_event.js";
import demoConfig from './demo_config.js';
import demoResources from './demo_resources.js';
import demoConfig from "./demo_config.js";
import demoResources from "./demo_resources.js";
const ensureArray = val => (Array.isArray(val) ? val : [val]);
const ensureArray = (val) => (Array.isArray(val) ? val : [val]);
export default (elements, { initialStates = {} } = {}) => {
elements = ensureArray(elements);
@@ -14,13 +14,15 @@ export default (elements, { initialStates = {} } = {}) => {
function updateHass(obj) {
hass = Object.assign({}, hass, obj);
elements.forEach((el) => { el.hass = hass; });
elements.forEach((el) => {
el.hass = hass;
});
}
updateHass({
// Home Assistant properties
config: demoConfig,
language: 'en',
language: "en",
resources: demoResources,
states: initialStates,
@@ -29,21 +31,28 @@ export default (elements, { initialStates = {} } = {}) => {
// Home Assistant functions
async callService(domain, service, data) {
fireEvent(elements[0], 'show-notification', { message: `Called service ${domain}/${service}` });
fireEvent(elements[0], "show-notification", {
message: `Called service ${domain}/${service}`,
});
if (data.entity_id) {
await Promise.all(ensureArray(data.entity_id).map(ent =>
entities[ent].handleService(domain, service, data)));
await Promise.all(
ensureArray(data.entity_id).map((ent) =>
entities[ent].handleService(domain, service, data)
)
);
} else {
console.log('unmocked callService', domain, service, data);
console.log("unmocked callService", domain, service, data);
}
},
async callWS(msg) {
const callback = wsCommands[msg.type];
return callback ? callback(msg) : Promise.reject({
code: 'command_not_mocked',
message: 'This command is not implemented in the gallery.',
});
return callback
? callback(msg)
: Promise.reject({
code: "command_not_mocked",
message: "This command is not implemented in the gallery.",
});
},
async sendWS(msg) {
@@ -54,7 +63,7 @@ export default (elements, { initialStates = {} } = {}) => {
} else {
console.error(`Unknown command: ${msg.type}`);
}
console.log('sendWS', msg);
console.log("sendWS", msg);
},
// Mock functions
@@ -72,7 +81,7 @@ export default (elements, { initialStates = {} } = {}) => {
states[ent.entityId] = ent.toState();
});
this.updateStates(states);
}
},
});
return hass;

View File

@@ -0,0 +1,75 @@
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import getEntity from "../data/entity.js";
import provideHass from "../data/provide_hass.js";
import "../components/demo-cards.js";
const ENTITIES = [
getEntity("alarm_control_panel", "alarm", "disarmed", {
friendly_name: "Alarm",
}),
getEntity("alarm_control_panel", "alarm_armed", "armed_home", {
friendly_name: "Alarm",
}),
];
const CONFIGS = [
{
heading: "Basic Example",
config: `
- type: alarm-panel
entity: alarm_control_panel.alarm
`,
},
{
heading: "With Title",
config: `
- type: alarm-panel
entity: alarm_control_panel.alarm_armed
title: My Alarm
`,
},
{
heading: "Using only Arm_Home State",
config: `
- type: alarm-panel
entity: alarm_control_panel.alarm
states:
- arm_home
`,
},
{
heading: "Invalid Entity",
config: `
- type: alarm-panel
entity: alarm_control_panel.alarm1
`,
},
];
class DemoAlarmPanelEntity extends PolymerElement {
static get template() {
return html`
<demo-cards id='demos' hass='[[hass]]' configs="[[_configs]]"></demo-cards>
`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
hass: Object,
};
}
ready() {
super.ready();
const hass = provideHass(this.$.demos);
hass.addEntities(ENTITIES);
}
}
customElements.define("demo-hui-alarm-panel-card", DemoAlarmPanelEntity);

View File

@@ -1,28 +1,28 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import getEntity from '../data/entity.js';
import provideHass from '../data/provide_hass.js';
import '../components/demo-cards.js';
import getEntity from "../data/entity.js";
import provideHass from "../data/provide_hass.js";
import "../components/demo-cards.js";
const ENTITIES = [
getEntity('light', 'controller_1', 'on', {
friendly_name: 'Controller 1'
getEntity("light", "controller_1", "on", {
friendly_name: "Controller 1",
}),
getEntity('light', 'controller_2', 'on', {
friendly_name: 'Controller 2'
getEntity("light", "controller_2", "on", {
friendly_name: "Controller 2",
}),
getEntity('light', 'floor', 'off', {
friendly_name: 'Floor light'
getEntity("light", "floor", "off", {
friendly_name: "Floor light",
}),
getEntity('light', 'kitchen', 'on', {
friendly_name: 'Kitchen light'
getEntity("light", "kitchen", "on", {
friendly_name: "Kitchen light",
}),
];
const CONFIGS = [
{
heading: 'Controller',
heading: "Controller",
config: `
- type: entities
entities:
@@ -31,10 +31,10 @@ const CONFIGS = [
- type: divider
- light.floor
- light.kitchen
`
`,
},
{
heading: 'Demo',
heading: "Demo",
config: `
- type: conditional
conditions:
@@ -49,7 +49,7 @@ const CONFIGS = [
- light.controller_2
- light.floor
- light.kitchen
`
`,
},
];
@@ -68,7 +68,7 @@ class DemoConditional extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
value: CONFIGS,
},
hass: Object,
};
@@ -81,4 +81,4 @@ class DemoConditional extends PolymerElement {
}
}
customElements.define('demo-hui-conditional-card', DemoConditional);
customElements.define("demo-hui-conditional-card", DemoConditional);

View File

@@ -1,75 +1,70 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import getEntity from '../data/entity.js';
import provideHass from '../data/provide_hass.js';
import '../components/demo-cards.js';
import getEntity from "../data/entity.js";
import provideHass from "../data/provide_hass.js";
import "../components/demo-cards.js";
const ENTITIES = [
getEntity('light', 'bed_light', 'on', {
friendly_name: 'Bed Light'
getEntity("light", "bed_light", "on", {
friendly_name: "Bed Light",
}),
getEntity('group', 'kitchen', 'on', {
entity_id: [
'light.bed_light',
],
getEntity("group", "kitchen", "on", {
entity_id: ["light.bed_light"],
order: 8,
friendly_name: 'Kitchen'
friendly_name: "Kitchen",
}),
getEntity('lock', 'kitchen_door', 'locked', {
friendly_name: 'Kitchen Door'
getEntity("lock", "kitchen_door", "locked", {
friendly_name: "Kitchen Door",
}),
getEntity('cover', 'kitchen_window', 'open', {
friendly_name: 'Kitchen Window',
supported_features: 11
getEntity("cover", "kitchen_window", "open", {
friendly_name: "Kitchen Window",
supported_features: 11,
}),
getEntity('scene', 'romantic_lights', 'scening', {
entity_id: [
'light.bed_light',
'light.ceiling_lights'
],
friendly_name: 'Romantic lights'
getEntity("scene", "romantic_lights", "scening", {
entity_id: ["light.bed_light", "light.ceiling_lights"],
friendly_name: "Romantic lights",
}),
getEntity('device_tracker', 'demo_paulus', 'home', {
source_type: 'gps',
getEntity("device_tracker", "demo_paulus", "home", {
source_type: "gps",
latitude: 32.877105,
longitude: 117.232185,
gps_accuracy: 91,
battery: 71,
friendly_name: 'Paulus'
friendly_name: "Paulus",
}),
getEntity('climate', 'ecobee', 'auto', {
getEntity("climate", "ecobee", "auto", {
current_temperature: 73,
min_temp: 45,
max_temp: 95,
temperature: null,
target_temp_high: 75,
target_temp_low: 70,
fan_mode: 'Auto Low',
fan_list: ['On Low', 'On High', 'Auto Low', 'Auto High', 'Off'],
operation_mode: 'auto',
operation_list: ['heat', 'cool', 'auto', 'off'],
hold_mode: 'home',
swing_mode: 'Auto',
swing_list: ['Auto', '1', '2', '3', 'Off'],
unit_of_measurement: '°F',
friendly_name: 'Ecobee',
supported_features: 1014
fan_mode: "Auto Low",
fan_list: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
operation_mode: "auto",
operation_list: ["heat", "cool", "auto", "off"],
hold_mode: "home",
swing_mode: "Auto",
swing_list: ["Auto", "1", "2", "3", "Off"],
unit_of_measurement: "°F",
friendly_name: "Ecobee",
supported_features: 1014,
}),
getEntity('input_number', 'noise_allowance', 5, {
getEntity("input_number", "noise_allowance", 5, {
min: 0,
max: 10,
step: 1,
mode: 'slider',
unit_of_measurement: 'dB',
friendly_name: 'Allowed Noise',
icon: 'mdi:bell-ring'
})
mode: "slider",
unit_of_measurement: "dB",
friendly_name: "Allowed Noise",
icon: "mdi:bell-ring",
}),
];
const CONFIGS = [
{
heading: 'Basic',
heading: "Basic",
config: `
- type: entities
entities:
@@ -82,10 +77,10 @@ const CONFIGS = [
- light.non_existing
- climate.ecobee
- input_number.noise_allowance
`
`,
},
{
heading: 'With title, toggle-able',
heading: "With title, toggle-able",
config: `
- type: entities
entities:
@@ -98,10 +93,10 @@ const CONFIGS = [
- climate.ecobee
- input_number.noise_allowance
title: Random group
`
`,
},
{
heading: 'With title, toggle = false',
heading: "With title, toggle = false",
config: `
- type: entities
entities:
@@ -115,19 +110,19 @@ const CONFIGS = [
- input_number.noise_allowance
title: Random group
show_header_toggle: false
`
`,
},
{
heading: 'With title, can\'t toggle',
heading: "With title, can't toggle",
config: `
- type: entities
entities:
- device_tracker.demo_paulus
title: Random group
`
`,
},
{
heading: 'Custom name, secondary info, custom icon',
heading: "Custom name, secondary info, custom icon",
config: `
- type: entities
entities:
@@ -147,17 +142,13 @@ const CONFIGS = [
- input_number.noise_allowance
title: Random group
show_header_toggle: false
`
`,
},
{
heading: 'Special rows',
heading: "Special rows",
config: `
- type: entities
entities:
- type: weblink
url: http://google.com/
icon: mdi:google
name: Google
- type: call-service
icon: mdi:power
name: Bed light
@@ -165,13 +156,19 @@ const CONFIGS = [
service: light.toggle
service_data:
entity_id: light.bed_light
- type: section
label: Links
- type: weblink
url: http://google.com/
icon: mdi:google
name: Google
- type: divider
- type: divider
style:
height: 30px
margin: 4px 0
background: center / contain url("/images/divider.png") no-repeat
`
`,
},
];
@@ -190,7 +187,7 @@ class DemoEntities extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
value: CONFIGS,
},
hass: Object,
};
@@ -203,4 +200,4 @@ class DemoEntities extends PolymerElement {
}
}
customElements.define('demo-hui-entities-card', DemoEntities);
customElements.define("demo-hui-entities-card", DemoEntities);

View File

@@ -0,0 +1,95 @@
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import getEntity from "../data/entity.js";
import provideHass from "../data/provide_hass.js";
import "../components/demo-cards.js";
const ENTITIES = [
getEntity("light", "bed_light", "on", {
friendly_name: "Bed Light",
}),
];
const CONFIGS = [
{
heading: "Basic example",
config: `
- type: entity-button
entity: light.bed_light
`,
},
{
heading: "With Name",
config: `
- type: entity-button
name: Bedroom
entity: light.bed_light
`,
},
{
heading: "With Icon",
config: `
- type: entity-button
entity: light.bed_light
icon: mdi:hotel
`,
},
{
heading: "Without State",
config: `
- type: entity-button
entity: light.bed_light
show_state: false
`,
},
{
heading: "Custom Tap Action (toggle)",
config: `
- type: entity-button
entity: light.bed_light
tap_action: toggle
`,
},
{
heading: "Running Service",
config: `
- type: entity-button
entity: light.bed_light
service: light.toggle
`,
},
{
heading: "Invalid Entity",
config: `
- type: entity-button
entity: sensor.invalid_entity
`,
},
];
class DemoEntityButtonEntity extends PolymerElement {
static get template() {
return html`
<demo-cards id='demos' hass='[[hass]]' configs="[[_configs]]"></demo-cards>
`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
hass: Object,
};
}
ready() {
super.ready();
const hass = provideHass(this.$.demos);
hass.addEntities(ENTITIES);
}
}
customElements.define("demo-hui-entity-button-card", DemoEntityButtonEntity);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js';
import "../components/demo-cards.js";
const CONFIGS = [
{
heading: 'Basic',
heading: "Basic",
config: `
- type: entity-filter
entities:
@@ -18,10 +18,10 @@ const CONFIGS = [
state_filter:
- "on"
- not_home
`
`,
},
{
heading: 'With card config',
heading: "With card config",
config: `
- type: entity-filter
entities:
@@ -37,10 +37,10 @@ const CONFIGS = [
card:
type: glance
show_state: false
`
`,
},
{
heading: 'Showing single entity conditionally',
heading: "Showing single entity conditionally",
config: `
- type: entity-filter
entities:
@@ -50,8 +50,8 @@ const CONFIGS = [
card:
type: media-control
entity: media_player.lounge_room
`
}
`,
},
];
class DemoFilter extends PolymerElement {
@@ -65,10 +65,10 @@ class DemoFilter extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
}
value: CONFIGS,
},
};
}
}
customElements.define('demo-hui-entity-filter-card', DemoFilter);
customElements.define("demo-hui-entity-filter-card", DemoFilter);

View File

@@ -0,0 +1,83 @@
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import "../components/demo-cards.js";
const CONFIGS = [
{
heading: "Basic example",
config: `
- type: gauge
entity: sensor.brightness
`,
},
{
heading: "With title",
config: `
- type: gauge
title: Humidity
entity: sensor.outside_humidity
`,
},
{
heading: "Custom Unit of Measurement",
config: `
- type: gauge
entity: sensor.outside_temperature
unit_of_measurement: C
`,
},
{
heading: "Setting Severity Levels",
config: `
- type: gauge
entity: sensor.brightness
severity:
red: 32
green: 0
yellow: 23
`,
},
{
heading: "Setting Min and Max Values",
config: `
- type: gauge
entity: sensor.brightness
min: 0
max: 38
`,
},
{
heading: "Invalid Entity",
config: `
- type: gauge
entity: sensor.invalid_entity
`,
},
{
heading: "Non-Numeric Value",
config: `
- type: gauge
entity: plant.bonsai
`,
},
];
class DemoGaugeEntity extends PolymerElement {
static get template() {
return html`
<demo-cards configs="[[_configs]]"></demo-cards>
`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
}
customElements.define("demo-hui-gauge-card", DemoGaugeEntity);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js';
import "../components/demo-cards.js";
const CONFIGS = [
{
heading: 'Basic example',
heading: "Basic example",
config: `
- type: glance
entities:
@@ -16,10 +16,10 @@ const CONFIGS = [
- light.kitchen_lights
- lock.kitchen_door
- light.ceiling_lights
`
`,
},
{
heading: 'With title',
heading: "With title",
config: `
- type: glance
title: This is glance
@@ -31,10 +31,10 @@ const CONFIGS = [
- light.kitchen_lights
- lock.kitchen_door
- light.ceiling_lights
`
`,
},
{
heading: 'Custom column width',
heading: "Custom column width",
config: `
- type: glance
column_width: calc(100% / 7)
@@ -46,10 +46,10 @@ const CONFIGS = [
- light.kitchen_lights
- lock.kitchen_door
- light.ceiling_lights
`
`,
},
{
heading: 'No name',
heading: "No name",
config: `
- type: glance
show_name: false
@@ -61,10 +61,10 @@ const CONFIGS = [
- light.kitchen_lights
- lock.kitchen_door
- light.ceiling_lights
`
`,
},
{
heading: 'No state',
heading: "No state",
config: `
- type: glance
show_state: false
@@ -76,10 +76,10 @@ const CONFIGS = [
- light.kitchen_lights
- lock.kitchen_door
- light.ceiling_lights
`
`,
},
{
heading: 'No name and no state',
heading: "No name and no state",
config: `
- type: glance
show_name: false
@@ -92,10 +92,10 @@ const CONFIGS = [
- light.kitchen_lights
- lock.kitchen_door
- light.ceiling_lights
`
`,
},
{
heading: 'Custom name, custom icon',
heading: "Custom name, custom icon",
config: `
- type: glance
entities:
@@ -109,10 +109,10 @@ const CONFIGS = [
icon: mdi:alarm-light
- lock.kitchen_door
- light.ceiling_lights
`
`,
},
{
heading: 'Custom tap action',
heading: "Custom tap action",
config: `
- type: glance
entities:
@@ -126,10 +126,10 @@ const CONFIGS = [
- sun.sun
- cover.kitchen_window
- light.kitchen_lights
`
`,
},
{
heading: 'Selectively hidden name',
heading: "Selectively hidden name",
config: `
- type: glance
entities:
@@ -140,7 +140,22 @@ const CONFIGS = [
- entity: cover.kitchen_window
name:
- light.kitchen_lights
`
`,
},
{
heading: "Primary theme",
config: `
- type: glance
theming: primary
entities:
- device_tracker.demo_paulus
- media_player.living_room
- sun.sun
- cover.kitchen_window
- light.kitchen_lights
- lock.kitchen_door
- light.ceiling_lights
`,
},
];
@@ -155,10 +170,10 @@ class DemoPicEntity extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
}
value: CONFIGS,
},
};
}
}
customElements.define('demo-hui-glance-card', DemoPicEntity);
customElements.define("demo-hui-glance-card", DemoPicEntity);

View File

@@ -1,39 +1,39 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js';
import "../components/demo-cards.js";
const CONFIGS = [
{
heading: 'Without title',
heading: "Without title",
config: `
- type: iframe
url: https://embed.windy.com/embed2.html
`
`,
},
{
heading: 'With title',
heading: "With title",
config: `
- type: iframe
url: https://embed.windy.com/embed2.html
title: Weather radar
`
`,
},
{
heading: 'Height-Width 3:4',
heading: "Height-Width 3:4",
config: `
- type: iframe
url: https://embed.windy.com/embed2.html
aspect_ratio: 75%
`
`,
},
{
heading: 'Height-Width 1:1',
heading: "Height-Width 1:1",
config: `
- type: iframe
url: https://embed.windy.com/embed2.html
aspect_ratio: 100%
`
`,
},
];
@@ -48,10 +48,10 @@ class DemoIframe extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
}
value: CONFIGS,
},
};
}
}
customElements.define('demo-hui-iframe-card', DemoIframe);
customElements.define("demo-hui-iframe-card", DemoIframe);

View File

@@ -1,120 +1,120 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import getEntity from '../data/entity.js';
import provideHass from '../data/provide_hass.js';
import '../components/demo-cards.js';
import getEntity from "../data/entity.js";
import provideHass from "../data/provide_hass.js";
import "../components/demo-cards.js";
const ENTITIES = [
getEntity('device_tracker', 'demo_paulus', 'not_home', {
source_type: 'gps',
getEntity("device_tracker", "demo_paulus", "not_home", {
source_type: "gps",
latitude: 32.877105,
longitude: 117.232185,
gps_accuracy: 91,
battery: 71,
friendly_name: 'Paulus'
friendly_name: "Paulus",
}),
getEntity('device_tracker', 'demo_home_boy', 'home', {
source_type: 'gps',
getEntity("device_tracker", "demo_home_boy", "home", {
source_type: "gps",
latitude: 32.87334,
longitude: 117.22745,
gps_accuracy: 20,
battery: 53,
friendly_name: 'Home Boy'
friendly_name: "Home Boy",
}),
getEntity('zone', 'home', 'zoning', {
getEntity("zone", "home", "zoning", {
latitude: 32.87354,
longitude: 117.22765,
radius: 100,
friendly_name: 'Home',
icon: 'mdi:home'
})
friendly_name: "Home",
icon: "mdi:home",
}),
];
const CONFIGS = [
{
heading: 'Without title',
heading: "Without title",
config: `
- type: map
entities:
- entity: device_tracker.demo_paulus
- device_tracker.demo_home_boy
- zone.home
`
`,
},
{
heading: 'With title',
heading: "With title",
config: `
- type: map
entities:
- entity: device_tracker.demo_paulus
- zone.home
title: Where is Paulus?
`
`,
},
{
heading: 'Height-Width 1:2',
heading: "Height-Width 1:2",
config: `
- type: map
entities:
- entity: device_tracker.demo_paulus
- zone.home
aspect_ratio: 50%
`
`,
},
{
heading: 'Default Zoom',
heading: "Default Zoom",
config: `
- type: map
default_zoom: 12
entities:
- entity: device_tracker.demo_paulus
- zone.home
`
`,
},
{
heading: 'Default Zoom too High',
heading: "Default Zoom too High",
config: `
- type: map
default_zoom: 20
entities:
- entity: device_tracker.demo_paulus
- zone.home
`
`,
},
{
heading: 'Single Marker',
heading: "Single Marker",
config: `
- type: map
entities:
- device_tracker.demo_paulus
`
`,
},
{
heading: 'Single Marker Default Zoom',
heading: "Single Marker Default Zoom",
config: `
- type: map
default_zoom: 8
entities:
- device_tracker.demo_paulus
`
`,
},
{
heading: 'No Entities',
heading: "No Entities",
config: `
- type: map
entities:
- light.bed_light
`
`,
},
{
heading: 'No Entities, Default Zoom',
heading: "No Entities, Default Zoom",
config: `
- type: map
default_zoom: 8
entities:
- light.bed_light
`
`,
},
];
@@ -133,9 +133,9 @@ class DemoMap extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
value: CONFIGS,
},
hass: Object
hass: Object,
};
}
@@ -146,4 +146,4 @@ class DemoMap extends PolymerElement {
}
}
customElements.define('demo-hui-map-card', DemoMap);
customElements.define("demo-hui-map-card", DemoMap);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js';
import "../components/demo-cards.js";
const CONFIGS = [
{
heading: 'markdown-it demo',
heading: "markdown-it demo",
config: `
- type: markdown
content: >
@@ -248,7 +248,7 @@ const CONFIGS = [
::: warning
*here be dragons*
:::
`
`,
},
];
@@ -263,10 +263,10 @@ class DemoMarkdown extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
}
value: CONFIGS,
},
};
}
}
customElements.define('demo-hui-markdown-card', DemoMarkdown);
customElements.define("demo-hui-markdown-card", DemoMarkdown);

View File

@@ -1,58 +1,58 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import getEntity from '../data/entity.js';
import provideHass from '../data/provide_hass.js';
import '../components/demo-cards.js';
import getEntity from "../data/entity.js";
import provideHass from "../data/provide_hass.js";
import "../components/demo-cards.js";
const ENTITIES = [
getEntity('media_player', 'bedroom', 'playing', {
media_content_type: 'movie',
media_title: 'Epic sax guy 10 hours',
app_name: 'YouTube',
supported_features: 32
getEntity("media_player", "bedroom", "playing", {
media_content_type: "movie",
media_title: "Epic sax guy 10 hours",
app_name: "YouTube",
supported_features: 32,
}),
getEntity('media_player', 'family_room', 'paused', {
media_content_type: 'music',
media_title: 'I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)',
media_artist: 'Technohead',
supported_features: 16417
getEntity("media_player", "family_room", "paused", {
media_content_type: "music",
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
media_artist: "Technohead",
supported_features: 16417,
}),
getEntity('media_player', 'family_room_no_play', 'paused', {
media_content_type: 'movie',
media_title: 'Epic sax guy 10 hours',
app_name: 'YouTube',
supported_features: 33
getEntity("media_player", "family_room_no_play", "paused", {
media_content_type: "movie",
media_title: "Epic sax guy 10 hours",
app_name: "YouTube",
supported_features: 33,
}),
getEntity('media_player', 'living_room', 'playing', {
media_content_type: 'tvshow',
media_title: 'Chapter 1',
media_series_title: 'House of Cards',
app_name: 'Netflix',
supported_features: 1
}),
getEntity('media_player', 'lounge_room', 'idle', {
media_content_type: 'music',
media_title: 'I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)',
media_artist: 'Technohead',
getEntity("media_player", "living_room", "playing", {
media_content_type: "tvshow",
media_title: "Chapter 1",
media_series_title: "House of Cards",
app_name: "Netflix",
supported_features: 1,
}),
getEntity('media_player', 'theater', 'off', {
media_content_type: 'movie',
media_title: 'Epic sax guy 10 hours',
app_name: 'YouTube',
supported_features: 33
getEntity("media_player", "lounge_room", "idle", {
media_content_type: "music",
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
media_artist: "Technohead",
supported_features: 1,
}),
getEntity('media_player', 'android_cast', 'playing', {
media_title: 'Android Screen Casting',
app_name: 'Screen Mirroring',
supported_features: 21437
getEntity("media_player", "theater", "off", {
media_content_type: "movie",
media_title: "Epic sax guy 10 hours",
app_name: "YouTube",
supported_features: 33,
}),
getEntity("media_player", "android_cast", "playing", {
media_title: "Android Screen Casting",
app_name: "Screen Mirroring",
supported_features: 21437,
}),
];
const CONFIGS = [
{
heading: 'Media Players',
heading: "Media Players",
config: `
- type: entities
entities:
@@ -70,8 +70,8 @@ const CONFIGS = [
name: Chromcast Idle
- entity: media_player.theater
name: 'Player Off'
`
}
`,
},
];
class DemoHuiMediaPlayerRows extends PolymerElement {
@@ -89,7 +89,7 @@ class DemoHuiMediaPlayerRows extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
value: CONFIGS,
},
hass: Object,
};
@@ -102,4 +102,4 @@ class DemoHuiMediaPlayerRows extends PolymerElement {
}
}
customElements.define('demo-hui-media-player-rows', DemoHuiMediaPlayerRows);
customElements.define("demo-hui-media-player-rows", DemoHuiMediaPlayerRows);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js';
import "../components/demo-cards.js";
const CONFIGS = [
{
heading: 'Card with few elements',
heading: "Card with few elements",
config: `
- type: picture-elements
image: /images/floorplan.png
@@ -49,7 +49,7 @@ const CONFIGS = [
style:
top: 8%
left: 35%
`
`,
},
];
@@ -64,10 +64,10 @@ class DemoPicElements extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
}
value: CONFIGS,
},
};
}
}
customElements.define('demo-hui-picture-elements-card', DemoPicElements);
customElements.define("demo-hui-picture-elements-card", DemoPicElements);

View File

@@ -1,67 +1,67 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js';
import "../components/demo-cards.js";
const CONFIGS = [
{
heading: 'State on',
heading: "State on",
config: `
- type: picture-entity
image: /images/kitchen.png
entity: light.kitchen_lights
`
`,
},
{
heading: 'State off',
heading: "State off",
config: `
- type: picture-entity
image: /images/bed.png
entity: light.bed_light
`
`,
},
{
heading: 'Entity unavailable',
heading: "Entity unavailable",
config: `
- type: picture-entity
image: /images/living_room.png
entity: light.non_existing
`
`,
},
{
heading: 'Camera entity',
heading: "Camera entity",
config: `
- type: picture-entity
entity: camera.demo_camera
`
`,
},
{
heading: 'Hidden name',
heading: "Hidden name",
config: `
- type: picture-entity
image: /images/kitchen.png
entity: light.kitchen_lights
show_name: false
`
`,
},
{
heading: 'Hidden state',
heading: "Hidden state",
config: `
- type: picture-entity
image: /images/kitchen.png
entity: light.kitchen_lights
show_state: false
`
`,
},
{
heading: 'Both hidden',
heading: "Both hidden",
config: `
- type: picture-entity
image: /images/kitchen.png
entity: light.kitchen_lights
show_name: false
show_state: false
`
`,
},
];
@@ -76,10 +76,10 @@ class DemoPicEntity extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
}
value: CONFIGS,
},
};
}
}
customElements.define('demo-hui-picture-entity-card', DemoPicEntity);
customElements.define("demo-hui-picture-entity-card", DemoPicEntity);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js';
import "../components/demo-cards.js";
const CONFIGS = [
{
heading: 'Title, dialog, toggle',
heading: "Title, dialog, toggle",
config: `
- type: picture-glance
image: /images/living_room.png
@@ -15,10 +15,10 @@ const CONFIGS = [
- light.ceiling_lights
- binary_sensor.movement_backyard
- binary_sensor.basement_floor_wet
`
`,
},
{
heading: 'Title, dialog, no toggle',
heading: "Title, dialog, no toggle",
config: `
- type: picture-glance
image: /images/living_room.png
@@ -26,10 +26,10 @@ const CONFIGS = [
entities:
- binary_sensor.movement_backyard
- binary_sensor.basement_floor_wet
`
`,
},
{
heading: 'Title, no dialog, toggle',
heading: "Title, no dialog, toggle",
config: `
- type: picture-glance
image: /images/living_room.png
@@ -37,10 +37,10 @@ const CONFIGS = [
entities:
- switch.decorative_lights
- light.ceiling_lights
`
`,
},
{
heading: 'No title, dialog, toggle',
heading: "No title, dialog, toggle",
config: `
- type: picture-glance
image: /images/living_room.png
@@ -49,30 +49,30 @@ const CONFIGS = [
- light.ceiling_lights
- binary_sensor.movement_backyard
- binary_sensor.basement_floor_wet
`
`,
},
{
heading: 'No title, dialog, no toggle',
heading: "No title, dialog, no toggle",
config: `
- type: picture-glance
image: /images/living_room.png
entities:
- binary_sensor.movement_backyard
- binary_sensor.basement_floor_wet
`
`,
},
{
heading: 'No title, no dialog, toggle',
heading: "No title, no dialog, toggle",
config: `
- type: picture-glance
image: /images/living_room.png
entities:
- switch.decorative_lights
- light.ceiling_lights
`
`,
},
{
heading: 'Custom icon',
heading: "Custom icon",
config: `
- type: picture-glance
image: /images/living_room.png
@@ -81,7 +81,7 @@ const CONFIGS = [
- entity: switch.decorative_lights
icon: mdi:power
- binary_sensor.basement_floor_wet
`
`,
},
];
@@ -96,10 +96,10 @@ class DemoPicGlance extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
}
value: CONFIGS,
},
};
}
}
customElements.define('demo-hui-picture-glance-card', DemoPicGlance);
customElements.define("demo-hui-picture-glance-card", DemoPicGlance);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/demo-cards.js';
import "../components/demo-cards.js";
const CONFIGS = [
{
heading: 'Vertical Stack',
heading: "Vertical Stack",
config: `
- type: vertical-stack
cards:
@@ -17,10 +17,10 @@ const CONFIGS = [
- device_tracker.demo_anne_therese
- device_tracker.demo_home_boy
- device_tracker.demo_paulus
`
`,
},
{
heading: 'Horizontal Stack',
heading: "Horizontal Stack",
config: `
- type: horizontal-stack
cards:
@@ -32,10 +32,10 @@ const CONFIGS = [
- device_tracker.demo_anne_therese
- device_tracker.demo_home_boy
- device_tracker.demo_paulus
`
`,
},
{
heading: 'Combination of both',
heading: "Combination of both",
config: `
- type: vertical-stack
cards:
@@ -52,7 +52,7 @@ const CONFIGS = [
- type: picture-entity
image: /images/bed.png
entity: light.bed_light
`
`,
},
];
@@ -67,10 +67,10 @@ class DemoStack extends PolymerElement {
return {
_configs: {
type: Object,
value: CONFIGS
}
value: CONFIGS,
},
};
}
}
customElements.define('demo-hui-stack-card', DemoStack);
customElements.define("demo-hui-stack-card", DemoStack);

View File

@@ -1,13 +1,13 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/dialogs/more-info/controls/more-info-content.js';
import '../../../src/components/ha-card.js';
import "../../../src/dialogs/more-info/controls/more-info-content.js";
import "../../../src/components/ha-card.js";
import getEntity from '../data/entity.js';
import provideHass from '../data/provide_hass.js';
import getEntity from "../data/entity.js";
import provideHass from "../data/provide_hass.js";
import '../components/demo-more-infos.js';
import "../components/demo-more-infos.js";
/* eslint-disable no-unused-vars */
@@ -20,17 +20,16 @@ const SUPPORT_TRANSITION = 32;
const SUPPORT_WHITE_VALUE = 128;
const ENTITIES = [
getEntity('light', 'bed_light', 'on', {
friendly_name: 'Basic Light'
getEntity("light", "bed_light", "on", {
friendly_name: "Basic Light",
}),
getEntity('light', 'kitchen_light', 'on', {
friendly_name: 'Brightness Light',
getEntity("light", "kitchen_light", "on", {
friendly_name: "Brightness Light",
brightness: 80,
supported_features: SUPPORT_BRIGHTNESS,
}),
];
class DemoMoreInfoLight extends PolymerElement {
static get template() {
return html`
@@ -45,7 +44,7 @@ class DemoMoreInfoLight extends PolymerElement {
return {
_entities: {
type: Array,
value: ENTITIES.map(ent => ent.entityId),
value: ENTITIES.map((ent) => ent.entityId),
},
};
}
@@ -57,4 +56,4 @@ class DemoMoreInfoLight extends PolymerElement {
}
}
customElements.define('demo-more-info-light', DemoMoreInfoLight);
customElements.define("demo-more-info-light", DemoMoreInfoLight);

View File

@@ -1,12 +1,12 @@
import '@polymer/paper-styles/typography.js';
import '@polymer/polymer/lib/elements/dom-if.js';
import '@polymer/polymer/lib/elements/dom-repeat.js';
import "@polymer/paper-styles/typography.js";
import "@polymer/polymer/lib/elements/dom-if.js";
import "@polymer/polymer/lib/elements/dom-repeat.js";
import '../../src/resources/hass-icons.js';
import '../../src/resources/ha-style.js';
import '../../src/resources/roboto.js';
import '../../src/components/ha-iconset-svg.js';
import "../../src/resources/hass-icons.js";
import "../../src/resources/ha-style.js";
import "../../src/resources/roboto.js";
import "../../src/components/ha-iconset-svg.js";
import './ha-gallery.js';
import "./ha-gallery.js";
document.body.appendChild(document.createElement('ha-gallery'));
document.body.appendChild(document.createElement("ha-gallery"));

View File

@@ -1,19 +1,19 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js';
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/iron-icon/iron-icon.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-item/paper-item.js';
import '@polymer/paper-item/paper-item-body.js';
import '@polymer/paper-icon-button/paper-icon-button.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/app-layout/app-header-layout/app-header-layout.js";
import "@polymer/app-layout/app-header/app-header.js";
import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import "@polymer/iron-icon/iron-icon.js";
import "@polymer/paper-card/paper-card.js";
import "@polymer/paper-item/paper-item.js";
import "@polymer/paper-item/paper-item-body.js";
import "@polymer/paper-icon-button/paper-icon-button.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../src/managers/notification-manager.js';
import "../../src/managers/notification-manager.js";
const DEMOS = require.context('./demos', true, /^(.*\.(js$))[^.]*$/im);
const DEMOS = require.context("./demos", true, /^(.*\.(js$))[^.]*$/im);
const fixPath = path => path.substr(2, path.length - 5);
const fixPath = (path) => path.substr(2, path.length - 5);
class HaGallery extends PolymerElement {
static get template() {
@@ -131,19 +131,19 @@ class HaGallery extends PolymerElement {
_demo: {
type: String,
value: document.location.hash.substr(1),
observer: '_demoChanged',
observer: "_demoChanged",
},
_demos: {
type: Array,
value: DEMOS.keys().map(fixPath)
value: DEMOS.keys().map(fixPath),
},
_lovelaceDemos: {
type: Array,
computed: '_computeLovelace(_demos)',
computed: "_computeLovelace(_demos)",
},
_moreInfoDemos: {
type: Array,
computed: '_computeMoreInfos(_demos)',
computed: "_computeMoreInfos(_demos)",
},
};
}
@@ -151,18 +151,21 @@ class HaGallery extends PolymerElement {
ready() {
super.ready();
this.addEventListener(
'show-notification',
ev => this.$.notifications.showNotification(ev.detail.message)
this.addEventListener("show-notification", (ev) =>
this.$.notifications.showNotification(ev.detail.message)
);
this.addEventListener('hass-more-info', (ev) => {
this.addEventListener("hass-more-info", (ev) => {
if (ev.detail.entityId) {
this.$.notifications.showNotification(`Showing more info for ${ev.detail.entityId}`);
this.$.notifications.showNotification(
`Showing more info for ${ev.detail.entityId}`
);
}
});
window.addEventListener('hashchange', () => { this._demo = document.location.hash.substr(1); });
window.addEventListener("hashchange", () => {
this._demo = document.location.hash.substr(1);
});
}
_withDefault(value, def) {
@@ -182,20 +185,20 @@ class HaGallery extends PolymerElement {
}
_computeHeaderButtonClass(demo) {
return demo ? '' : 'invisible';
return demo ? "" : "invisible";
}
_backTapped() {
document.location.hash = '';
document.location.hash = "";
}
_computeLovelace(demos) {
return demos.filter(demo => demo.includes('hui'));
return demos.filter((demo) => demo.includes("hui"));
}
_computeMoreInfos(demos) {
return demos.filter(demo => demo.includes('more-info'));
return demos.filter((demo) => demo.includes("more-info"));
}
}
customElements.define('ha-gallery', HaGallery);
customElements.define("ha-gallery", HaGallery);

View File

@@ -1,76 +1,71 @@
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require("path");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { babelLoaderConfig } = require("../config/babel.js");
const isProd = process.env.NODE_ENV === 'production';
const chunkFilename = isProd ?
'chunk.[chunkhash].js' : '[name].chunk.js';
const buildPath = path.resolve(__dirname, 'dist');
const publicPath = isProd ? './' : 'http://localhost:8080/';
const isProd = process.env.NODE_ENV === "production";
const chunkFilename = isProd ? "chunk.[chunkhash].js" : "[name].chunk.js";
const buildPath = path.resolve(__dirname, "dist");
const publicPath = isProd ? "./" : "http://localhost:8080/";
module.exports = {
mode: isProd ? 'production' : 'development',
mode: isProd ? "production" : "development",
// Disabled in prod while we make Home Assistant able to serve the right files.
// Was source-map
devtool: isProd ? 'none' : 'inline-source-map',
entry: './src/entrypoint.js',
devtool: isProd ? "none" : "inline-source-map",
entry: "./src/entrypoint.js",
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
plugins: [
// Only support the syntax, Webpack will handle it.
'syntax-dynamic-import',
[
'transform-react-jsx',
{
pragma: 'h'
}
],
],
},
},
},
babelLoaderConfig({ latestBuild: true }),
{
test: /\.(html)$/,
use: {
loader: 'html-loader',
loader: "html-loader",
options: {
exportAsEs6Default: true,
}
}
},
},
},
]
],
},
plugins: [
new CopyWebpackPlugin([
'public',
{ from: '../public', to: 'static' },
{ from: '../build-translations/output', to: 'static/translations' },
{ from: '../node_modules/leaflet/dist/leaflet.css', to: 'static/images/leaflet/' },
{ from: '../node_modules/@polymer/font-roboto-local/fonts', to: 'static/fonts' },
{ from: '../node_modules/leaflet/dist/images', to: 'static/images/leaflet/' },
"public",
{ from: "../public", to: "static" },
{ from: "../build-translations/output", to: "static/translations" },
{
from: "../node_modules/leaflet/dist/leaflet.css",
to: "static/images/leaflet/",
},
{
from: "../node_modules/@polymer/font-roboto-local/fonts",
to: "static/fonts",
},
{
from: "../node_modules/leaflet/dist/images",
to: "static/images/leaflet/",
},
]),
isProd && new UglifyJsPlugin({
extractComments: true,
sourceMap: true,
uglifyOptions: {
// Disabling because it broke output
mangle: false,
}
}),
isProd &&
new UglifyJsPlugin({
extractComments: true,
sourceMap: true,
uglifyOptions: {
// Disabling because it broke output
mangle: false,
},
}),
].filter(Boolean),
resolve: {
extensions: [".ts", ".js", ".json"],
},
output: {
filename: '[name].js',
filename: "[name].js",
chunkFilename: chunkFilename,
path: buildPath,
publicPath,
},
devServer: {
contentBase: './public',
}
contentBase: "./public",
},
};

View File

@@ -1,8 +1,8 @@
var path = require('path');
var path = require("path");
module.exports = {
polymer_dir: path.resolve(__dirname, '..'),
build_dir: path.resolve(__dirname, '../build'),
output: path.resolve(__dirname, '../hass_frontend'),
output_es5: path.resolve(__dirname, '../hass_frontend_es5'),
polymer_dir: path.resolve(__dirname, ".."),
build_dir: path.resolve(__dirname, "../build"),
output: path.resolve(__dirname, "../hass_frontend"),
output_es5: path.resolve(__dirname, "../hass_frontend_es5"),
};

View File

@@ -1,31 +1,34 @@
const gulp = require('gulp');
const path = require('path');
const fs = require('fs');
const config = require('../config');
const gulp = require("gulp");
const path = require("path");
const fs = require("fs");
const config = require("../config");
const ICON_PACKAGE_PATH = path.resolve(__dirname, '../../node_modules/@mdi/svg/');
const META_PATH = path.resolve(ICON_PACKAGE_PATH, 'meta.json');
const ICON_PATH = path.resolve(ICON_PACKAGE_PATH, 'svg');
const OUTPUT_DIR = path.resolve(__dirname, '../../build');
const MDI_OUTPUT_PATH = path.resolve(OUTPUT_DIR, 'mdi.html');
const HASS_OUTPUT_PATH = path.resolve(OUTPUT_DIR, 'hass-icons.html');
const ICON_PACKAGE_PATH = path.resolve(
__dirname,
"../../node_modules/@mdi/svg/"
);
const META_PATH = path.resolve(ICON_PACKAGE_PATH, "meta.json");
const ICON_PATH = path.resolve(ICON_PACKAGE_PATH, "svg");
const OUTPUT_DIR = path.resolve(__dirname, "../../build");
const MDI_OUTPUT_PATH = path.resolve(OUTPUT_DIR, "mdi.html");
const HASS_OUTPUT_PATH = path.resolve(OUTPUT_DIR, "hass-icons.html");
const BUILT_IN_PANEL_ICONS = [
'calendar', // Calendar
'settings', // Config
'home-assistant', // Hass.io
'poll-box', // History panel
'format-list-bulleted-type', // Logbook
'mailbox', // Mailbox
'account-location', // Map
'cart', // Shopping List
"calendar", // Calendar
"settings", // Config
"home-assistant", // Hass.io
"poll-box", // History panel
"format-list-bulleted-type", // Logbook
"mailbox", // Mailbox
"account-location", // Map
"cart", // Shopping List
];
// Given an icon name, load the SVG file
function loadIcon(name) {
const iconPath = path.resolve(ICON_PATH, `${name}.svg`);
try {
return fs.readFileSync(iconPath, 'utf-8');
return fs.readFileSync(iconPath, "utf-8");
} catch (err) {
return null;
}
@@ -33,7 +36,7 @@ function loadIcon(name) {
// Given an SVG file, convert it to an iron-iconset-svg definition
function transformXMLtoPolymer(name, xml) {
const start = xml.indexOf('><path') + 1;
const start = xml.indexOf("><path") + 1;
const end = xml.length - start - 6;
const path = xml.substr(start, end);
return `<g id="${name}">${path}</g>`;
@@ -41,22 +44,26 @@ function transformXMLtoPolymer(name, xml) {
// Given an iconset name and icon names, generate a polymer iconset
function generateIconset(name, iconNames) {
const iconDefs = iconNames.map(name => {
const iconDef = loadIcon(name);
if (!iconDef) {
throw new Error(`Unknown icon referenced: ${name}`);
}
return transformXMLtoPolymer(name, iconDef)
}).join('');
const iconDefs = iconNames
.map((name) => {
const iconDef = loadIcon(name);
if (!iconDef) {
throw new Error(`Unknown icon referenced: ${name}`);
}
return transformXMLtoPolymer(name, iconDef);
})
.join("");
return `<ha-iconset-svg name="${name}" size="24"><svg><defs>${iconDefs}</defs></svg></ha-iconset-svg>`;
}
// Generate the full MDI iconset
function genMDIIcons() {
const meta = JSON.parse(fs.readFileSync(path.resolve(ICON_PACKAGE_PATH, META_PATH), 'UTF-8'));
const iconNames = meta.map(iconInfo => iconInfo.name);
const meta = JSON.parse(
fs.readFileSync(path.resolve(ICON_PACKAGE_PATH, META_PATH), "UTF-8")
);
const iconNames = meta.map((iconInfo) => iconInfo.name);
fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR);
fs.writeFileSync(MDI_OUTPUT_PATH, generateIconset('mdi', iconNames));
fs.writeFileSync(MDI_OUTPUT_PATH, generateIconset("mdi", iconNames));
}
// Helper function to map recursively over files in a folder and it's subfolders
@@ -75,30 +82,31 @@ function mapFiles(startPath, filter, mapFunc) {
// Find all icons used by the project.
function findIcons(path, iconsetName) {
const iconRegex = new RegExp(`${iconsetName}:[\\w-]+`, 'g');
const iconRegex = new RegExp(`${iconsetName}:[\\w-]+`, "g");
const icons = new Set();
function processFile(filename) {
const content = fs.readFileSync(filename);
let match;
// eslint-disable-next-line
while (match = iconRegex.exec(content)) {
while ((match = iconRegex.exec(content))) {
// strip off "hass:" and add to set
icons.add(match[0].substr(iconsetName.length + 1));
}
}
mapFiles(path, '.js', processFile);
mapFiles(path, ".js", processFile);
mapFiles(path, ".ts", processFile);
return Array.from(icons);
}
function genHassIcons() {
const iconNames = findIcons('./src', 'hass').concat(BUILT_IN_PANEL_ICONS);
const iconNames = findIcons("./src", "hass").concat(BUILT_IN_PANEL_ICONS);
fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR);
fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset('hass', iconNames));
fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset("hass", iconNames));
}
gulp.task('gen-icons-mdi', () => genMDIIcons());
gulp.task('gen-icons-hass', () => genHassIcons());
gulp.task('gen-icons', ['gen-icons-hass', 'gen-icons-mdi'], () => {});
gulp.task("gen-icons-mdi", () => genMDIIcons());
gulp.task("gen-icons-hass", () => genHassIcons());
gulp.task("gen-icons", ["gen-icons-hass", "gen-icons-mdi"], () => {});
module.exports = {
findIcons,

View File

@@ -1,40 +1,44 @@
const path = require('path');
const gulp = require('gulp');
const foreach = require('gulp-foreach');
const hash = require('gulp-hash');
const insert = require('gulp-insert');
const merge = require('gulp-merge-json');
const minify = require('gulp-jsonminify');
const rename = require('gulp-rename');
const transform = require('gulp-json-transform');
const path = require("path");
const gulp = require("gulp");
const foreach = require("gulp-foreach");
const hash = require("gulp-hash");
const insert = require("gulp-insert");
const merge = require("gulp-merge-json");
const minify = require("gulp-jsonminify");
const rename = require("gulp-rename");
const transform = require("gulp-json-transform");
const inDir = 'translations';
const workDir = 'build-translations';
const fullDir = workDir + '/full';
const coreDir = workDir + '/core';
const outDir = workDir + '/output';
const inDir = "translations";
const workDir = "build-translations";
const fullDir = workDir + "/full";
const coreDir = workDir + "/core";
const outDir = workDir + "/output";
// Panel translations which should be split from the core translations. These
// should mirror the fragment definitions in polymer.json, so that we load
// additional resources at equivalent points.
const TRANSLATION_FRAGMENTS = [
'config',
'history',
'logbook',
'mailbox',
'profile',
'shopping-list',
'page-authorize',
'page-onboarding',
"config",
"history",
"logbook",
"mailbox",
"profile",
"shopping-list",
"page-authorize",
"page-onboarding",
];
const tasks = [];
function recursiveFlatten(prefix, data) {
let output = {};
Object.keys(data).forEach(function (key) {
if (typeof (data[key]) === 'object') {
output = Object.assign({}, output, recursiveFlatten(prefix + key + '.', data[key]));
Object.keys(data).forEach(function(key) {
if (typeof data[key] === "object") {
output = Object.assign(
{},
output,
recursiveFlatten(prefix + key + ".", data[key])
);
} else {
output[prefix + key] = data[key];
}
@@ -43,14 +47,14 @@ function recursiveFlatten(prefix, data) {
}
function flatten(data) {
return recursiveFlatten('', data);
return recursiveFlatten("", data);
}
function emptyFilter(data) {
const newData = {};
Object.keys(data).forEach((key) => {
if (data[key]) {
if (typeof (data[key]) === 'object') {
if (typeof data[key] === "object") {
newData[key] = emptyFilter(data[key]);
} else {
newData[key] = data[key];
@@ -70,16 +74,18 @@ function emptyFilter(data) {
* @link https://docs.lokalise.co/article/KO5SZWLLsy-key-referencing
*/
const re_key_reference = /\[%key:([^%]+)%\]/;
function lokalise_transform (data, original) {
function lokalise_transform(data, original) {
const output = {};
Object.entries(data).forEach(([key, value]) => {
if (value instanceof Object) {
output[key] = lokalise_transform(value, original);
} else {
output[key] = value.replace(re_key_reference, (match, key) => {
const replace = key.split('::').reduce((tr, k) => tr[k], original);
if (typeof replace !== 'string') {
throw Error(`Invalid key placeholder ${key} in src/translations/en.json`);
const replace = key.split("::").reduce((tr, k) => tr[k], original);
if (typeof replace !== "string") {
throw Error(
`Invalid key placeholder ${key} in src/translations/en.json`
);
}
return replace;
});
@@ -97,21 +103,24 @@ function lokalise_transform (data, original) {
* project is buildable immediately after merging new translation keys, since
* the Lokalise update to translations/en.json will not happen immediately.
*/
let taskName = 'build-master-translation';
gulp.task(taskName, function () {
return gulp.src('src/translations/en.json')
.pipe(transform(function(data, file) {
return lokalise_transform(data, data);
}))
.pipe(rename('translationMaster.json'))
let taskName = "build-master-translation";
gulp.task(taskName, function() {
return gulp
.src("src/translations/en.json")
.pipe(
transform(function(data, file) {
return lokalise_transform(data, data);
})
)
.pipe(rename("translationMaster.json"))
.pipe(gulp.dest(workDir));
});
tasks.push(taskName);
taskName = 'build-merged-translations';
gulp.task(taskName, ['build-master-translation'], function () {
return gulp.src(inDir + '/*.json')
.pipe(foreach(function(stream, file) {
taskName = "build-merged-translations";
gulp.task(taskName, ["build-master-translation"], function() {
return gulp.src(inDir + "/*.json").pipe(
foreach(function(stream, file) {
// For each language generate a merged json file. It begins with the master
// translation as a failsafe for untranslated strings, and merges all parent
// tags into one file for each specific subtag
@@ -119,139 +128,169 @@ gulp.task(taskName, ['build-master-translation'], function () {
// TODO: This is a naive interpretation of BCP47 that should be improved.
// Will be OK for now as long as we don't have anything more complicated
// than a base translation + region.
const tr = path.basename(file.history[0], '.json');
const subtags = tr.split('-');
const src = [workDir + '/translationMaster.json'];
const tr = path.basename(file.history[0], ".json");
const subtags = tr.split("-");
const src = [workDir + "/translationMaster.json"];
for (let i = 1; i <= subtags.length; i++) {
const lang = subtags.slice(0, i).join('-');
src.push(inDir + '/' + lang + '.json');
const lang = subtags.slice(0, i).join("-");
src.push(inDir + "/" + lang + ".json");
}
return gulp.src(src)
.pipe(transform(data => emptyFilter(data)))
.pipe(merge({
fileName: tr + '.json',
}))
return gulp
.src(src)
.pipe(transform((data) => emptyFilter(data)))
.pipe(
merge({
fileName: tr + ".json",
})
)
.pipe(gulp.dest(fullDir));
}));
})
);
});
tasks.push(taskName);
const splitTasks = [];
TRANSLATION_FRAGMENTS.forEach((fragment) => {
taskName = 'build-translation-fragment-' + fragment;
gulp.task(taskName, ['build-merged-translations'], function () {
taskName = "build-translation-fragment-" + fragment;
gulp.task(taskName, ["build-merged-translations"], function() {
// Return only the translations for this fragment.
return gulp.src(fullDir + '/*.json')
.pipe(transform(data => ({
ui: {
panel: {
[fragment]: data.ui.panel[fragment],
return gulp
.src(fullDir + "/*.json")
.pipe(
transform((data) => ({
ui: {
panel: {
[fragment]: data.ui.panel[fragment],
},
},
},
})))
.pipe(gulp.dest(workDir + '/' + fragment));
}))
)
.pipe(gulp.dest(workDir + "/" + fragment));
});
tasks.push(taskName);
splitTasks.push(taskName);
});
taskName = 'build-translation-core';
gulp.task(taskName, ['build-merged-translations'], function () {
taskName = "build-translation-core";
gulp.task(taskName, ["build-merged-translations"], function() {
// Remove the fragment translations from the core translation.
return gulp.src(fullDir + '/*.json')
.pipe(transform((data) => {
TRANSLATION_FRAGMENTS.forEach((fragment) => {
delete data.ui.panel[fragment];
});
return data;
}))
return gulp
.src(fullDir + "/*.json")
.pipe(
transform((data) => {
TRANSLATION_FRAGMENTS.forEach((fragment) => {
delete data.ui.panel[fragment];
});
return data;
})
)
.pipe(gulp.dest(coreDir));
});
tasks.push(taskName);
splitTasks.push(taskName);
taskName = 'build-flattened-translations';
gulp.task(taskName, splitTasks, function () {
taskName = "build-flattened-translations";
gulp.task(taskName, splitTasks, function() {
// Flatten the split versions of our translations, and move them into outDir
return gulp.src(
TRANSLATION_FRAGMENTS.map(fragment => workDir + '/' + fragment + '/*.json')
.concat(coreDir + '/*.json'),
{ base: workDir },
)
.pipe(transform(function (data) {
// Polymer.AppLocalizeBehavior requires flattened json
return flatten(data);
}))
return gulp
.src(
TRANSLATION_FRAGMENTS.map(
(fragment) => workDir + "/" + fragment + "/*.json"
).concat(coreDir + "/*.json"),
{ base: workDir }
)
.pipe(
transform(function(data) {
// Polymer.AppLocalizeBehavior requires flattened json
return flatten(data);
})
)
.pipe(minify())
.pipe(rename((filePath) => {
if (filePath.dirname === 'core') {
filePath.dirname = '';
}
}))
.pipe(
rename((filePath) => {
if (filePath.dirname === "core") {
filePath.dirname = "";
}
})
)
.pipe(gulp.dest(outDir));
});
tasks.push(taskName);
taskName = 'build-translation-fingerprints';
gulp.task(taskName, ['build-flattened-translations'], function () {
return gulp.src(outDir + '/**/*.json')
.pipe(rename({
extname: '',
}))
.pipe(hash({
algorithm: 'md5',
hashLength: 32,
template: '<%= name %>-<%= hash %>.json',
}))
.pipe(hash.manifest('translationFingerprints.json'))
.pipe(transform(function (data) {
// After generating fingerprints of our translation files, consolidate
// all translation fragment fingerprints under the translation name key
const newData = {};
Object.entries(data).forEach(([key, value]) => {
const parts = key.split('/');
let translation = key;
if (parts.length === 2) {
translation = parts[1];
}
if (!(translation in newData)) {
newData[translation] = {
fingerprints: {},
};
}
newData[translation].fingerprints[key] = value;
});
return newData;
}))
taskName = "build-translation-fingerprints";
gulp.task(taskName, ["build-flattened-translations"], function() {
return gulp
.src(outDir + "/**/*.json")
.pipe(
rename({
extname: "",
})
)
.pipe(
hash({
algorithm: "md5",
hashLength: 32,
template: "<%= name %>-<%= hash %>.json",
})
)
.pipe(hash.manifest("translationFingerprints.json"))
.pipe(
transform(function(data) {
// After generating fingerprints of our translation files, consolidate
// all translation fragment fingerprints under the translation name key
const newData = {};
Object.entries(data).forEach(([key, value]) => {
const parts = key.split("/");
let translation = key;
if (parts.length === 2) {
translation = parts[1];
}
if (!(translation in newData)) {
newData[translation] = {
fingerprints: {},
};
}
newData[translation].fingerprints[key] = value;
});
return newData;
})
)
.pipe(gulp.dest(workDir));
});
tasks.push(taskName);
taskName = 'build-translations';
gulp.task(taskName, ['build-translation-fingerprints'], function () {
return gulp.src([
'src/translations/translationMetadata.json',
workDir + '/translationFingerprints.json',
])
taskName = "build-translations";
gulp.task(taskName, ["build-translation-fingerprints"], function() {
return gulp
.src([
"src/translations/translationMetadata.json",
workDir + "/translationFingerprints.json",
])
.pipe(merge({}))
.pipe(transform(function (data) {
const newData = {};
Object.entries(data).forEach(([key, value]) => {
// Filter out translations without native name.
if (data[key].nativeName) {
newData[key] = data[key];
} else {
console.warn(`Skipping language ${key}. Native name was not translated.`);
}
if (data[key]) newData[key] = value;
});
return newData;
}))
.pipe(transform(data => ({
fragments: TRANSLATION_FRAGMENTS,
translations: data,
})))
.pipe(rename('translationMetadata.json'))
.pipe(
transform(function(data) {
const newData = {};
Object.entries(data).forEach(([key, value]) => {
// Filter out translations without native name.
if (data[key].nativeName) {
newData[key] = data[key];
} else {
console.warn(
`Skipping language ${key}. Native name was not translated.`
);
}
if (data[key]) newData[key] = value;
});
return newData;
})
)
.pipe(
transform((data) => ({
fragments: TRANSLATION_FRAGMENTS,
translations: data,
}))
)
.pipe(rename("translationMetadata.json"))
.pipe(gulp.dest(workDir));
});
tasks.push(taskName);

View File

@@ -1,8 +1,8 @@
const path = require('path');
const path = require("path");
module.exports = {
// Target directory for the build.
buildDir: path.resolve(__dirname, 'build'),
buildDir: path.resolve(__dirname, "build"),
// Path where the Hass.io frontend will be publicly available.
publicPath: '/api/hassio/app',
}
publicPath: "/api/hassio/app",
};

View File

@@ -1,15 +1,12 @@
#!/usr/bin/env node
const fs = require('fs');
const {
findIcons,
generateIconset,
} = require('../../gulp/tasks/gen-icons.js');
const fs = require("fs");
const { findIcons, generateIconset } = require("../../gulp/tasks/gen-icons.js");
const MENU_BUTTON_ICON = 'menu';
const MENU_BUTTON_ICON = "menu";
function genHassioIcons() {
const iconNames = findIcons('./src', 'hassio').concat(MENU_BUTTON_ICON);
fs.writeFileSync('./hassio-icons.html', generateIconset('hassio', iconNames));
const iconNames = findIcons("./src", "hassio").concat(MENU_BUTTON_ICON);
fs.writeFileSync("./hassio-icons.html", generateIconset("hassio", iconNames));
}
genHassioIcons();

View File

@@ -1,10 +1,10 @@
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-card/paper-card.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/hassio-card-content.js';
import '../resources/hassio-style.js';
import NavigateMixin from '../../../src/mixins/navigate-mixin.js';
import "../components/hassio-card-content.js";
import "../resources/hassio-style.js";
import NavigateMixin from "../../../src/mixins/navigate-mixin.js";
class HassioAddonRepository extends NavigateMixin(PolymerElement) {
static get template() {
@@ -48,21 +48,27 @@ class HassioAddonRepository extends NavigateMixin(PolymerElement) {
}
sortAddons(a, b) {
return a.name < b.name ? -1 : 1;
return a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1;
}
computeIcon(addon) {
return addon.installed && addon.installed !== addon.version ? 'hassio:arrow-up-bold-circle' : 'hassio:puzzle';
return addon.installed && addon.installed !== addon.version
? "hassio:arrow-up-bold-circle"
: "hassio:puzzle";
}
computeIconTitle(addon) {
if (addon.installed) return addon.installed !== addon.version ? 'New version available' : 'Add-on is installed';
return 'Add-on is not installed';
if (addon.installed)
return addon.installed !== addon.version
? "New version available"
: "Add-on is installed";
return "Add-on is not installed";
}
computeIconClass(addon) {
if (addon.installed) return addon.installed !== addon.version ? 'update' : 'installed';
return '';
if (addon.installed)
return addon.installed !== addon.version ? "update" : "installed";
return "";
}
addonTapped(ev) {
@@ -70,4 +76,4 @@ class HassioAddonRepository extends NavigateMixin(PolymerElement) {
}
}
customElements.define('hassio-addon-repository', HassioAddonRepository);
customElements.define("hassio-addon-repository", HassioAddonRepository);

View File

@@ -1,8 +1,8 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import './hassio-addon-repository.js';
import './hassio-repositories-editor.js';
import "./hassio-addon-repository.js";
import "./hassio-repositories-editor.js";
class HassioAddonStore extends PolymerElement {
static get template() {
@@ -30,7 +30,7 @@ class HassioAddonStore extends PolymerElement {
ready() {
super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
this.loadData();
}
@@ -41,42 +41,45 @@ class HassioAddonStore extends PolymerElement {
}
sortRepos(a, b) {
if (a.slug === 'local') {
if (a.slug === "local") {
return -1;
} if (b.slug === 'local') {
return 1;
} if (a.slug === 'core') {
return -1;
} if (b.slug === 'core') {
}
if (b.slug === "local") {
return 1;
}
return a.name < b.name ? -1 : 1;
if (a.slug === "core") {
return -1;
}
if (b.slug === "core") {
return 1;
}
return a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1;
}
computeAddons(repo) {
return this.addons.filter(function (addon) {
return this.addons.filter(function(addon) {
return addon.repository === repo;
});
}
loadData() {
this.hass.callApi('get', 'hassio/addons')
.then((info) => {
this.hass.callApi("get", "hassio/addons").then(
(info) => {
this.addons = info.data.addons;
this.repos = info.data.repositories;
}, () => {
},
() => {
this.addons = [];
this.repos = [];
});
}
);
}
refreshData() {
this.hass.callApi('post', 'hassio/addons/reload')
.then(() => {
this.loadData();
});
this.hass.callApi("post", "hassio/addons/reload").then(() => {
this.loadData();
});
}
}
customElements.define('hassio-addon-store', HassioAddonStore);
customElements.define("hassio-addon-store", HassioAddonStore);

View File

@@ -1,12 +1,12 @@
import '@polymer/iron-icon/iron-icon.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-input/paper-input.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/iron-icon/iron-icon.js";
import "@polymer/paper-card/paper-card.js";
import "@polymer/paper-input/paper-input.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js';
import '../components/hassio-card-content.js';
import '../resources/hassio-style.js';
import "../../../src/components/buttons/ha-call-api-button.js";
import "../components/hassio-card-content.js";
import "../resources/hassio-style.js";
class HassioRepositoriesEditor extends PolymerElement {
static get template() {
@@ -60,7 +60,7 @@ class HassioRepositoriesEditor extends PolymerElement {
hass: Object,
repos: {
type: Array,
observer: 'reposChanged',
observer: "reposChanged",
},
repoList: Array,
repoUrl: String,
@@ -68,8 +68,10 @@ class HassioRepositoriesEditor extends PolymerElement {
}
reposChanged(repos) {
this.repoList = repos.filter(repo => repo.slug !== 'core' && repo.slug !== 'local');
this.repoUrl = '';
this.repoList = repos.filter(
(repo) => repo.slug !== "core" && repo.slug !== "local"
);
this.repoUrl = "";
}
sortRepos(a, b) {
@@ -77,15 +79,17 @@ class HassioRepositoriesEditor extends PolymerElement {
}
computeRemoveRepoData(repoList, url) {
const list = repoList.filter(repo => repo.url !== url).map(repo => repo.url);
const list = repoList
.filter((repo) => repo.url !== url)
.map((repo) => repo.url);
return { addons_repositories: list };
}
computeAddRepoData(repoList, url) {
const list = repoList ? repoList.map(repo => repo.url) : [];
const list = repoList ? repoList.map((repo) => repo.url) : [];
list.push(url);
return { addons_repositories: list };
}
}
customElements.define('hassio-repositories-editor', HassioRepositoriesEditor);
customElements.define("hassio-repositories-editor", HassioRepositoriesEditor);

View File

@@ -1,15 +1,15 @@
import 'web-animations-js/web-animations-next-lite.min.js';
import "web-animations-js/web-animations-next-lite.min.js";
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
import '@polymer/paper-item/paper-item.js';
import '@polymer/paper-listbox/paper-listbox.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-button/paper-button.js";
import "@polymer/paper-card/paper-card.js";
import "@polymer/paper-dropdown-menu/paper-dropdown-menu.js";
import "@polymer/paper-item/paper-item.js";
import "@polymer/paper-listbox/paper-listbox.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/resources/ha-style.js';
import EventsMixin from '../../../src/mixins/events-mixin.js';
import "../../../src/resources/ha-style.js";
import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioAddonAudio extends EventsMixin(PolymerElement) {
static get template() {
@@ -64,7 +64,7 @@ class HassioAddonAudio extends EventsMixin(PolymerElement) {
hass: Object,
addon: {
type: Object,
observer: 'addonChanged'
observer: "addonChanged",
},
inputDevices: Array,
outputDevices: Array,
@@ -76,40 +76,55 @@ class HassioAddonAudio extends EventsMixin(PolymerElement) {
addonChanged(addon) {
this.setProperties({
selectedInput: addon.audio_input || 'null',
selectedOutput: addon.audio_output || 'null'
selectedInput: addon.audio_input || "null",
selectedOutput: addon.audio_output || "null",
});
if (this.outputDevices) return;
const noDevice = [{ device: 'null', name: '-' }];
this.hass.callApi('get', 'hassio/hardware/audio').then((resp) => {
const dev = resp.data.audio;
const input = Object.keys(dev.input).map(key => ({ device: key, name: dev.input[key] }));
const output = Object.keys(dev.output).map(key => ({ device: key, name: dev.output[key] }));
this.setProperties({
inputDevices: noDevice.concat(input),
outputDevices: noDevice.concat(output)
});
}, () => {
this.setProperties({
inputDevices: noDevice,
outputDevices: noDevice
});
});
const noDevice = [{ device: "null", name: "-" }];
this.hass.callApi("get", "hassio/hardware/audio").then(
(resp) => {
const dev = resp.data.audio;
const input = Object.keys(dev.input).map((key) => ({
device: key,
name: dev.input[key],
}));
const output = Object.keys(dev.output).map((key) => ({
device: key,
name: dev.output[key],
}));
this.setProperties({
inputDevices: noDevice.concat(input),
outputDevices: noDevice.concat(output),
});
},
() => {
this.setProperties({
inputDevices: noDevice,
outputDevices: noDevice,
});
}
);
}
_saveSettings() {
this.error = null;
const path = `hassio/addons/${this.addon.slug}/options`;
this.hass.callApi('post', path, {
audio_input: this.selectedInput === 'null' ? null : this.selectedInput,
audio_output: this.selectedOutput === 'null' ? null : this.selectedOutput
}).then(() => {
this.fire('hass-api-called', { success: true, path: path });
}, (resp) => {
this.error = resp.body.message;
});
this.hass
.callApi("post", path, {
audio_input: this.selectedInput === "null" ? null : this.selectedInput,
audio_output:
this.selectedOutput === "null" ? null : this.selectedOutput,
})
.then(
() => {
this.fire("hass-api-called", { success: true, path: path });
},
(resp) => {
this.error = resp.body.message;
}
);
}
}
customElements.define('hassio-addon-audio', HassioAddonAudio);
customElements.define("hassio-addon-audio", HassioAddonAudio);

View File

@@ -1,10 +1,10 @@
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js";
import "@polymer/paper-button/paper-button.js";
import "@polymer/paper-card/paper-card.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js';
import "../../../src/components/buttons/ha-call-api-button.js";
class HassioAddonConfig extends PolymerElement {
static get template() {
@@ -52,12 +52,12 @@ class HassioAddonConfig extends PolymerElement {
hass: Object,
addon: {
type: Object,
observer: 'addonChanged',
observer: "addonChanged",
},
addonSlug: String,
config: {
type: String,
observer: 'configChanged',
observer: "configChanged",
},
configParsed: Object,
error: String,
@@ -71,15 +71,15 @@ class HassioAddonConfig extends PolymerElement {
}
addonChanged(addon) {
this.config = addon ? JSON.stringify(addon.options, null, 2) : '';
this.config = addon ? JSON.stringify(addon.options, null, 2) : "";
}
configChanged(config) {
try {
this.$.config.classList.remove('syntaxerror');
this.$.config.classList.remove("syntaxerror");
this.configParsed = JSON.parse(config);
} catch (err) {
this.$.config.classList.add('syntaxerror');
this.$.config.classList.add("syntaxerror");
this.configParsed = null;
}
}
@@ -87,12 +87,14 @@ class HassioAddonConfig extends PolymerElement {
saveTapped() {
this.error = null;
this.hass.callApi('post', `hassio/addons/${this.addonSlug}/options`, {
options: this.configParsed
}).catch((resp) => {
this.error = resp.body.message;
});
this.hass
.callApi("post", `hassio/addons/${this.addonSlug}/options`, {
options: this.configParsed,
})
.catch((resp) => {
this.error = resp.body.message;
});
}
}
customElements.define('hassio-addon-config', HassioAddonConfig);
customElements.define("hassio-addon-config", HassioAddonConfig);

View File

@@ -1,16 +1,16 @@
import '@polymer/iron-icon/iron-icon.js';
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-toggle-button/paper-toggle-button.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/iron-icon/iron-icon.js";
import "@polymer/paper-button/paper-button.js";
import "@polymer/paper-card/paper-card.js";
import "@polymer/paper-toggle-button/paper-toggle-button.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js';
import '../../../src/components/ha-markdown.js';
import '../../../src/resources/ha-style.js';
import EventsMixin from '../../../src/mixins/events-mixin.js';
import "../../../src/components/buttons/ha-call-api-button.js";
import "../../../src/components/ha-markdown.js";
import "../../../src/resources/ha-style.js";
import EventsMixin from "../../../src/mixins/events-mixin.js";
import '../components/hassio-card-content.js';
import "../components/hassio-card-content.js";
class HassioAddonInfo extends EventsMixin(PolymerElement) {
static get template() {
@@ -157,21 +157,26 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) {
addonSlug: String,
isRunning: {
type: Boolean,
computed: 'computeIsRunning(addon)',
computed: "computeIsRunning(addon)",
},
};
}
computeIsRunning(addon) {
return addon && addon.state === 'started';
return addon && addon.state === "started";
}
computeUpdateAvailable(addon) {
return addon && !addon.detached && addon.version && addon.version !== addon.last_version;
return (
addon &&
!addon.detached &&
addon.version &&
addon.version !== addon.last_version
);
}
pathWebui(webui) {
return webui && webui.replace('[HOST]', document.location.hostname);
return webui && webui.replace("[HOST]", document.location.hostname);
}
computeShowWebUI(webui, isRunning) {
@@ -179,49 +184,54 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) {
}
computeStartOnBoot(state) {
return state === 'auto';
return state === "auto";
}
startOnBootToggled() {
const data = { boot: this.addon.boot === 'auto' ? 'manual' : 'auto' };
this.hass.callApi('POST', `hassio/addons/${this.addonSlug}/options`, data);
const data = { boot: this.addon.boot === "auto" ? "manual" : "auto" };
this.hass.callApi("POST", `hassio/addons/${this.addonSlug}/options`, data);
}
autoUpdateToggled() {
const data = { auto_update: !this.addon.auto_update };
this.hass.callApi('POST', `hassio/addons/${this.addonSlug}/options`, data);
this.hass.callApi("POST", `hassio/addons/${this.addonSlug}/options`, data);
}
openChangelog() {
this.hass.callApi('get', `hassio/addons/${this.addonSlug}/changelog`)
.then(
resp => resp,
() => 'Error getting changelog'
).then((content) => {
this.fire('hassio-markdown-dialog', {
title: 'Changelog',
this.hass
.callApi("get", `hassio/addons/${this.addonSlug}/changelog`)
.then((resp) => resp, () => "Error getting changelog")
.then((content) => {
this.fire("hassio-markdown-dialog", {
title: "Changelog",
content: content,
});
});
}
_unistallClicked() {
if (!confirm('Are you sure you want to uninstall this add-on?')) {
if (!confirm("Are you sure you want to uninstall this add-on?")) {
return;
}
const path = `hassio/addons/${this.addonSlug}/uninstall`;
const eventData = {
path: path,
};
this.hass.callApi('post', path).then((resp) => {
eventData.success = true;
eventData.response = resp;
}, (resp) => {
eventData.success = false;
eventData.response = resp;
}).then(() => {
this.fire('hass-api-called', eventData);
});
this.hass
.callApi("post", path)
.then(
(resp) => {
eventData.success = true;
eventData.response = resp;
},
(resp) => {
eventData.success = false;
eventData.response = resp;
}
)
.then(() => {
this.fire("hass-api-called", eventData);
});
}
}
customElements.define('hassio-addon-info', HassioAddonInfo);
customElements.define("hassio-addon-info", HassioAddonInfo);

View File

@@ -1,9 +1,9 @@
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-button/paper-button.js";
import "@polymer/paper-card/paper-card.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/resources/ha-style.js';
import "../../../src/resources/ha-style.js";
class HassioAddonLogs extends PolymerElement {
static get template() {
@@ -33,7 +33,7 @@ class HassioAddonLogs extends PolymerElement {
hass: Object,
addonSlug: {
type: String,
observer: 'addonSlugChanged',
observer: "addonSlugChanged",
},
log: String,
};
@@ -41,7 +41,9 @@ class HassioAddonLogs extends PolymerElement {
addonSlugChanged(slug) {
if (!this.hass) {
setTimeout(() => { this.addonChanged(slug); }, 0);
setTimeout(() => {
this.addonChanged(slug);
}, 0);
return;
}
@@ -49,11 +51,12 @@ class HassioAddonLogs extends PolymerElement {
}
refresh() {
this.hass.callApi('get', `hassio/addons/${this.addonSlug}/logs`)
this.hass
.callApi("get", `hassio/addons/${this.addonSlug}/logs`)
.then((info) => {
this.log = info;
});
}
}
customElements.define('hassio-addon-logs', HassioAddonLogs);
customElements.define("hassio-addon-logs", HassioAddonLogs);

View File

@@ -1,11 +1,11 @@
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-input/paper-input.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-card/paper-card.js";
import "@polymer/paper-input/paper-input.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js';
import '../../../src/resources/ha-style.js';
import EventsMixin from '../../../src/mixins/events-mixin.js';
import "../../../src/components/buttons/ha-call-api-button.js";
import "../../../src/resources/ha-style.js";
import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioAddonNetwork extends EventsMixin(PolymerElement) {
static get template() {
@@ -64,7 +64,7 @@ class HassioAddonNetwork extends EventsMixin(PolymerElement) {
config: Object,
addon: {
type: Object,
observer: 'addonChanged',
observer: "addonChanged",
},
error: String,
resetData: {
@@ -80,29 +80,36 @@ class HassioAddonNetwork extends EventsMixin(PolymerElement) {
if (!addon) return;
const network = addon.network || {};
const items = Object.keys(network).map(key => ({
const items = Object.keys(network).map((key) => ({
container: key,
host: network[key]
host: network[key],
}));
this.config = items.sort(function (el1, el2) { return el1.host - el2.host; });
this.config = items.sort(function(el1, el2) {
return el1.host - el2.host;
});
}
saveTapped() {
this.error = null;
const data = {};
this.config.forEach(function (item) {
this.config.forEach(function(item) {
data[item.container] = parseInt(item.host);
});
const path = `hassio/addons/${this.addonSlug}/options`;
this.hass.callApi('post', path, {
network: data
}).then(() => {
this.fire('hass-api-called', { success: true, path: path });
}, (resp) => {
this.error = resp.body.message;
});
this.hass
.callApi("post", path, {
network: data,
})
.then(
() => {
this.fire("hass-api-called", { success: true, path: path });
},
(resp) => {
this.error = resp.body.message;
}
);
}
}
customElements.define('hassio-addon-network', HassioAddonNetwork);
customElements.define("hassio-addon-network", HassioAddonNetwork);

View File

@@ -1,19 +1,19 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js';
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/app-route/app-route.js';
import '@polymer/paper-icon-button/paper-icon-button.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/app-layout/app-header-layout/app-header-layout.js";
import "@polymer/app-layout/app-header/app-header.js";
import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import "@polymer/app-route/app-route.js";
import "@polymer/paper-icon-button/paper-icon-button.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/ha-menu-button.js';
import '../../../src/resources/ha-style.js';
import '../hassio-markdown-dialog.js';
import './hassio-addon-audio.js';
import './hassio-addon-config.js';
import './hassio-addon-info.js';
import './hassio-addon-logs.js';
import './hassio-addon-network.js';
import "../../../src/components/ha-menu-button.js";
import "../../../src/resources/ha-style.js";
import "../hassio-markdown-dialog.js";
import "./hassio-addon-audio.js";
import "./hassio-addon-config.js";
import "./hassio-addon-info.js";
import "./hassio-addon-logs.js";
import "./hassio-addon-network.js";
class HassioAddonView extends PolymerElement {
static get template() {
@@ -91,7 +91,7 @@ class HassioAddonView extends PolymerElement {
route: Object,
routeData: {
type: Object,
observer: 'routeDataChanged',
observer: "routeDataChanged",
},
routeMatches: Boolean,
addon: Object,
@@ -99,15 +99,17 @@ class HassioAddonView extends PolymerElement {
markdownTitle: String,
markdownContent: {
type: String,
value: '',
value: "",
},
};
}
ready() {
super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
this.addEventListener('hassio-markdown-dialog', ev => this.openMarkdown(ev));
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
this.addEventListener("hassio-markdown-dialog", (ev) =>
this.openMarkdown(ev)
);
}
apiCalled(ev) {
@@ -115,7 +117,7 @@ class HassioAddonView extends PolymerElement {
if (!path) return;
if (path.substr(path.lastIndexOf('/') + 1) === 'uninstall') {
if (path.substr(path.lastIndexOf("/") + 1) === "uninstall") {
this.backTapped();
} else {
this.routeDataChanged(this.routeData);
@@ -124,12 +126,14 @@ class HassioAddonView extends PolymerElement {
routeDataChanged(routeData) {
if (!this.routeMatches || !routeData || !routeData.slug) return;
this.hass.callApi('get', `hassio/addons/${routeData.slug}/info`)
.then((info) => {
this.hass.callApi("get", `hassio/addons/${routeData.slug}/info`).then(
(info) => {
this.addon = info.data;
}, () => {
},
() => {
this.addon = null;
});
}
);
}
backTapped() {
@@ -141,8 +145,8 @@ class HassioAddonView extends PolymerElement {
markdownTitle: ev.detail.title,
markdownContent: ev.detail.content,
});
this.shadowRoot.querySelector('hassio-markdown-dialog').openDialog();
this.shadowRoot.querySelector("hassio-markdown-dialog").openDialog();
}
}
customElements.define('hassio-addon-view', HassioAddonView);
customElements.define("hassio-addon-view", HassioAddonView);

View File

@@ -1,8 +1,8 @@
import '@polymer/iron-icon/iron-icon.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/iron-icon/iron-icon.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/ha-relative-time.js';
import "../../../src/components/ha-relative-time.js";
class HassioCardContent extends PolymerElement {
static get template() {
@@ -65,11 +65,11 @@ class HassioCardContent extends PolymerElement {
datetime: String,
icon: {
type: String,
value: 'hass:help-circle'
value: "hass:help-circle",
},
iconTitle: String,
iconClass: String,
};
}
}
customElements.define('hassio-card-content', HassioCardContent);
customElements.define("hassio-card-content", HassioCardContent);

View File

@@ -1,10 +1,10 @@
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-card/paper-card.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/hassio-card-content.js';
import '../resources/hassio-style.js';
import NavigateMixin from '../../../src/mixins/navigate-mixin.js';
import "../components/hassio-card-content.js";
import "../resources/hassio-style.js";
import NavigateMixin from "../../../src/mixins/navigate-mixin.js";
class HassioAddons extends NavigateMixin(PolymerElement) {
static get template() {
@@ -46,28 +46,32 @@ class HassioAddons extends NavigateMixin(PolymerElement) {
}
computeIcon(addon) {
return addon.installed !== addon.version ? 'hassio:arrow-up-bold-circle' : 'hassio:puzzle';
return addon.installed !== addon.version
? "hassio:arrow-up-bold-circle"
: "hassio:puzzle";
}
computeIconTitle(addon) {
if (addon.installed !== addon.version) return 'New version available';
return addon.state === 'started' ? 'Add-on is running' : 'Add-on is stopped';
if (addon.installed !== addon.version) return "New version available";
return addon.state === "started"
? "Add-on is running"
: "Add-on is stopped";
}
computeIconClass(addon) {
if (addon.installed !== addon.version) return 'update';
return addon.state === 'started' ? 'running' : '';
if (addon.installed !== addon.version) return "update";
return addon.state === "started" ? "running" : "";
}
addonTapped(ev) {
this.navigate('/hassio/addon/' + ev.model.addon.slug);
this.navigate("/hassio/addon/" + ev.model.addon.slug);
ev.target.blur();
}
openStore(ev) {
this.navigate('/hassio/store');
this.navigate("/hassio/store");
ev.target.blur();
}
}
customElements.define('hassio-addons', HassioAddons);
customElements.define("hassio-addons", HassioAddons);

View File

@@ -1,9 +1,9 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import './hassio-addons.js';
import './hassio-hass-update.js';
import EventsMixin from '../../../src/mixins/events-mixin.js';
import "./hassio-addons.js";
import "./hassio-hass-update.js";
import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioDashboard extends EventsMixin(PolymerElement) {
static get template() {
@@ -29,4 +29,4 @@ class HassioDashboard extends EventsMixin(PolymerElement) {
}
}
customElements.define('hassio-dashboard', HassioDashboard);
customElements.define("hassio-dashboard", HassioDashboard);

View File

@@ -1,11 +1,11 @@
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-button/paper-button.js";
import "@polymer/paper-card/paper-card.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js';
import '../components/hassio-card-content.js';
import '../resources/hassio-style.js';
import "../../../src/components/buttons/ha-call-api-button.js";
import "../components/hassio-card-content.js";
import "../resources/hassio-style.js";
class HassioHassUpdate extends PolymerElement {
static get template() {
@@ -19,6 +19,9 @@ class HassioHassUpdate extends PolymerElement {
color: var(--google-red-500);
margin-top: 16px;
}
a {
color: var(--primary-color);
}
</style>
<template is="dom-if" if="[[computeUpdateAvailable(hassInfo)]]">
<div class="content">
@@ -30,6 +33,7 @@ class HassioHassUpdate extends PolymerElement {
<template is="dom-if" if="[[error]]">
<div class="error">Error: [[error]]</div>
</template>
<p><a href='https://www.home-assistant.io/latest-release-notes/' target='_blank'>Read the release notes</a></p>
</div>
<div class="card-actions">
<ha-call-api-button hass="[[hass]]" path="hassio/homeassistant/update">Update</ha-call-api-button>
@@ -52,7 +56,7 @@ class HassioHassUpdate extends PolymerElement {
ready() {
super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
}
apiCalled(ev) {
@@ -63,8 +67,8 @@ class HassioHassUpdate extends PolymerElement {
const response = ev.detail.response;
if (typeof response.body === 'object') {
this.errors = response.body.message || 'Unknown error';
if (typeof response.body === "object") {
this.errors = response.body.message || "Unknown error";
} else {
this.errors = response.body;
}
@@ -75,4 +79,4 @@ class HassioHassUpdate extends PolymerElement {
}
}
customElements.define('hassio-hass-update', HassioHassUpdate);
customElements.define("hassio-hass-update", HassioHassUpdate);

View File

@@ -1,4 +1,4 @@
window.loadES5Adapter().then(() => {
import(/* webpackChunkName: "hassio-icons" */ './resources/hassio-icons.js');
import(/* webpackChunkName: "hassio-main" */ './hassio-main.js');
import(/* webpackChunkName: "hassio-icons" */ "./resources/hassio-icons.js");
import(/* webpackChunkName: "hassio-main" */ "./hassio-main.js");
});

View File

@@ -1,8 +1,8 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import './hassio-main.js';
import './resources/hassio-icons.js';
import "./hassio-main.js";
import "./resources/hassio-icons.js";
class HassioApp extends PolymerElement {
static get template() {
@@ -29,13 +29,13 @@ class HassioApp extends PolymerElement {
ready() {
super.ready();
window.setProperties = this.setProperties.bind(this);
this.addEventListener('location-changed', () => this._locationChanged());
this.addEventListener('hass-open-menu', () => this._menuEvent(true));
this.addEventListener('hass-close-menu', () => this._menuEvent(false));
this.addEventListener("location-changed", () => this._locationChanged());
this.addEventListener("hass-open-menu", () => this._menuEvent(true));
this.addEventListener("hass-close-menu", () => this._menuEvent(false));
}
_menuEvent(shouldOpen) {
this.hassioPanel.fire(shouldOpen ? 'hass-open-menu' : 'hass-close-menu');
this.hassioPanel.fire(shouldOpen ? "hass-open-menu" : "hass-close-menu");
}
_locationChanged() {
@@ -43,4 +43,4 @@ class HassioApp extends PolymerElement {
}
}
customElements.define('hassio-app', HassioApp);
customElements.define("hassio-app", HassioApp);

View File

@@ -1,4 +1,4 @@
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
class HassioData extends PolymerElement {
static get properties() {
@@ -36,25 +36,24 @@ class HassioData extends PolymerElement {
}
fetchSupervisorInfo() {
return this.hass.callApi('get', 'hassio/supervisor/info')
.then((info) => {
this.supervisor = info.data;
});
return this.hass.callApi("get", "hassio/supervisor/info").then((info) => {
this.supervisor = info.data;
});
}
fetchHostInfo() {
return this.hass.callApi('get', 'hassio/host/info')
.then((info) => {
this.host = info.data;
});
return this.hass.callApi("get", "hassio/host/info").then((info) => {
this.host = info.data;
});
}
fetchHassInfo() {
return this.hass.callApi('get', 'hassio/homeassistant/info')
return this.hass
.callApi("get", "hassio/homeassistant/info")
.then((info) => {
this.homeassistant = info.data;
});
}
}
customElements.define('hassio-data', HassioData);
customElements.define("hassio-data", HassioData);

View File

@@ -1,16 +1,17 @@
import '@polymer/app-route/app-route.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/app-route/app-route.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../src/layouts/hass-loading-screen.js';
import './addon-view/hassio-addon-view.js';
import './hassio-data.js';
import './hassio-pages-with-tabs.js';
import "../../src/layouts/hass-loading-screen.js";
import "./addon-view/hassio-addon-view.js";
import "./hassio-data.js";
import "./hassio-pages-with-tabs.js";
import applyThemesOnElement from '../../src/common/dom/apply_themes_on_element.js';
import NavigateMixin from '../../src/mixins/navigate-mixin.js';
import applyThemesOnElement from "../../src/common/dom/apply_themes_on_element.js";
import EventsMixin from "../../src/mixins/events-mixin.js";
import NavigateMixin from "../../src/mixins/navigate-mixin.js";
class HassioMain extends NavigateMixin(PolymerElement) {
class HassioMain extends EventsMixin(NavigateMixin(PolymerElement)) {
static get template() {
return html`
<app-route route="[[route]]" pattern="/:page" data="{{routeData}}"></app-route>
@@ -40,11 +41,11 @@ class HassioMain extends NavigateMixin(PolymerElement) {
type: Object,
// Fake route object
value: {
prefix: '/hassio',
path: '/dashboard',
__queryParams: {}
prefix: "/hassio",
path: "/dashboard",
__queryParams: {},
},
observer: 'routeChanged',
observer: "routeChanged",
},
routeData: Object,
supervisorInfo: Object,
@@ -52,7 +53,7 @@ class HassioMain extends NavigateMixin(PolymerElement) {
hassInfo: Object,
loaded: {
type: Boolean,
computed: 'computeIsLoaded(supervisorInfo, hostInfo, hassInfo)',
computed: "computeIsLoaded(supervisorInfo, hostInfo, hassInfo)",
},
};
}
@@ -60,7 +61,7 @@ class HassioMain extends NavigateMixin(PolymerElement) {
ready() {
super.ready();
applyThemesOnElement(this, this.hass.themes, this.hass.selectedTheme, true);
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
}
connectedCallback() {
@@ -73,7 +74,7 @@ class HassioMain extends NavigateMixin(PolymerElement) {
let tries = 1;
const tryUpdate = () => {
this.$.data.refresh().catch(function () {
this.$.data.refresh().catch(function() {
tries += 1;
setTimeout(tryUpdate, Math.min(tries, 5) * 1000);
});
@@ -84,20 +85,19 @@ class HassioMain extends NavigateMixin(PolymerElement) {
}
computeIsLoaded(supervisorInfo, hostInfo, hassInfo) {
return (supervisorInfo !== null
&& hostInfo !== null
&& hassInfo !== null);
return supervisorInfo !== null && hostInfo !== null && hassInfo !== null;
}
routeChanged(route) {
if (route.path === '' && route.prefix === '/hassio') {
this.navigate('/hassio/dashboard', true);
if (route.path === "" && route.prefix === "/hassio") {
this.navigate("/hassio/dashboard", true);
}
this.fire("iron-resize");
}
equalsAddon(page) {
return page && page === 'addon';
return page && page === "addon";
}
}
customElements.define('hassio-main', HassioMain);
customElements.define("hassio-main", HassioMain);

View File

@@ -1,12 +1,12 @@
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js';
import '@polymer/paper-dialog/paper-dialog.js';
import '@polymer/paper-icon-button/paper-icon-button.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js";
import "@polymer/paper-dialog/paper-dialog.js";
import "@polymer/paper-icon-button/paper-icon-button.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../src/components/ha-markdown.js';
import '../../src/resources/ha-style.js';
import "../../src/components/ha-markdown.js";
import "../../src/resources/ha-style.js";
class HassioMarkdownDialog extends PolymerElement {
static get template() {
@@ -73,4 +73,4 @@ class HassioMarkdownDialog extends PolymerElement {
this.$.dialog.open();
}
}
customElements.define('hassio-markdown-dialog', HassioMarkdownDialog);
customElements.define("hassio-markdown-dialog", HassioMarkdownDialog);

View File

@@ -1,24 +1,24 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js';
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/paper-icon-button/paper-icon-button.js';
import '@polymer/paper-tabs/paper-tab.js';
import '@polymer/paper-tabs/paper-tabs.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/app-layout/app-header-layout/app-header-layout.js";
import "@polymer/app-layout/app-header/app-header.js";
import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import "@polymer/paper-icon-button/paper-icon-button.js";
import "@polymer/paper-tabs/paper-tab.js";
import "@polymer/paper-tabs/paper-tabs.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../src/components/ha-menu-button.js';
import '../../src/resources/ha-style.js';
import './addon-store/hassio-addon-store.js';
import './dashboard/hassio-dashboard.js';
import './hassio-markdown-dialog.js';
import './snapshots/hassio-snapshot.js';
import './snapshots/hassio-snapshots.js';
import './system/hassio-system.js';
import "../../src/components/ha-menu-button.js";
import "../../src/resources/ha-style.js";
import "./addon-store/hassio-addon-store.js";
import "./dashboard/hassio-dashboard.js";
import "./hassio-markdown-dialog.js";
import "./snapshots/hassio-snapshot.js";
import "./snapshots/hassio-snapshots.js";
import "./system/hassio-system.js";
import scrollToTarget from '../../src/common/dom/scroll-to-target.js';
import scrollToTarget from "../../src/common/dom/scroll-to-target.js";
import NavigateMixin from '../../src/mixins/navigate-mixin.js';
import NavigateMixin from "../../src/mixins/navigate-mixin.js";
class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
static get template() {
@@ -87,18 +87,20 @@ class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
markdownTitle: String,
markdownContent: {
type: String,
value: '',
value: "",
},
};
}
ready() {
super.ready();
this.addEventListener('hassio-markdown-dialog', ev => this.openMarkdown(ev));
this.addEventListener("hassio-markdown-dialog", (ev) =>
this.openMarkdown(ev)
);
}
handlePageSelected(ev) {
const newPage = ev.detail.item.getAttribute('page-name');
const newPage = ev.detail.item.getAttribute("page-name");
if (newPage !== this.page) {
this.navigate(`/hassio/${newPage}`);
}
@@ -110,14 +112,14 @@ class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
}
showRefreshButton(page) {
return page === 'store' || page === 'snapshots';
return page === "store" || page === "snapshots";
}
refreshClicked() {
if (this.page === 'snapshots') {
this.shadowRoot.querySelector('hassio-snapshots').refreshData();
if (this.page === "snapshots") {
this.shadowRoot.querySelector("hassio-snapshots").refreshData();
} else {
this.shadowRoot.querySelector('hassio-addon-store').refreshData();
this.shadowRoot.querySelector("hassio-addon-store").refreshData();
}
}
@@ -126,8 +128,8 @@ class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
markdownTitle: ev.detail.title,
markdownContent: ev.detail.content,
});
this.shadowRoot.querySelector('hassio-markdown-dialog').openDialog();
this.shadowRoot.querySelector("hassio-markdown-dialog").openDialog();
}
}
customElements.define('hassio-pages-with-tabs', HassioPagesWithTabs);
customElements.define("hassio-pages-with-tabs", HassioPagesWithTabs);

View File

@@ -1,7 +1,7 @@
import '../../../src/components/ha-iconset-svg.js';
import iconSetContent from '../../hassio-icons.html';
import "../../../src/components/ha-iconset-svg.js";
import iconSetContent from "../../hassio-icons.html";
const documentContainer = document.createElement('template');
documentContainer.setAttribute('style', 'display: none;');
const documentContainer = document.createElement("template");
documentContainer.setAttribute("style", "display: none;");
documentContainer.innerHTML = iconSetContent;
document.head.appendChild(documentContainer.content);

View File

@@ -1,5 +1,5 @@
const documentContainer = document.createElement('template');
documentContainer.setAttribute('style', 'display: none;');
const documentContainer = document.createElement("template");
documentContainer.setAttribute("style", "display: none;");
documentContainer.innerHTML = `<dom-module id="hassio-style">
<template>

View File

@@ -1,14 +1,14 @@
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-checkbox/paper-checkbox.js';
import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js';
import '@polymer/paper-dialog/paper-dialog.js';
import '@polymer/paper-icon-button/paper-icon-button.js';
import '@polymer/paper-input/paper-input.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/app-layout/app-toolbar/app-toolbar.js";
import "@polymer/paper-button/paper-button.js";
import "@polymer/paper-checkbox/paper-checkbox.js";
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js";
import "@polymer/paper-dialog/paper-dialog.js";
import "@polymer/paper-icon-button/paper-icon-button.js";
import "@polymer/paper-input/paper-input.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/resources/ha-style.js';
import "../../../src/resources/ha-style.js";
class HassioSnapshot extends PolymerElement {
static get template() {
@@ -114,7 +114,7 @@ class HassioSnapshot extends PolymerElement {
snapshotSlug: {
type: String,
notify: true,
observer: '_snapshotSlugChanged',
observer: "_snapshotSlugChanged",
},
snapshotDeleted: {
type: Boolean,
@@ -131,85 +131,124 @@ class HassioSnapshot extends PolymerElement {
}
_snapshotSlugChanged(snapshotSlug) {
if (!snapshotSlug || snapshotSlug === 'update') return;
this.hass.callApi('get', `hassio/snapshots/${snapshotSlug}/info`)
.then((info) => {
if (!snapshotSlug || snapshotSlug === "update") return;
this.hass.callApi("get", `hassio/snapshots/${snapshotSlug}/info`).then(
(info) => {
info.data.folders = this._computeFolders(info.data.folders);
info.data.addons = this._computeAddons(info.data.addons);
this.snapshot = info.data;
this.$.dialog.open();
}, () => {
},
() => {
this.snapshot = null;
});
}
);
}
_computeFolders(folders) {
const list = [];
if (folders.includes('homeassistant')) list.push({ slug: 'homeassistant', name: 'Home Assistant configuration', checked: true });
if (folders.includes('ssl')) list.push({ slug: 'ssl', name: 'SSL', checked: true });
if (folders.includes('share')) list.push({ slug: 'share', name: 'Share', checked: true });
if (folders.includes('addons/local')) list.push({ slug: 'addons/local', name: 'Local add-ons', checked: true });
if (folders.includes("homeassistant"))
list.push({
slug: "homeassistant",
name: "Home Assistant configuration",
checked: true,
});
if (folders.includes("ssl"))
list.push({ slug: "ssl", name: "SSL", checked: true });
if (folders.includes("share"))
list.push({ slug: "share", name: "Share", checked: true });
if (folders.includes("addons/local"))
list.push({ slug: "addons/local", name: "Local add-ons", checked: true });
return list;
}
_computeAddons(addons) {
return addons.map(addon => (
{ slug: addon.slug, name: addon.name, version: addon.version, checked: true }));
return addons.map((addon) => ({
slug: addon.slug,
name: addon.name,
version: addon.version,
checked: true,
}));
}
_isFullSnapshot(type) {
return type === 'full';
return type === "full";
}
_partialRestoreClicked() {
if (!confirm('Are you sure you want to restore this snapshot?')) {
if (!confirm("Are you sure you want to restore this snapshot?")) {
return;
}
const addons = this.snapshot.addons.filter(addon => addon.checked).map(addon => addon.slug);
const folders = this.snapshot.folders.filter(
folder => folder.checked
).map(folder => folder.slug);
const addons = this.snapshot.addons
.filter((addon) => addon.checked)
.map((addon) => addon.slug);
const folders = this.snapshot.folders
.filter((folder) => folder.checked)
.map((folder) => folder.slug);
const data = {
homeassistant: this.restoreHass,
addons: addons,
folders: folders
folders: folders,
};
if (this.snapshot.protected) data.password = this.snapshotPassword;
this.hass.callApi('post', `hassio/snapshots/${this.snapshotSlug}/restore/partial`, data).then(() => {
alert('Snapshot restored!');
this.$.dialog.close();
}, (error) => {
this.error = error.body.message;
});
this.hass
.callApi(
"post",
`hassio/snapshots/${this.snapshotSlug}/restore/partial`,
data
)
.then(
() => {
alert("Snapshot restored!");
this.$.dialog.close();
},
(error) => {
this.error = error.body.message;
}
);
}
_fullRestoreClicked() {
if (!confirm('Are you sure you want to restore this snapshot?')) {
if (!confirm("Are you sure you want to restore this snapshot?")) {
return;
}
const data = this.snapshot.protected ? { password: this.snapshotPassword } : null;
this.hass.callApi('post', `hassio/snapshots/${this.snapshotSlug}/restore/full`, data)
.then(() => {
alert('Snapshot restored!');
this.$.dialog.close();
}, (error) => {
this.error = error.body.message;
});
const data = this.snapshot.protected
? { password: this.snapshotPassword }
: null;
this.hass
.callApi(
"post",
`hassio/snapshots/${this.snapshotSlug}/restore/full`,
data
)
.then(
() => {
alert("Snapshot restored!");
this.$.dialog.close();
},
(error) => {
this.error = error.body.message;
}
);
}
_deleteClicked() {
if (!confirm('Are you sure you want to delete this snapshot?')) {
if (!confirm("Are you sure you want to delete this snapshot?")) {
return;
}
this.hass.callApi('post', `hassio/snapshots/${this.snapshotSlug}/remove`)
.then(() => {
this.$.dialog.close();
this.snapshotDeleted = true;
}, (error) => {
this.error = error.body.message;
});
this.hass
.callApi("post", `hassio/snapshots/${this.snapshotSlug}/remove`)
.then(
() => {
this.$.dialog.close();
this.snapshotDeleted = true;
},
(error) => {
this.error = error.body.message;
}
);
}
_computeDownloadUrl(snapshotSlug) {
@@ -218,7 +257,7 @@ class HassioSnapshot extends PolymerElement {
}
_computeDownloadName(snapshot) {
const name = this._computeName(snapshot).replace(/[^a-z0-9]+/gi, '_');
const name = this._computeName(snapshot).replace(/[^a-z0-9]+/gi, "_");
return `Hass_io_${name}.tar`;
}
@@ -227,11 +266,11 @@ class HassioSnapshot extends PolymerElement {
}
_computeType(type) {
return type === 'full' ? 'Full snapshot' : 'Partial snapshot';
return type === "full" ? "Full snapshot" : "Partial snapshot";
}
_computeSize(size) {
return (Math.ceil(size * 10) / 10) + ' MB';
return Math.ceil(size * 10) / 10 + " MB";
}
_sortAddons(a, b) {
@@ -240,12 +279,12 @@ class HassioSnapshot extends PolymerElement {
_formatDatetime(datetime) {
return new Date(datetime).toLocaleDateString(navigator.language, {
weekday: 'long',
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: '2-digit'
weekday: "long",
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
});
}
@@ -253,4 +292,4 @@ class HassioSnapshot extends PolymerElement {
this.snapshotSlug = null;
}
}
customElements.define('hassio-snapshot', HassioSnapshot);
customElements.define("hassio-snapshot", HassioSnapshot);

View File

@@ -1,15 +1,15 @@
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-checkbox/paper-checkbox.js';
import '@polymer/paper-input/paper-input.js';
import '@polymer/paper-radio-button/paper-radio-button.js';
import '@polymer/paper-radio-group/paper-radio-group.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-button/paper-button.js";
import "@polymer/paper-card/paper-card.js";
import "@polymer/paper-checkbox/paper-checkbox.js";
import "@polymer/paper-input/paper-input.js";
import "@polymer/paper-radio-button/paper-radio-button.js";
import "@polymer/paper-radio-group/paper-radio-group.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/hassio-card-content.js';
import '../resources/hassio-style.js';
import EventsMixin from '../../../src/mixins/events-mixin.js';
import "../components/hassio-card-content.js";
import "../resources/hassio-style.js";
import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioSnapshots extends EventsMixin(PolymerElement) {
static get template() {
@@ -105,16 +105,16 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
hass: Object,
snapshotName: {
type: String,
value: '',
value: "",
},
snapshotPassword: {
type: String,
value: '',
value: "",
},
snapshotHasPassword: Boolean,
snapshotType: {
type: String,
value: 'full',
value: "full",
},
snapshots: {
type: Array,
@@ -122,16 +122,20 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
},
installedAddons: {
type: Array,
observer: '_installedAddonsChanged',
observer: "_installedAddonsChanged",
},
addonList: Array,
folderList: {
type: Array,
value: [
{ slug: 'homeassistant', name: 'Home Assistant configuration', checked: true },
{ slug: 'ssl', name: 'SSL', checked: true },
{ slug: 'share', name: 'Share', checked: true },
{ slug: 'addons/local', name: 'Local add-ons', checked: true },
{
slug: "homeassistant",
name: "Home Assistant configuration",
checked: true,
},
{ slug: "ssl", name: "SSL", checked: true },
{ slug: "share", name: "Share", checked: true },
{ slug: "addons/local", name: "Local add-ons", checked: true },
],
},
snapshotSlug: {
@@ -141,7 +145,7 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
snapshotDeleted: {
type: Boolean,
notify: true,
observer: '_snapshotDeletedChanged',
observer: "_snapshotDeletedChanged",
},
creatingSnapshot: Boolean,
dialogOpened: Boolean,
@@ -151,7 +155,7 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
ready() {
super.ready();
this.addEventListener('hass-api-called', ev => this._apiCalled(ev));
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
this._updateSnapshots();
}
@@ -162,57 +166,70 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
}
_updateSnapshots() {
this.hass.callApi('get', 'hassio/snapshots')
.then((result) => {
this.hass.callApi("get", "hassio/snapshots").then(
(result) => {
this.snapshots = result.data.snapshots;
}, (error) => {
},
(error) => {
this.error = error.message;
});
}
);
}
_createSnapshot() {
this.error = '';
this.error = "";
if (this.snapshotHasPassword && !this.snapshotPassword.length) {
this.error = 'Please enter a password.';
this.error = "Please enter a password.";
return;
}
this.creatingSnapshot = true;
let name = this.snapshotName;
if (!name.length) {
name = new Date().toLocaleDateString(navigator.language, {
weekday: 'long',
year: 'numeric',
month: 'short',
day: 'numeric' });
weekday: "long",
year: "numeric",
month: "short",
day: "numeric",
});
}
let data;
let path;
if (this.snapshotType === 'full') {
if (this.snapshotType === "full") {
data = { name: name };
path = 'hassio/snapshots/new/full';
path = "hassio/snapshots/new/full";
} else {
const addons = this.addonList.filter(addon => addon.checked).map(addon => addon.slug);
const folders = this.folderList.filter(folder => folder.checked).map(folder => folder.slug);
const addons = this.addonList
.filter((addon) => addon.checked)
.map((addon) => addon.slug);
const folders = this.folderList
.filter((folder) => folder.checked)
.map((folder) => folder.slug);
data = { name: name, folders: folders, addons: addons };
path = 'hassio/snapshots/new/partial';
path = "hassio/snapshots/new/partial";
}
if (this.snapshotHasPassword) {
data.password = this.snapshotPassword;
}
this.hass.callApi('post', path, data)
.then(() => {
this.hass.callApi("post", path, data).then(
() => {
this.creatingSnapshot = false;
this.fire('hass-api-called', { success: true });
}, (error) => {
this.fire("hass-api-called", { success: true });
},
(error) => {
this.creatingSnapshot = false;
this.error = error.message;
});
}
);
}
_installedAddonsChanged(addons) {
this.addonList = addons.map(addon => ({ slug: addon.slug, name: addon.name, checked: true }));
this.addonList = addons.map((addon) => ({
slug: addon.slug,
name: addon.name,
checked: true,
}));
}
_sortAddons(a, b) {
@@ -228,12 +245,15 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
}
_computeDetails(snapshot) {
const type = snapshot.type === 'full' ? 'Full snapshot' : 'Partial snapshot';
const type =
snapshot.type === "full" ? "Full snapshot" : "Partial snapshot";
return snapshot.protected ? `${type}, password protected` : type;
}
_computeIcon(type) {
return type === 'full' ? 'hassio:package-variant-closed' : 'hassio:package-variant';
return type === "full"
? "hassio:package-variant-closed"
: "hassio:package-variant";
}
_snapshotClicked(ev) {
@@ -241,7 +261,7 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
}
_fullSelected(type) {
return type === 'full';
return type === "full";
}
_snapshotDeletedChanged(snapshotDeleted) {
@@ -252,11 +272,10 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
}
refreshData() {
this.hass.callApi('post', 'hassio/snapshots/reload')
.then(() => {
this._updateSnapshots();
});
this.hass.callApi("post", "hassio/snapshots/reload").then(() => {
this._updateSnapshots();
});
}
}
customElements.define('hassio-snapshots', HassioSnapshots);
customElements.define("hassio-snapshots", HassioSnapshots);

View File

@@ -1,10 +1,10 @@
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-button/paper-button.js";
import "@polymer/paper-card/paper-card.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js';
import EventsMixin from '../../../src/mixins/events-mixin.js';
import "../../../src/components/buttons/ha-call-api-button.js";
import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioHostInfo extends EventsMixin(PolymerElement) {
static get template() {
@@ -17,6 +17,7 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
}
.card-content {
height: 200px;
color: var(--primary-text-color);
}
@media screen and (max-width: 830px) {
paper-card {
@@ -96,16 +97,16 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
hass: Object,
data: {
type: Object,
observer: '_dataChanged'
observer: "_dataChanged",
},
errors: String,
_hassOs: Object
_hassOs: Object,
};
}
ready() {
super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
}
apiCalled(ev) {
@@ -116,19 +117,18 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
var response = ev.detail.response;
if (typeof response.body === 'object') {
this.errors = response.body.message || 'Unknown error';
if (typeof response.body === "object") {
this.errors = response.body.message || "Unknown error";
} else {
this.errors = response.body;
}
}
_dataChanged(data) {
if (data.features && data.features.includes('hassos')) {
this.hass.callApi('get', 'hassio/hassos/info')
.then((resp) => {
this._hassOs = resp.data;
});
if (data.features && data.features.includes("hassos")) {
this.hass.callApi("get", "hassio/hassos/info").then((resp) => {
this._hassOs = resp.data;
});
} else {
this._hassOs = {};
}
@@ -143,28 +143,31 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
}
_showHardware() {
this.hass.callApi('get', 'hassio/hardware/info')
this.hass
.callApi("get", "hassio/hardware/info")
.then(
resp => this._objectToMarkdown(resp.data),
() => 'Error getting hardware info'
).then((content) => {
this.fire('hassio-markdown-dialog', {
title: 'Hardware',
(resp) => this._objectToMarkdown(resp.data),
() => "Error getting hardware info"
)
.then((content) => {
this.fire("hassio-markdown-dialog", {
title: "Hardware",
content: content,
});
});
}
_objectToMarkdown(obj, indent = '') {
let data = '';
_objectToMarkdown(obj, indent = "") {
let data = "";
Object.keys(obj).forEach((key) => {
if (typeof obj[key] !== 'object') {
if (typeof obj[key] !== "object") {
data += `${indent}- ${key}: ${obj[key]}\n`;
} else {
data += `${indent}- ${key}:\n`;
if (Array.isArray(obj[key])) {
if (obj[key].length) {
data += `${indent} - ` + obj[key].join(`\n${indent} - `) + '\n';
data +=
`${indent} - ` + obj[key].join(`\n${indent} - `) + "\n";
}
} else {
data += this._objectToMarkdown(obj[key], ` ${indent}`);
@@ -176,11 +179,11 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
_changeHostnameClicked() {
const curHostname = this.data.hostname;
const hostname = prompt('Please enter a new hostname:', curHostname);
const hostname = prompt("Please enter a new hostname:", curHostname);
if (hostname && hostname !== curHostname) {
this.hass.callApi('post', 'hassio/host/options', { hostname });
this.hass.callApi("post", "hassio/host/options", { hostname });
}
}
}
customElements.define('hassio-host-info', HassioHostInfo);
customElements.define("hassio-host-info", HassioHostInfo);

View File

@@ -1,10 +1,10 @@
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-button/paper-button.js";
import "@polymer/paper-card/paper-card.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../../../src/components/buttons/ha-call-api-button.js';
import EventsMixin from '../../../src/mixins/events-mixin.js';
import "../../../src/components/buttons/ha-call-api-button.js";
import EventsMixin from "../../../src/mixins/events-mixin.js";
class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
static get template() {
@@ -16,6 +16,7 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
}
.card-content {
height: 200px;
color: var(--primary-text-color);
}
@media screen and (max-width: 830px) {
paper-card {
@@ -84,14 +85,14 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
errors: String,
leaveBeta: {
type: Object,
value: { channel: 'stable' },
value: { channel: "stable" },
},
};
}
ready() {
super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
}
apiCalled(ev) {
@@ -102,8 +103,8 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
var response = ev.detail.response;
if (typeof response.body === 'object') {
this.errors = response.body.message || 'Unknown error';
if (typeof response.body === "object") {
this.errors = response.body.message || "Unknown error";
} else {
this.errors = response.body;
}
@@ -118,18 +119,20 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
}
_joinBeta() {
if (!confirm(`WARNING:
if (
!confirm(`WARNING:
Beta releases are for testers and early adopters and can contain unstable code changes. Make sure you have backups of your data before you activate this feature.
This inludes beta releases for:
- Home Assistant (Release Candidates)
- Hass.io supervisor
- Host system`)) {
- Host system`)
) {
return;
}
const method = 'post';
const path = 'hassio/supervisor/options';
const data = { channel: 'beta' };
const method = "post";
const path = "hassio/supervisor/options";
const data = { channel: "beta" };
const eventData = {
method: method,
@@ -137,17 +140,22 @@ This inludes beta releases for:
data: data,
};
this.hass.callApi(method, path, data)
.then((resp) => {
eventData.success = true;
eventData.response = resp;
}, (resp) => {
eventData.success = false;
eventData.response = resp;
}).then(() => {
this.fire('hass-api-called', eventData);
this.hass
.callApi(method, path, data)
.then(
(resp) => {
eventData.success = true;
eventData.response = resp;
},
(resp) => {
eventData.success = false;
eventData.response = resp;
}
)
.then(() => {
this.fire("hass-api-called", eventData);
});
}
}
customElements.define('hassio-supervisor-info', HassioSupervisorInfo);
customElements.define("hassio-supervisor-info", HassioSupervisorInfo);

View File

@@ -1,7 +1,7 @@
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-button/paper-button.js";
import "@polymer/paper-card/paper-card.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
class HassioSupervisorLog extends PolymerElement {
static get template() {
@@ -38,12 +38,14 @@ class HassioSupervisorLog extends PolymerElement {
}
loadData() {
this.hass.callApi('get', 'hassio/supervisor/logs')
.then((info) => {
this.hass.callApi("get", "hassio/supervisor/logs").then(
(info) => {
this.log = info;
}, () => {
this.log = 'Error fetching logs';
});
},
() => {
this.log = "Error fetching logs";
}
);
}
refreshTapped() {
@@ -51,4 +53,4 @@ class HassioSupervisorLog extends PolymerElement {
}
}
customElements.define('hassio-supervisor-log', HassioSupervisorLog);
customElements.define("hassio-supervisor-log", HassioSupervisorLog);

View File

@@ -1,10 +1,10 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/iron-flex-layout/iron-flex-layout-classes.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import './hassio-host-info.js';
import './hassio-supervisor-info.js';
import './hassio-supervisor-log.js';
import "./hassio-host-info.js";
import "./hassio-supervisor-info.js";
import "./hassio-supervisor-log.js";
class HassioSystem extends PolymerElement {
static get template() {
@@ -40,4 +40,4 @@ class HassioSystem extends PolymerElement {
}
}
customElements.define('hassio-system', HassioSystem);
customElements.define("hassio-system", HassioSystem);

View File

@@ -1,69 +1,54 @@
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const CompressionPlugin = require("compression-webpack-plugin");
const config = require('./config.js');
const config = require("./config.js");
const { babelLoaderConfig } = require("../config/babel.js");
const isProdBuild = process.env.NODE_ENV === 'production'
const chunkFilename = isProdBuild ?
'chunk.[chunkhash].js' : '[name].chunk.js';
const isProdBuild = process.env.NODE_ENV === "production";
const chunkFilename = isProdBuild ? "chunk.[chunkhash].js" : "[name].chunk.js";
module.exports = {
mode: isProdBuild ? 'production' : 'development',
devtool: isProdBuild ? 'source-map' : 'inline-source-map',
mode: isProdBuild ? "production" : "development",
devtool: isProdBuild ? "source-map" : "inline-source-map",
entry: {
entrypoint: './src/entrypoint.js',
entrypoint: "./src/entrypoint.js",
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
[require('babel-preset-env').default, { modules: false }]
],
plugins: [
// Only support the syntax, Webpack will handle it.
"syntax-dynamic-import",
],
},
},
},
babelLoaderConfig({ latestBuild: false }),
{
test: /\.(html)$/,
use: {
loader: 'html-loader',
loader: "html-loader",
options: {
exportAsEs6Default: true,
}
}
}
]
},
},
},
],
},
plugins: [
isProdBuild && new UglifyJsPlugin({
extractComments: true,
sourceMap: true,
uglifyOptions: {
// Disabling because it broke output
mangle: false,
}
}),
isProdBuild && new CompressionPlugin({
cache: true,
exclude: [
/\.js\.map$/,
/\.LICENSE$/,
/\.py$/,
/\.txt$/,
]
}),
isProdBuild &&
new UglifyJsPlugin({
extractComments: true,
sourceMap: true,
uglifyOptions: {
// Disabling because it broke output
mangle: false,
},
}),
isProdBuild &&
new CompressionPlugin({
cache: true,
exclude: [/\.js\.map$/, /\.LICENSE$/, /\.py$/, /\.txt$/],
}),
].filter(Boolean),
resolve: {
extensions: [".ts", ".js", ".json"],
},
output: {
filename: '[name].js',
filename: "[name].js",
chunkFilename,
path: config.buildDir,
publicPath: `${config.publicPath}/`,
}
},
};

View File

@@ -8,7 +8,7 @@
"version": "1.0.0",
"scripts": {
"build": "script/build_frontend",
"lint": "eslint src hassio/src gallery/src test-mocha && polymer lint",
"lint": "eslint src hassio/src gallery/src test-mocha && tslint -c tslint.json 'src/**/*.ts' 'hassio/src/**/*.ts' 'gallery/src/**/*.ts' 'test-mocha/**/*.ts' && polymer lint && tsc",
"mocha": "node_modules/.bin/mocha --opts test-mocha/mocha.opts",
"test": "npm run lint && npm run mocha",
"docker_build": "sh ./script/docker_run.sh build $npm_package_version",
@@ -17,6 +17,7 @@
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
"license": "Apache-2.0",
"dependencies": {
"@material/mwc-ripple": "^0.3.1",
"@mdi/svg": "^2.7.94",
"@polymer/app-layout": "^3.0.1",
"@polymer/app-localize-behavior": "^3.0.1",
@@ -34,6 +35,7 @@
"@polymer/iron-media-query": "^3.0.1",
"@polymer/iron-pages": "^3.0.1",
"@polymer/iron-resizable-behavior": "^3.0.1",
"@polymer/lit-element": "^0.6.2",
"@polymer/neon-animation": "^3.0.1",
"@polymer/paper-button": "^3.0.1",
"@polymer/paper-card": "^3.0.1",
@@ -75,6 +77,7 @@
"intl-messageformat": "^2.2.0",
"js-yaml": "^3.12.0",
"leaflet": "^1.3.4",
"lit-html": "^0.12.0",
"marked": "^0.5.0",
"mdn-polyfills": "^5.12.0",
"moment": "^2.22.2",
@@ -87,22 +90,26 @@
"xss": "^1.0.3"
},
"devDependencies": {
"@babel/core": "^7.1.2",
"@babel/plugin-external-helpers": "^7.0.0",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
"@babel/plugin-transform-react-jsx": "^7.0.0",
"@babel/preset-env": "^7.1.0",
"@babel/preset-typescript": "7.0.0",
"@gfx/zopfli": "^1.0.9",
"babel-core": "^6.26.3",
"babel-eslint": "^9.0.0",
"babel-loader": "^7.1.4",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-react-jsx": "^6.24.1",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.24.1",
"babel-eslint": "^10",
"babel-loader": "^8.0.4",
"babel-minify-webpack-plugin": "^0.3.1",
"chai": "^4.1.2",
"compression-webpack-plugin": "^2.0.0",
"copy-webpack-plugin": "^4.5.2",
"del": "^3.0.0",
"eslint": "^5.6.0",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-config-prettier": "^3.1.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-prettier": "^3.0.0",
"eslint-plugin-react": "^7.11.1",
"gulp": "^3.9.1",
"gulp-foreach": "^0.1.0",
@@ -115,17 +122,23 @@
"html-loader": "^0.5.5",
"html-minifier": "^3.5.20",
"html-webpack-plugin": "^3.2.0",
"husky": "^1.1.0",
"lint-staged": "^7.3.0",
"merge-stream": "^1.0.1",
"mocha": "^5.2.0",
"parse5": "^5.1.0",
"polymer-analyzer": "^3.1.2",
"polymer-bundler": "^4.0.2",
"polymer-cli": "^1.8.0",
"prettier": "^1.14.3",
"raw-loader": "^0.5.1",
"reify": "^0.17.3",
"require-dir": "^1.0.0",
"sinon": "^6.3.4",
"uglifyjs-webpack-plugin": "^1.2.6",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.15.0",
"tslint-eslint-rules": "^5.4.0",
"typescript": "3.1.3",
"wct-browser-legacy": "^1.0.1",
"web-component-tester": "^6.8.0",
"webpack": "^4.19.1",
@@ -145,5 +158,25 @@
"@vaadin/vaadin-lumo-styles": "1.2.0",
"fecha": "https://github.com/balloob/fecha/archive/51d14fd0eb4781e2ecf265d1c3080706259133b5.tar.gz"
},
"main": "src/home-assistant.js"
"main": "src/home-assistant.js",
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"linters": {
"*.{js,json,css,md}": [
"prettier --write",
"git add"
]
},
"ignore": [
"translations/**"
]
},
"prettier": {
"trailingComma": "es5",
"arrowParens": "always"
}
}

View File

@@ -28,7 +28,7 @@ mkdir -p ${LOCAL_DIR}
docker run \
-v ${LOCAL_DIR}:/opt/dest/locale \
lokalise/lokalise-cli@sha256:ddf5677f58551261008342df5849731c88bcdc152ab645b133b21819aede8218 lokalise \
lokalise/lokalise-cli@sha256:b8329d20280263cad04f65b843e54b9e8e6909a348a678eac959550b5ef5c75f lokalise \
--token ${LOKALISE_TOKEN} \
export ${PROJECT_ID} \
--export_empty skip \

View File

@@ -1,20 +1,22 @@
from setuptools import setup, find_packages
setup(name='home-assistant-frontend',
version='20180919.0',
description='The Home Assistant frontend',
url='https://github.com/home-assistant/home-assistant-polymer',
author='The Home Assistant Authors',
author_email='hello@home-assistant.io',
license='Apache License 2.0',
packages=find_packages(include=[
'hass_frontend',
'hass_frontend_es5',
'hass_frontend.*',
'hass_frontend_es5.*'
]),
install_requires=[
'user-agents==1.1.0',
],
include_package_data=True,
zip_safe=False)
setup(
name="home-assistant-frontend",
version="20181024.0",
description="The Home Assistant frontend",
url="https://github.com/home-assistant/home-assistant-polymer",
author="The Home Assistant Authors",
author_email="hello@home-assistant.io",
license="Apache License 2.0",
packages=find_packages(
include=[
"hass_frontend",
"hass_frontend_es5",
"hass_frontend.*",
"hass_frontend_es5.*",
]
),
install_requires=["user-agents==1.1.0"],
include_package_data=True,
zip_safe=False,
)

View File

@@ -1,8 +1,8 @@
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '@polymer/paper-button/paper-button.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import '../components/ha-form.js';
import LocalizeLiteMixin from '../mixins/localize-lite-mixin.js';
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import "@polymer/paper-button/paper-button.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import "../components/ha-form.js";
import LocalizeLiteMixin from "../mixins/localize-lite-mixin.js";
class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
static get template() {
@@ -61,14 +61,14 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
return {
authProvider: {
type: Object,
observer: '_providerChanged',
observer: "_providerChanged",
},
clientId: String,
redirectUri: String,
oauth2State: String,
_state: {
type: String,
value: 'loading'
value: "loading",
},
_stepData: {
type: Object,
@@ -85,7 +85,7 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
ready() {
super.ready();
this.addEventListener('keypress', (ev) => {
this.addEventListener("keypress", (ev) => {
if (ev.keyCode === 13) {
this._handleSubmit();
}
@@ -93,22 +93,22 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
}
async _providerChanged(newProvider, oldProvider) {
if (oldProvider && this._step && this._step.type === 'form') {
if (oldProvider && this._step && this._step.type === "form") {
fetch(`/auth/login_flow/${this._step.flow_id}`, {
method: 'DELETE',
credentials: 'same-origin',
method: "DELETE",
credentials: "same-origin",
}).catch(() => {});
}
try {
const response = await fetch('/auth/login_flow', {
method: 'POST',
credentials: 'same-origin',
const response = await fetch("/auth/login_flow", {
method: "POST",
credentials: "same-origin",
body: JSON.stringify({
client_id: this.clientId,
handler: [newProvider.type, newProvider.id],
redirect_uri: this.redirectUri,
})
}),
});
const data = await response.json();
@@ -117,16 +117,16 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
this._updateStep(data);
} else {
this.setProperties({
_state: 'error',
_state: "error",
_errorMsg: data.message,
});
}
} catch (err) {
// eslint-disable-next-line
console.error('Error starting auth flow', err);
console.error("Error starting auth flow", err);
this.setProperties({
_state: 'error',
_errorMsg: this.localize('ui.panel.page-authorize.form.unknown_error'),
_state: "error",
_errorMsg: this.localize("ui.panel.page-authorize.form.unknown_error"),
});
}
}
@@ -134,11 +134,14 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
_updateStep(step) {
const props = {
_step: step,
_state: 'step',
_state: "step",
};
if (this._step
&& (step.flow_id !== this._step.flow_id || step.step_id !== this._step.step_id)) {
if (
this._step &&
(step.flow_id !== this._step.flow_id ||
step.step_id !== this._step.step_id)
) {
props._stepData = {};
}
@@ -150,15 +153,23 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
}
_computeSubmitCaption(stepType) {
return stepType === 'form' ? 'Next' : 'Start over';
return stepType === "form" ? "Next" : "Start over";
}
_computeStepAbortedReason(localize, step) {
return localize(`ui.panel.page-authorize.form.providers.${step.handler[0]}.abort.${step.reason}`);
return localize(
`ui.panel.page-authorize.form.providers.${step.handler[0]}.abort.${
step.reason
}`
);
}
_computeStepDescription(localize, step) {
const args = [`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${step.step_id}.description`];
const args = [
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${
step.step_id
}.description`,
];
const placeholders = step.description_placeholders || {};
Object.keys(placeholders).forEach((key) => {
args.push(key);
@@ -169,22 +180,32 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
_computeLabelCallback(localize, step) {
// Returns a callback for ha-form to calculate labels per schema object
return schema => localize(`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${step.step_id}.data.${schema.name}`);
return (schema) =>
localize(
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${
step.step_id
}.data.${schema.name}`
);
}
_computeErrorCallback(localize, step) {
// Returns a callback for ha-form to calculate error messages
return error => localize(`ui.panel.page-authorize.form.providers.${step.handler[0]}.error.${error}`);
return (error) =>
localize(
`ui.panel.page-authorize.form.providers.${
step.handler[0]
}.error.${error}`
);
}
async _handleSubmit() {
if (this._step.type !== 'form') {
if (this._step.type !== "form") {
this._providerChanged(this.authProvider, null);
return;
}
this._state = 'loading';
this._state = "loading";
// To avoid a jumping UI.
this.style.setProperty('min-height', `${this.offsetHeight}px`);
this.style.setProperty("min-height", `${this.offsetHeight}px`);
const postData = Object.assign({}, this._stepData, {
client_id: this.clientId,
@@ -192,20 +213,20 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
try {
const response = await fetch(`/auth/login_flow/${this._step.flow_id}`, {
method: 'POST',
credentials: 'same-origin',
body: JSON.stringify(postData)
method: "POST",
credentials: "same-origin",
body: JSON.stringify(postData),
});
const newStep = await response.json();
if (newStep.type === 'create_entry') {
if (newStep.type === "create_entry") {
// OAuth 2: 3.1.2 we need to retain query component of a redirect URI
let url = this.redirectUri;
if (!url.includes('?')) {
url += '?';
} else if (!url.endsWith('&')) {
url += '&';
if (!url.includes("?")) {
url += "?";
} else if (!url.endsWith("&")) {
url += "&";
}
url += `code=${encodeURIComponent(newStep.result)}`;
@@ -220,11 +241,11 @@ class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
this._updateStep(newStep);
} catch (err) {
// eslint-disable-next-line
console.error('Error submitting step', err);
this._state = 'error-loading';
console.error("Error submitting step", err);
this._state = "error-loading";
} finally {
this.style.setProperty('min-height', '');
this.style.setProperty("min-height", "");
}
}
}
customElements.define('ha-auth-flow', HaAuthFlow);
customElements.define("ha-auth-flow", HaAuthFlow);

View File

@@ -1,13 +1,13 @@
import '@polymer/polymer/lib/elements/dom-if.js';
import '@polymer/polymer/lib/elements/dom-repeat.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/polymer/lib/elements/dom-if.js";
import "@polymer/polymer/lib/elements/dom-repeat.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/ha-markdown.js';
import "../components/ha-markdown.js";
import LocalizeLiteMixin from '../mixins/localize-lite-mixin.js';
import LocalizeLiteMixin from "../mixins/localize-lite-mixin.js";
import './ha-auth-flow.js';
import "./ha-auth-flow.js";
class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
static get template() {
@@ -66,17 +66,17 @@ class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
oauth2State: String,
translationFragment: {
type: String,
value: 'page-authorize',
}
value: "page-authorize",
},
};
}
async ready() {
super.ready();
const query = {};
const values = location.search.substr(1).split('&');
const values = location.search.substr(1).split("&");
for (let i = 0; i < values.length; i++) {
const value = values[i].split('=');
const value = values[i].split("=");
if (value.length > 1) {
query[decodeURIComponent(value[0])] = decodeURIComponent(value[1]);
}
@@ -87,7 +87,7 @@ class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
if (query.state) props.oauth2State = query.state;
this.setProperties(props);
import(/* webpackChunkName: "pick-auth-provider" */ '../auth/ha-pick-auth-provider.js');
import(/* webpackChunkName: "pick-auth-provider" */ "../auth/ha-pick-auth-provider.js");
// Fetch auth providers
try {
@@ -95,13 +95,16 @@ class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
const authProviders = await response.json();
// Forward to main screen which will redirect to right onboarding page.
if (response.status === 400 && authProviders.code === 'onboarding_required') {
location.href = '/';
if (
response.status === 400 &&
authProviders.code === "onboarding_required"
) {
location.href = "/";
return;
}
if (authProviders.length === 0) {
alert('No auth providers returned. Unable to finish login.');
alert("No auth providers returned. Unable to finish login.");
return;
}
@@ -111,8 +114,8 @@ class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
});
} catch (err) {
// eslint-disable-next-line
console.error('Error loading auth providers', err);
this._state = 'error-loading';
console.error("Error loading auth providers", err);
this._state = "error-loading";
}
}
@@ -125,15 +128,25 @@ class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
}
_computeInactiveProvders(curProvider, providers) {
return providers.filter(prv => prv.type !== curProvider.type || prv.id !== curProvider.id);
return providers.filter(
(prv) => prv.type !== curProvider.type || prv.id !== curProvider.id
);
}
_computeIntro(localize, clientId, authProvider) {
return (
localize('ui.panel.page-authorize.authorizing_client', 'clientId', clientId)
+ '\n\n'
+ localize('ui.panel.page-authorize.logging_in_with', 'authProviderName', authProvider.name)
localize(
"ui.panel.page-authorize.authorizing_client",
"clientId",
clientId
) +
"\n\n" +
localize(
"ui.panel.page-authorize.logging_in_with",
"authProviderName",
authProvider.name
)
);
}
}
customElements.define('ha-authorize', HaAuthorize);
customElements.define("ha-authorize", HaAuthorize);

View File

@@ -1,15 +1,17 @@
import '@polymer/paper-item/paper-item.js';
import '@polymer/paper-item/paper-item-body.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-item/paper-item.js";
import "@polymer/paper-item/paper-item-body.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import EventsMixin from '../mixins/events-mixin.js';
import LocalizeLiteMixin from '../mixins/localize-lite-mixin.js';
import EventsMixin from "../mixins/events-mixin.js";
import LocalizeLiteMixin from "../mixins/localize-lite-mixin.js";
/*
* @appliesMixin EventsMixin
*/
class HaPickAuthProvider extends EventsMixin(LocalizeLiteMixin(PolymerElement)) {
class HaPickAuthProvider extends EventsMixin(
LocalizeLiteMixin(PolymerElement)
) {
static get template() {
return html`
<style>
@@ -34,18 +36,18 @@ class HaPickAuthProvider extends EventsMixin(LocalizeLiteMixin(PolymerElement))
return {
_state: {
type: String,
value: 'loading'
value: "loading",
},
authProviders: Array,
};
}
_handlePick(ev) {
this.fire('pick', ev.model.item);
this.fire("pick", ev.model.item);
}
_equal(a, b) {
return a === b;
}
}
customElements.define('ha-pick-auth-provider', HaPickAuthProvider);
customElements.define("ha-pick-auth-provider", HaPickAuthProvider);

View File

@@ -1,7 +1,7 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/entity/ha-state-label-badge.js';
import "../components/entity/ha-state-label-badge.js";
class HaBadgesCard extends PolymerElement {
static get template() {
@@ -25,4 +25,4 @@ class HaBadgesCard extends PolymerElement {
};
}
}
customElements.define('ha-badges-card', HaBadgesCard);
customElements.define("ha-badges-card", HaBadgesCard);

View File

@@ -1,11 +1,10 @@
import '@polymer/paper-styles/element-styles/paper-material-styles.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-styles/element-styles/paper-material-styles.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import computeStateName from '../common/entity/compute_state_name.js';
import EventsMixin from '../mixins/events-mixin.js';
import LocalizeMixin from '../mixins/localize-mixin.js';
import computeStateName from "../common/entity/compute_state_name.js";
import EventsMixin from "../mixins/events-mixin.js";
import LocalizeMixin from "../mixins/localize-mixin.js";
const UPDATE_INTERVAL = 10000; // ms
/*
@@ -67,11 +66,11 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
hass: Object,
stateObj: {
type: Object,
observer: 'updateCameraFeedSrc',
observer: "updateCameraFeedSrc",
},
cameraFeedSrc: {
type: String,
value: '',
value: "",
},
imageLoaded: {
type: Boolean,
@@ -82,7 +81,7 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
ready() {
super.ready();
this.addEventListener('click', () => this.cardTapped());
this.addEventListener("click", () => this.cardTapped());
}
connectedCallback() {
@@ -96,13 +95,13 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
}
cardTapped() {
this.fire('hass-more-info', { entityId: this.stateObj.entity_id });
this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
}
async updateCameraFeedSrc() {
try {
const { content_type: contentType, content } = await this.hass.callWS({
type: 'camera_thumbnail',
type: "camera_thumbnail",
entity_id: this.stateObj.entity_id,
});
this.setProperties({
@@ -118,4 +117,4 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
return computeStateName(stateObj);
}
}
customElements.define('ha-camera-card', HaCameraCard);
customElements.define("ha-camera-card", HaCameraCard);

View File

@@ -1,28 +1,29 @@
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import './ha-camera-card.js';
import './ha-entities-card.js';
import './ha-history_graph-card.js';
import './ha-media_player-card.js';
import './ha-persistent_notification-card.js';
import './ha-plant-card.js';
import './ha-weather-card.js';
import "./ha-camera-card.js";
import "./ha-entities-card.js";
import "./ha-history_graph-card.js";
import "./ha-media_player-card.js";
import "./ha-persistent_notification-card.js";
import "./ha-plant-card.js";
import "./ha-weather-card.js";
import dynamicContentUpdater from '../common/dom/dynamic_content_updater.js';
import dynamicContentUpdater from "../common/dom/dynamic_content_updater.js";
class HaCardChooser extends PolymerElement {
static get properties() {
return {
cardData: {
type: Object,
observer: 'cardDataChanged',
observer: "cardDataChanged",
},
};
}
_updateCard(newData) {
dynamicContentUpdater(
this, 'HA-' + newData.cardType.toUpperCase() + '-CARD',
this,
"HA-" + newData.cardType.toUpperCase() + "-CARD",
newData
);
}
@@ -32,7 +33,7 @@ class HaCardChooser extends PolymerElement {
this.observer = new IntersectionObserver((entries) => {
if (!entries.length) return;
if (entries[0].isIntersecting) {
this.style.height = '';
this.style.height = "";
if (this._detachedChild) {
this.appendChild(this._detachedChild);
this._detachedChild = null;
@@ -58,13 +59,14 @@ class HaCardChooser extends PolymerElement {
if (!newData) return;
// ha-entities-card is exempt from observer as it doesn't load heavy resources.
// and usually doesn't load external resources (except for entity_picture).
const eligibleToObserver = (window.IntersectionObserver && newData.cardType !== 'entities');
const eligibleToObserver =
window.IntersectionObserver && newData.cardType !== "entities";
if (!eligibleToObserver) {
if (this.observer) {
this.observer.unobserve(this);
this.observer = null;
}
this.style.height = '';
this.style.height = "";
this._updateCard(newData);
return;
}
@@ -76,4 +78,4 @@ class HaCardChooser extends PolymerElement {
}
}
}
customElements.define('ha-card-chooser', HaCardChooser);
customElements.define("ha-card-chooser", HaCardChooser);

View File

@@ -1,18 +1,17 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/iron-flex-layout/iron-flex-layout-classes.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/entity/ha-entity-toggle.js';
import '../components/ha-card.js';
import '../state-summary/state-card-content.js';
import "../components/entity/ha-entity-toggle.js";
import "../components/ha-card.js";
import "../state-summary/state-card-content.js";
import computeStateDomain from '../common/entity/compute_state_domain.js';
import computeStateName from '../common/entity/compute_state_name.js';
import stateMoreInfoType from '../common/entity/state_more_info_type.js';
import canToggleState from '../common/entity/can_toggle_state.js';
import EventsMixin from '../mixins/events-mixin.js';
import LocalizeMixin from '../mixins/localize-mixin.js';
import computeStateDomain from "../common/entity/compute_state_domain.js";
import computeStateName from "../common/entity/compute_state_name.js";
import stateMoreInfoType from "../common/entity/state_more_info_type.js";
import canToggleState from "../common/entity/can_toggle_state.js";
import EventsMixin from "../mixins/events-mixin.js";
import LocalizeMixin from "../mixins/localize-mixin.js";
class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() {
@@ -74,7 +73,7 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
groupEntity: Object,
title: {
type: String,
computed: 'computeTitle(states, groupEntity, localize)',
computed: "computeTitle(states, groupEntity, localize)",
},
};
}
@@ -91,34 +90,40 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
return computeStateName(groupEntity).trim();
}
const domain = computeStateDomain(states[0]);
return (localize && localize(`domain.${domain}`)) || domain.replace(/_/g, ' ');
return (
(localize && localize(`domain.${domain}`)) || domain.replace(/_/g, " ")
);
}
computeTitleClass(groupEntity) {
let classes = 'header horizontal layout center ';
let classes = "header horizontal layout center ";
if (groupEntity) {
classes += 'more-info';
classes += "more-info";
}
return classes;
}
computeStateClass(stateObj) {
return stateMoreInfoType(stateObj) !== 'hidden' ? 'state more-info' : 'state';
return stateMoreInfoType(stateObj) !== "hidden"
? "state more-info"
: "state";
}
addTapEvents() {
const cards = this.root.querySelectorAll('.state');
const cards = this.root.querySelectorAll(".state");
cards.forEach((card) => {
if (card.classList.contains('more-info')) {
card.addEventListener('click', this.entityTapped);
if (card.classList.contains("more-info")) {
card.addEventListener("click", this.entityTapped);
} else {
card.removeEventListener('click', this.entityTapped);
card.removeEventListener("click", this.entityTapped);
}
});
}
entityTapped(ev) {
const item = this.root.querySelector('dom-repeat').itemForElement(ev.target);
const item = this.root
.querySelector("dom-repeat")
.itemForElement(ev.target);
let entityId;
if (!item && !this.groupEntity) {
return;
@@ -130,12 +135,16 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
} else {
entityId = this.groupEntity.entity_id;
}
this.fire('hass-more-info', { entityId: entityId });
this.fire("hass-more-info", { entityId: entityId });
}
showGroupToggle(groupEntity, states) {
if (!groupEntity || !states || groupEntity.attributes.control === 'hidden'
|| (groupEntity.state !== 'on' && groupEntity.state !== 'off')) {
if (
!groupEntity ||
!states ||
groupEntity.attributes.control === "hidden" ||
(groupEntity.state !== "on" && groupEntity.state !== "off")
) {
return false;
}
@@ -156,4 +165,4 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
return canToggleCount > 1;
}
}
customElements.define('ha-entities-card', HaEntitiesCard);
customElements.define("ha-entities-card", HaEntitiesCard);

View File

@@ -1,13 +1,12 @@
import '@polymer/paper-card/paper-card.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-card/paper-card.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/state-history-charts.js';
import '../data/ha-state-history-data.js';
import "../components/state-history-charts.js";
import "../data/ha-state-history-data";
import computeStateName from '../common/entity/compute_state_name.js';
import EventsMixin from '../mixins/events-mixin.js';
import computeStateName from "../common/entity/compute_state_name.js";
import EventsMixin from "../mixins/events-mixin.js";
/*
* @appliesMixin EventsMixin
@@ -55,7 +54,7 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
hass: Object,
stateObj: {
type: Object,
observer: 'stateObjObserver',
observer: "stateObjObserver",
},
inDialog: {
type: Boolean,
@@ -76,14 +75,19 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
stateObjObserver(stateObj) {
if (!stateObj) return;
if (this.cacheConfig.cacheKey !== stateObj.entity_id
|| this.cacheConfig.refresh !== (stateObj.attributes.refresh || 0)
|| this.cacheConfig.hoursToShow !== (stateObj.attributes.hours_to_show || 24)) {
this.cacheConfig = Object.assign({}, {
refresh: stateObj.attributes.refresh || 0,
cacheKey: stateObj.entity_id,
hoursToShow: stateObj.attributes.hours_to_show || 24
});
if (
this.cacheConfig.cacheKey !== stateObj.entity_id ||
this.cacheConfig.refresh !== (stateObj.attributes.refresh || 0) ||
this.cacheConfig.hoursToShow !== (stateObj.attributes.hours_to_show || 24)
) {
this.cacheConfig = Object.assign(
{},
{
refresh: stateObj.attributes.refresh || 0,
cacheKey: stateObj.entity_id,
hoursToShow: stateObj.attributes.hours_to_show || 24,
}
);
}
}
@@ -92,7 +96,7 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
}
computeContentClass(inDialog) {
return inDialog ? '' : 'content';
return inDialog ? "" : "content";
}
computeHistoryEntities(stateObj) {
@@ -104,11 +108,11 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
}
cardTapped(ev) {
const mq = window.matchMedia('(min-width: 610px) and (min-height: 550px)');
const mq = window.matchMedia("(min-width: 610px) and (min-height: 550px)");
if (mq.matches) {
ev.stopPropagation();
this.fire('hass-more-info', { entityId: this.stateObj.entity_id });
this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
}
}
}
customElements.define('ha-history_graph-card', HaHistoryGraphCard);
customElements.define("ha-history_graph-card", HaHistoryGraphCard);

View File

@@ -1,15 +1,15 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
import '@polymer/paper-icon-button/paper-icon-button.js';
import '@polymer/paper-progress/paper-progress.js';
import '@polymer/paper-styles/element-styles/paper-material-styles.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/iron-flex-layout/iron-flex-layout-classes.js";
import "@polymer/paper-icon-button/paper-icon-button.js";
import "@polymer/paper-progress/paper-progress.js";
import "@polymer/paper-styles/element-styles/paper-material-styles.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import HassMediaPlayerEntity from '../util/hass-media-player-model.js';
import HassMediaPlayerEntity from "../util/hass-media-player-model.js";
import computeStateName from '../common/entity/compute_state_name.js';
import EventsMixin from '../mixins/events-mixin.js';
import LocalizeMixin from '../mixins/localize-mixin.js';
import computeStateName from "../common/entity/compute_state_name.js";
import EventsMixin from "../mixins/events-mixin.js";
import LocalizeMixin from "../mixins/localize-mixin.js";
/*
* @appliesMixin LocalizeMixin
@@ -189,12 +189,12 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
stateObj: Object,
playerObj: {
type: Object,
computed: 'computePlayerObj(hass, stateObj)',
observer: 'playerObjChanged',
computed: "computePlayerObj(hass, stateObj)",
observer: "playerObjChanged",
},
playbackControlIcon: {
type: String,
computed: 'computePlaybackControlIcon(playerObj)',
computed: "computePlaybackControlIcon(playerObj)",
},
playbackPosition: Number,
};
@@ -203,7 +203,10 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
async playerObjChanged(playerObj, oldPlayerObj) {
if (playerObj.isPlaying && playerObj.showProgress) {
if (!this._positionTracking) {
this._positionTracking = setInterval(() => this.updatePlaybackPosition(), 1000);
this._positionTracking = setInterval(
() => this.updatePlaybackPosition(),
1000
);
}
} else if (this._positionTracking) {
clearInterval(this._positionTracking);
@@ -214,25 +217,27 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
}
const picture = playerObj.stateObj.attributes.entity_picture;
const oldPicture = oldPlayerObj && oldPlayerObj.stateObj.attributes.entity_picture;
const oldPicture =
oldPlayerObj && oldPlayerObj.stateObj.attributes.entity_picture;
if (picture !== oldPicture && !picture) {
this.$.cover.style.backgroundImage = '';
this.$.cover.style.backgroundImage = "";
return;
} if (picture === oldPicture) {
}
if (picture === oldPicture) {
return;
}
// We have a new picture url
try {
const { content_type: contentType, content } = await this.hass.callWS({
type: 'media_player_thumbnail',
type: "media_player_thumbnail",
entity_id: playerObj.stateObj.entity_id,
});
this.$.cover.style.backgroundImage = `url(data:${contentType};base64,${content})`;
} catch (err) {
this.$.cover.style.backgroundImage = '';
this.$.cover.parentElement.classList.add('no-cover');
this.$.cover.style.backgroundImage = "";
this.$.cover.parentElement.classList.add("no-cover");
}
}
@@ -241,14 +246,14 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
}
computeBannerClasses(playerObj) {
var cls = 'banner';
var cls = "banner";
if (playerObj.isOff || playerObj.isIdle) {
cls += ' is-off no-cover';
cls += " is-off no-cover";
} else if (!playerObj.stateObj.attributes.entity_picture) {
cls += ' no-cover';
} else if (playerObj.stateObj.attributes.media_content_type === 'music') {
cls += ' content-type-music';
cls += " no-cover";
} else if (playerObj.stateObj.attributes.media_content_type === "music") {
cls += " content-type-music";
}
return cls;
@@ -259,7 +264,9 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
}
computeHidePowerButton(playerObj) {
return playerObj.isOff ? !playerObj.supportsTurnOn : !playerObj.supportsTurnOff;
return playerObj.isOff
? !playerObj.supportsTurnOn
: !playerObj.supportsTurnOff;
}
computePlayerObj(hass, stateObj) {
@@ -267,21 +274,29 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
}
computePrimaryText(localize, playerObj) {
return playerObj.primaryTitle
|| localize(`state.media_player.${playerObj.stateObj.state}`)
|| localize(`state.default.${playerObj.stateObj.state}`) || playerObj.stateObj.state;
return (
playerObj.primaryTitle ||
localize(`state.media_player.${playerObj.stateObj.state}`) ||
localize(`state.default.${playerObj.stateObj.state}`) ||
playerObj.stateObj.state
);
}
computePlaybackControlIcon(playerObj) {
if (playerObj.isPlaying) {
return playerObj.supportsPause ? 'hass:pause' : 'hass:stop';
} if (playerObj.hasMediaControl || playerObj.isOff || playerObj.isIdle) {
if (playerObj.hasMediaControl && playerObj.supportsPause && !playerObj.isPaused) {
return 'hass:play-pause';
}
return playerObj.supportsPlay ? 'hass:play' : null;
return playerObj.supportsPause ? "hass:pause" : "hass:stop";
}
return '';
if (playerObj.hasMediaControl || playerObj.isOff || playerObj.isIdle) {
if (
playerObj.hasMediaControl &&
playerObj.supportsPause &&
!playerObj.isPaused
) {
return "hass:play-pause";
}
return playerObj.supportsPlay ? "hass:play" : null;
}
return "";
}
_computeStateName(stateObj) {
@@ -295,7 +310,7 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
handleOpenMoreInfo(ev) {
ev.stopPropagation();
this.fire('hass-more-info', { entityId: this.stateObj.entity_id });
this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
}
handlePlaybackControl(ev) {
@@ -313,4 +328,4 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
this.playerObj.togglePower();
}
}
customElements.define('ha-media_player-card', HaMediaPlayerCard);
customElements.define("ha-media_player-card", HaMediaPlayerCard);

View File

@@ -1,14 +1,13 @@
import '@polymer/paper-button/paper-button.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import "@polymer/paper-button/paper-button.js";
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/ha-card.js';
import '../components/ha-markdown.js';
import "../components/ha-card.js";
import "../components/ha-markdown.js";
import computeStateName from '../common/entity/compute_state_name.js';
import LocalizeMixin from '../mixins/localize-mixin.js';
import computeObjectId from '../common/entity/compute_object_id';
import computeStateName from "../common/entity/compute_state_name.js";
import LocalizeMixin from "../mixins/localize-mixin.js";
import computeObjectId from "../common/entity/compute_object_id";
/*
* @appliesMixin LocalizeMixin
@@ -60,15 +59,17 @@ class HaPersistentNotificationCard extends LocalizeMixin(PolymerElement) {
}
computeTitle(stateObj) {
return (stateObj.attributes.title
|| computeStateName(stateObj));
return stateObj.attributes.title || computeStateName(stateObj);
}
dismissTap(ev) {
ev.preventDefault();
this.hass.callService('persistent_notification', 'dismiss', {
notification_id: computeObjectId(this.stateObj.entity_id)
this.hass.callService("persistent_notification", "dismiss", {
notification_id: computeObjectId(this.stateObj.entity_id),
});
}
}
customElements.define('ha-persistent_notification-card', HaPersistentNotificationCard);
customElements.define(
"ha-persistent_notification-card",
HaPersistentNotificationCard
);

View File

@@ -1,11 +1,11 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/ha-card.js';
import '../components/ha-icon.js';
import "../components/ha-card.js";
import "../components/ha-icon.js";
import computeStateName from '../common/entity/compute_state_name.js';
import EventsMixin from '../mixins/events-mixin.js';
import computeStateName from "../common/entity/compute_state_name.js";
import EventsMixin from "../mixins/events-mixin.js";
class HaPlantCard extends EventsMixin(PolymerElement) {
static get template() {
@@ -85,18 +85,18 @@ class HaPlantCard extends EventsMixin(PolymerElement) {
static get properties() {
return {
hass: Object,
stateObj: Object
stateObj: Object,
};
}
constructor() {
super();
this.sensors = {
moisture: 'hass:water',
temperature: 'hass:thermometer',
brightness: 'hass:white-balance-sunny',
conductivity: 'hass:emoticon-poop',
battery: 'hass:battery'
moisture: "hass:water",
temperature: "hass:thermometer",
brightness: "hass:white-balance-sunny",
conductivity: "hass:emoticon-poop",
battery: "hass:battery",
};
}
@@ -105,16 +105,17 @@ class HaPlantCard extends EventsMixin(PolymerElement) {
}
computeAttributes(data) {
return Object.keys(this.sensors).filter(key => key in data);
return Object.keys(this.sensors).filter((key) => key in data);
}
computeIcon(attr, batLvl) {
const icon = this.sensors[attr];
if (attr === 'battery') {
if (attr === "battery") {
if (batLvl <= 5) {
return `${icon}-alert`;
} if (batLvl < 95) {
return `${icon}-${Math.round((batLvl / 10) - 0.01) * 10}`;
}
if (batLvl < 95) {
return `${icon}-${Math.round(batLvl / 10 - 0.01) * 10}`;
}
}
return icon;
@@ -125,20 +126,22 @@ class HaPlantCard extends EventsMixin(PolymerElement) {
}
computeUom(dict, attr) {
return dict[attr] || '';
return dict[attr] || "";
}
computeAttributeClass(problem, attr) {
return problem.indexOf(attr) === -1 ? '' : 'problem';
return problem.indexOf(attr) === -1 ? "" : "problem";
}
computeImageClass(entityPicture) {
return entityPicture ? 'has-plant-image' : '';
return entityPicture ? "has-plant-image" : "";
}
attributeClicked(ev) {
this.fire('hass-more-info', { entityId: this.stateObj.attributes.sensors[ev.model.item] });
this.fire("hass-more-info", {
entityId: this.stateObj.attributes.sensors[ev.model.item],
});
}
}
customElements.define('ha-plant-card', HaPlantCard);
customElements.define("ha-plant-card", HaPlantCard);

View File

@@ -1,17 +1,16 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
import '../components/ha-card.js';
import '../components/ha-icon.js';
import "../components/ha-card.js";
import "../components/ha-icon.js";
import EventsMixin from '../mixins/events-mixin.js';
import LocalizeMixin from '../mixins/localize-mixin.js';
import EventsMixin from "../mixins/events-mixin.js";
import LocalizeMixin from "../mixins/localize-mixin.js";
/*
* @appliesMixin LocalizeMixin
*/
class HaWeatherCard extends
LocalizeMixin(EventsMixin(PolymerElement)) {
class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
static get template() {
return html`
<style>
@@ -129,11 +128,11 @@ class HaWeatherCard extends
<template is="dom-repeat" items="[[forecast]]">
<div>
<div class="weekday">[[computeDate(item.datetime)]]<br>
<template is="dom-if" if="[[!item.templow]]">
<template is="dom-if" if="[[!_showValue(item.templow)]]">
[[computeTime(item.datetime)]]
</template>
</div>
<template is="dom-if" if="[[item.condition]]">
<template is="dom-if" if="[[_showValue(item.condition)]]">
<div class="icon">
<ha-icon icon="[[getWeatherIcon(item.condition)]]"></ha-icon>
</div>
@@ -160,42 +159,57 @@ class HaWeatherCard extends
stateObj: Object,
forecast: {
type: Array,
computed: 'computeForecast(stateObj.attributes.forecast)'
}
computed: "computeForecast(stateObj.attributes.forecast)",
},
};
}
constructor() {
super();
this.cardinalDirections = [
'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'
"N",
"NNE",
"NE",
"ENE",
"E",
"ESE",
"SE",
"SSE",
"S",
"SSW",
"SW",
"WSW",
"W",
"WNW",
"NW",
"NNW",
"N",
];
this.weatherIcons = {
'clear-night': 'hass:weather-night',
cloudy: 'hass:weather-cloudy',
fog: 'hass:weather-fog',
hail: 'hass:weather-hail',
lightning: 'mid:weather-lightning',
'lightning-rainy': 'hass:weather-lightning-rainy',
partlycloudy: 'hass:weather-partlycloudy',
pouring: 'hass:weather-pouring',
rainy: 'hass:weather-rainy',
snowy: 'hass:weather-snowy',
'snowy-rainy': 'hass:weather-snowy-rainy',
sunny: 'hass:weather-sunny',
windy: 'hass:weather-windy',
'windy-variant': 'hass:weather-windy-variant'
"clear-night": "hass:weather-night",
cloudy: "hass:weather-cloudy",
fog: "hass:weather-fog",
hail: "hass:weather-hail",
lightning: "hass:weather-lightning",
"lightning-rainy": "hass:weather-lightning-rainy",
partlycloudy: "hass:weather-partlycloudy",
pouring: "hass:weather-pouring",
rainy: "hass:weather-rainy",
snowy: "hass:weather-snowy",
"snowy-rainy": "hass:weather-snowy-rainy",
sunny: "hass:weather-sunny",
windy: "hass:weather-windy",
"windy-variant": "hass:weather-windy-variant",
};
}
ready() {
this.addEventListener('click', this._onClick);
this.addEventListener("click", this._onClick);
super.ready();
}
_onClick() {
this.fire('hass-more-info', { entityId: this.stateObj.entity_id });
this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
}
computeForecast(forecast) {
@@ -203,16 +217,16 @@ class HaWeatherCard extends
}
getUnit(measure) {
const lengthUnit = this.hass.config.unit_system.length || '';
const lengthUnit = this.hass.config.unit_system.length || "";
switch (measure) {
case 'air_pressure':
return lengthUnit === 'km' ? 'hPa' : 'inHg';
case 'length':
case "air_pressure":
return lengthUnit === "km" ? "hPa" : "inHg";
case "length":
return lengthUnit;
case 'precipitation':
return lengthUnit === 'km' ? 'mm' : 'in';
case "precipitation":
return lengthUnit === "km" ? "mm" : "in";
default:
return this.hass.config.unit_system[measure] || '';
return this.hass.config.unit_system[measure] || "";
}
}
@@ -239,20 +253,22 @@ class HaWeatherCard extends
getWind(speed, bearing, localize) {
if (bearing != null) {
const cardinalDirection = this.windBearingToText(bearing);
return `${speed} ${this.getUnit('length')}/h (${localize(`ui.card.weather.cardinal_direction.${cardinalDirection.toLowerCase()}`) || cardinalDirection})`;
return `${speed} ${this.getUnit("length")}/h (${localize(
`ui.card.weather.cardinal_direction.${cardinalDirection.toLowerCase()}`
) || cardinalDirection})`;
}
return `${speed} ${this.getUnit('length')}/h`;
return `${speed} ${this.getUnit("length")}/h`;
}
_showValue(item) {
return typeof item !== 'undefined' && item !== null;
return typeof item !== "undefined" && item !== null;
}
computeDate(data) {
const date = new Date(data);
return date.toLocaleDateString(
this.hass.selectedLanguage || this.hass.language,
{ weekday: 'short' }
{ weekday: "short" }
);
}
@@ -260,8 +276,8 @@ class HaWeatherCard extends
const date = new Date(data);
return date.toLocaleTimeString(
this.hass.selectedLanguage || this.hass.language,
{ hour: 'numeric' }
{ hour: "numeric" }
);
}
}
customElements.define('ha-weather-card', HaWeatherCard);
customElements.define("ha-weather-card", HaWeatherCard);

View File

@@ -1,13 +1,15 @@
/**
* Auth class that connects to a native app for authentication.
*/
import { Auth } from 'home-assistant-js-websocket';
import { Auth } from "home-assistant-js-websocket";
const CALLBACK_SET_TOKEN = 'externalAuthSetToken';
const CALLBACK_REVOKE_TOKEN = 'externalAuthRevokeToken';
const CALLBACK_SET_TOKEN = "externalAuthSetToken";
const CALLBACK_REVOKE_TOKEN = "externalAuthRevokeToken";
if (!window.externalApp && !window.webkit) {
throw new Error('External auth requires either externalApp or webkit defined on Window object.');
throw new Error(
"External auth requires either externalApp or webkit defined on Window object."
);
}
export default class ExternalAuth extends Auth {
@@ -16,7 +18,7 @@ export default class ExternalAuth extends Auth {
this.data = {
hassUrl,
access_token: '',
access_token: "",
// This will trigger connection to do a refresh right away
expires: 0,
};
@@ -24,7 +26,8 @@ export default class ExternalAuth extends Auth {
async refreshAccessToken() {
const responseProm = new Promise((resolve, reject) => {
window[CALLBACK_SET_TOKEN] = (success, data) => (success ? resolve(data) : reject(data));
window[CALLBACK_SET_TOKEN] = (success, data) =>
success ? resolve(data) : reject(data);
});
// Allow promise to set resolve on window object.
@@ -35,7 +38,9 @@ export default class ExternalAuth extends Auth {
if (window.externalApp) {
window.externalApp.getExternalAuth(callbackPayload);
} else {
window.webkit.messageHandlers.getExternalAuth.postMessage(callbackPayload);
window.webkit.messageHandlers.getExternalAuth.postMessage(
callbackPayload
);
}
// Response we expect back:
@@ -46,12 +51,13 @@ export default class ExternalAuth extends Auth {
const tokens = await responseProm;
this.data.access_token = tokens.access_token;
this.data.expires = (tokens.expires_in * 1000) + Date.now();
this.data.expires = tokens.expires_in * 1000 + Date.now();
}
async revoke() {
const responseProm = new Promise((resolve, reject) => {
window[CALLBACK_REVOKE_TOKEN] = (success, data) => (success ? resolve(data) : reject(data));
window[CALLBACK_REVOKE_TOKEN] = (success, data) =>
success ? resolve(data) : reject(data);
});
// Allow promise to set resolve on window object.
@@ -62,7 +68,9 @@ export default class ExternalAuth extends Auth {
if (window.externalApp) {
window.externalApp.revokeExternalAuth(callbackPayload);
} else {
window.webkit.messageHandlers.revokeExternalAuth.postMessage(callbackPayload);
window.webkit.messageHandlers.revokeExternalAuth.postMessage(
callbackPayload
);
}
await responseProm;

View File

@@ -10,7 +10,9 @@ if (!tokenCache) {
}
export function askWrite() {
return tokenCache.tokens !== undefined && tokenCache.writeEnabled === undefined;
return (
tokenCache.tokens !== undefined && tokenCache.writeEnabled === undefined
);
}
export function saveTokens(tokens) {
@@ -18,7 +20,7 @@ export function saveTokens(tokens) {
if (tokenCache.writeEnabled) {
try {
storage.hassTokens = JSON.stringify(tokens);
} catch (err) {} // eslint-disable-line
} catch (err) {} // eslint-disable-line
}
}

View File

@@ -0,0 +1,4 @@
/** Return if the displaymode is in standalone mode (PWA). */
export default function isPwa() {
return window.matchMedia("(display-mode: standalone)").matches;
}

View File

@@ -5,82 +5,80 @@
// Each constant should have a description what it is supposed to be used for.
/** Icon to use when no icon specified for domain. */
export const DEFAULT_DOMAIN_ICON = 'hass:bookmark';
export const DEFAULT_DOMAIN_ICON = "hass:bookmark";
/** Domains that have a state card. */
export const DOMAINS_WITH_CARD = [
'climate',
'cover',
'configurator',
'input_select',
'input_number',
'input_text',
'lock',
'media_player',
'scene',
'script',
'timer',
'vacuum',
'weblink',
"climate",
"cover",
"configurator",
"input_select",
"input_number",
"input_text",
"lock",
"media_player",
"scene",
"script",
"timer",
"vacuum",
"water_heater",
"weblink",
];
/** Domains with separate more info dialog. */
export const DOMAINS_WITH_MORE_INFO = [
'alarm_control_panel',
'automation',
'camera',
'climate',
'configurator',
'cover',
'fan',
'group',
'history_graph',
'input_datetime',
'light',
'lock',
'media_player',
'script',
'sun',
'updater',
'vacuum',
'weather'
"alarm_control_panel",
"automation",
"camera",
"climate",
"configurator",
"cover",
"fan",
"group",
"history_graph",
"input_datetime",
"light",
"lock",
"media_player",
"script",
"sun",
"updater",
"vacuum",
"water_heater",
"weather",
];
/** Domains that show no more info dialog. */
export const DOMAINS_HIDE_MORE_INFO = [
'input_number',
'input_select',
'input_text',
'scene',
'weblink'
"input_number",
"input_select",
"input_text",
"scene",
"weblink",
];
/** Domains that should have the history hidden in the more info dialog. */
export const DOMAINS_MORE_INFO_NO_HISTORY = [
'camera',
'configurator',
'history_graph',
'scene',
"camera",
"configurator",
"history_graph",
"scene",
];
/** States that we consider "off". */
export const STATES_OFF = [
'closed',
'locked',
'off'
];
export const STATES_OFF = ["closed", "locked", "off"];
/** Domains where we allow toggle in Lovelace. */
export const DOMAINS_TOGGLE = new Set([
'fan',
'input_boolean',
'light',
'switch'
"fan",
"input_boolean",
"light",
"switch",
]);
/** Temperature units. */
export const UNIT_C = '°C';
export const UNIT_F = '°F';
export const UNIT_C = "°C";
export const UNIT_F = "°F";
/** Entity ID of the default view. */
export const DEFAULT_VIEW_ENTITY_ID = 'group.default_view';
export const DEFAULT_VIEW_ENTITY_ID = "group.default_view";

View File

@@ -1,4 +1,4 @@
export default function durationToSeconds(duration) {
const parts = duration.split(':').map(Number);
return (parts[0] * 3600) + (parts[1] * 60) + parts[2];
const parts = duration.split(":").map(Number);
return parts[0] * 3600 + parts[1] * 60 + parts[2];
}

View File

@@ -1,21 +1,21 @@
import fecha from 'fecha';
import fecha from "fecha";
// Check for support of native locale string options
function toLocaleDateStringSupportsOptions() {
try {
new Date().toLocaleDateString('i');
new Date().toLocaleDateString("i");
} catch (e) {
return e.name === 'RangeError';
return e.name === "RangeError";
}
return false;
}
export default (toLocaleDateStringSupportsOptions()
? function (dateObj, locales) {
return dateObj.toLocaleDateString(
locales,
{ year: 'numeric', month: 'long', day: 'numeric' },
);
} : function (dateObj, locales) { // eslint-disable-line no-unused-vars
return fecha.format(dateObj, 'mediumDate');
});
? (dateObj, locales) =>
dateObj.toLocaleDateString(locales, {
year: "numeric",
month: "long",
day: "numeric",
})
: // eslint-disable-next-line no-unused-vars
(dateObj, locales) => fecha.format(dateObj, "mediumDate"));

View File

@@ -1,24 +1,23 @@
import fecha from 'fecha';
import fecha from "fecha";
// Check for support of native locale string options
function toLocaleStringSupportsOptions() {
try {
new Date().toLocaleString('i');
new Date().toLocaleString("i");
} catch (e) {
return e.name === 'RangeError';
return e.name === "RangeError";
}
return false;
}
export default (toLocaleStringSupportsOptions()
? function (dateObj, locales) {
return dateObj.toLocaleString(locales, {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: '2-digit',
});
} : function (dateObj, locales) { // eslint-disable-line no-unused-vars
return fecha.format(dateObj, 'haDateTime');
});
? (dateObj, locales) =>
dateObj.toLocaleString(locales, {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "2-digit",
})
: // eslint-disable-next-line no-unused-vars
(dateObj, locales) => fecha.format(dateObj, "haDateTime"));

View File

@@ -1,21 +1,20 @@
import fecha from 'fecha';
import fecha from "fecha";
// Check for support of native locale string options
function toLocaleTimeStringSupportsOptions() {
try {
new Date().toLocaleTimeString('i');
new Date().toLocaleTimeString("i");
} catch (e) {
return e.name === 'RangeError';
return e.name === "RangeError";
}
return false;
}
export default (toLocaleTimeStringSupportsOptions()
? function (dateObj, locales) {
return dateObj.toLocaleTimeString(
locales,
{ hour: 'numeric', minute: '2-digit' }
);
} : function (dateObj, locales) { // eslint-disable-line no-unused-vars
return fecha.format(dateObj, 'shortTime');
});
? (dateObj, locales) =>
dateObj.toLocaleTimeString(locales, {
hour: "numeric",
minute: "2-digit",
})
: // eslint-disable-next-line no-unused-vars
(dateObj, locales) => fecha.format(dateObj, "shortTime"));

View File

@@ -1,30 +1,33 @@
/** Calculate a string representing a date object as relative time from now.
*
* Example output: 5 minutes ago, in 3 days.
*/
const tests = [
60, 'second',
60, 'minute',
24, 'hour',
7, 'day',
];
*/
const tests = [60, "second", 60, "minute", 24, "hour", 7, "day"];
export default function relativeTime(dateObj, localize) {
let delta = (new Date() - dateObj) / 1000;
const tense = delta >= 0 ? 'past' : 'future';
const tense = delta >= 0 ? "past" : "future";
delta = Math.abs(delta);
for (let i = 0; i < tests.length; i += 2) {
if (delta < tests[i]) {
delta = Math.floor(delta);
const time = localize(`ui.components.relative_time.duration.${tests[i + 1]}`, 'count', delta);
return localize(`ui.components.relative_time.${tense}`, 'time', time);
const time = localize(
`ui.components.relative_time.duration.${tests[i + 1]}`,
"count",
delta
);
return localize(`ui.components.relative_time.${tense}`, "time", time);
}
delta /= tests[i];
}
delta = Math.floor(delta);
const time = localize('ui.components.relative_time.duration.week', 'count', delta);
return localize(`ui.components.relative_time.${tense}`, 'time', time);
const time = localize(
"ui.components.relative_time.duration.week",
"count",
delta
);
return localize(`ui.components.relative_time.${tense}`, "time", time);
}

View File

@@ -1,16 +1,18 @@
const leftPad = number => (number < 10 ? `0${number}` : number);
const leftPad = (number) => (number < 10 ? `0${number}` : number);
export default function secondsToDuration(d) {
const h = Math.floor(d / 3600);
const m = Math.floor((d % 3600) / 60);
const s = Math.floor(d % 3600 % 60);
const s = Math.floor((d % 3600) % 60);
if (h > 0) {
return `${h}:${leftPad(m)}:${leftPad(s)}`;
} if (m > 0) {
}
if (m > 0) {
return `${m}:${leftPad(s)}`;
} if (s > 0) {
return '' + s;
}
if (s > 0) {
return "" + s;
}
return null;
}

View File

@@ -5,21 +5,26 @@
* themes: HASS Theme information
* localTheme: selected theme.
* updateMeta: boolean if we should update the theme-color meta element.
*/
export default function applyThemesOnElement(element, themes, localTheme, updateMeta = false) {
*/
export default function applyThemesOnElement(
element,
themes,
localTheme,
updateMeta = false
) {
if (!element._themes) {
element._themes = {};
}
let themeName = themes.default_theme;
if (localTheme === 'default' || (localTheme && themes.themes[localTheme])) {
if (localTheme === "default" || (localTheme && themes.themes[localTheme])) {
themeName = localTheme;
}
const styles = Object.assign({}, element._themes);
if (themeName !== 'default') {
if (themeName !== "default") {
var theme = themes.themes[themeName];
Object.keys(theme).forEach((key) => {
var prefixedKey = '--' + key;
element._themes[prefixedKey] = '';
var prefixedKey = "--" + key;
element._themes[prefixedKey] = "";
styles[prefixedKey] = theme[key];
});
}
@@ -27,17 +32,18 @@ export default function applyThemesOnElement(element, themes, localTheme, update
element.updateStyles(styles);
} else if (window.ShadyCSS) {
// implement updateStyles() method of Polemer elements
window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */(element), styles);
window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */ (element), styles);
}
if (!updateMeta) return;
const meta = document.querySelector('meta[name=theme-color]');
const meta = document.querySelector("meta[name=theme-color]");
if (meta) {
if (!meta.hasAttribute('default-content')) {
meta.setAttribute('default-content', meta.getAttribute('content'));
if (!meta.hasAttribute("default-content")) {
meta.setAttribute("default-content", meta.getAttribute("content"));
}
const themeColor = styles['--primary-color'] || meta.getAttribute('default-content');
meta.setAttribute('content', themeColor);
const themeColor =
styles["--primary-color"] || meta.getAttribute("default-content");
meta.setAttribute("content", themeColor);
}
}

View File

@@ -43,15 +43,15 @@
* `node` on which to fire the event (HTMLElement, defaults to `this`).
* @return {Event} The new event that was fired.
*/
export default function fire(node, type, detail, options) {
export const fireEvent = (node, type, detail, options) => {
options = options || {};
detail = (detail === null || detail === undefined) ? {} : detail;
detail = detail === null || detail === undefined ? {} : detail;
const event = new Event(type, {
bubbles: options.bubbles === undefined ? true : options.bubbles,
cancelable: Boolean(options.cancelable),
composed: options.composed === undefined ? true : options.composed
composed: options.composed === undefined ? true : options.composed,
});
event.detail = detail;
node.dispatchEvent(event);
return event;
}
};

View File

@@ -3,10 +3,10 @@
function _load(tag, url, type) {
// This promise will be used by Promise.all to determine success or failure
return new Promise(function (resolve, reject) {
return new Promise(function(resolve, reject) {
const element = document.createElement(tag);
let attr = 'src';
let parent = 'body';
let attr = "src";
let parent = "body";
// Important success and error for the promise
element.onload = () => resolve(url);
@@ -14,17 +14,17 @@ function _load(tag, url, type) {
// Need to set different attributes depending on tag type
switch (tag) {
case 'script':
case "script":
element.async = true;
if (type) {
element.type = type;
}
break;
case 'link':
element.type = 'text/css';
element.rel = 'stylesheet';
attr = 'href';
parent = 'head';
case "link":
element.type = "text/css";
element.rel = "stylesheet";
attr = "href";
parent = "head";
}
// Inject into document to kick off loading
@@ -33,7 +33,7 @@ function _load(tag, url, type) {
});
}
export const loadCSS = url => _load('link', url);
export const loadJS = url => _load('script', url);
export const loadImg = url => _load('img', url);
export const loadModule = url => _load('script', url, 'module');
export const loadCSS = (url) => _load("link", url);
export const loadJS = (url) => _load("script", url);
export const loadImg = (url) => _load("img", url);
export const loadModule = (url) => _load("script", url, "module");

View File

@@ -16,7 +16,7 @@ export default function scrollToTarget(element, target) {
var easingFn = function easeOutQuad(t, b, c, d) {
/* eslint-disable no-param-reassign, space-infix-ops, no-mixed-operators */
t /= d;
return -c * t*(t-2) + b;
return -c * t * (t - 2) + b;
/* eslint-enable no-param-reassign, space-infix-ops, no-mixed-operators */
};
var animationId = Math.random();
@@ -31,8 +31,13 @@ export default function scrollToTarget(element, target) {
if (elapsedTime > duration) {
scroller.scrollTop = top;
} else if (element._currentAnimationId === animationId) {
scroller.scrollTop = easingFn(elapsedTime, currentScrollTop, deltaScrollTop, duration);
scroller.scrollTop = easingFn(
elapsedTime,
currentScrollTop,
deltaScrollTop,
duration
);
requestAnimationFrame(updateFrame.bind(element));
}
}).call(element);
}.call(element));
}

View File

@@ -1,18 +1,21 @@
import Leaflet from 'leaflet';
import Leaflet from "leaflet";
// Sets up a Leaflet map on the provided DOM element
export default function setupLeafletMap(mapElement) {
const map = Leaflet.map(mapElement);
const style = document.createElement('link');
style.setAttribute('href', '/static/images/leaflet/leaflet.css');
style.setAttribute('rel', 'stylesheet');
const style = document.createElement("link");
style.setAttribute("href", "/static/images/leaflet/leaflet.css");
style.setAttribute("rel", "stylesheet");
mapElement.parentNode.appendChild(style);
map.setView([51.505, -0.09], 13);
Leaflet.tileLayer(
`https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}${Leaflet.Browser.retina ? '@2x.png' : '.png'}`,
`https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}${
Leaflet.Browser.retina ? "@2x.png" : ".png"
}`,
{
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy; <a href="https://carto.com/attributions">CARTO</a>',
subdomains: "abcd",
minZoom: 0,
maxZoom: 20,
}

View File

@@ -1,2 +1,2 @@
/** An empty image which can be set as src of an img element. */
export default 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
export default "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";

View File

@@ -1,6 +1,9 @@
export default function attributeClassNames(stateObj, attributes) {
if (!stateObj) return '';
return attributes.map(function (attribute) {
return attribute in stateObj.attributes ? 'has-' + attribute : '';
}).filter(attr => attr !== '').join(' ');
if (!stateObj) return "";
return attributes
.map(function(attribute) {
return attribute in stateObj.attributes ? "has-" + attribute : "";
})
.filter((attr) => attr !== "")
.join(" ");
}

View File

@@ -1,49 +1,49 @@
/** Return an icon representing a binary sensor state. */
export default function binarySensorIcon(state) {
var activated = state.state && state.state === 'off';
var activated = state.state && state.state === "off";
switch (state.attributes.device_class) {
case 'battery':
return activated ? 'hass:battery' : 'hass:battery-outline';
case 'cold':
return activated ? 'hass:thermometer' : 'hass:snowflake';
case 'connectivity':
return activated ? 'hass:server-network-off' : 'hass:server-network';
case 'door':
return activated ? 'hass:door-closed' : 'hass:door-open';
case 'garage_door':
return activated ? 'hass:garage' : 'hass:garage-open';
case 'gas':
case 'power':
case 'problem':
case 'safety':
case 'smoke':
return activated ? 'hass:verified' : 'hass:alert';
case 'heat':
return activated ? 'hass:thermometer' : 'hass:fire';
case 'light':
return activated ? 'hass:brightness-5' : 'hass:brightness-7';
case 'lock':
return activated ? 'hass:lock' : 'hass:lock-open';
case 'moisture':
return activated ? 'hass:water-off' : 'hass:water';
case 'motion':
return activated ? 'hass:walk' : 'hass:run';
case 'occupancy':
return activated ? 'hass:home-outline' : 'hass:home';
case 'opening':
return activated ? 'hass:square' : 'hass:square-outline';
case 'plug':
return activated ? 'hass:power-plug-off' : 'hass:power-plug';
case 'presence':
return activated ? 'hass:home-outline' : 'hass:home';
case 'sound':
return activated ? 'hass:music-note-off' : 'hass:music-note';
case 'vibration':
return activated ? 'hass:crop-portrait' : 'hass:vibrate';
case 'window':
return activated ? 'hass:window-closed' : 'hass:window-open';
case "battery":
return activated ? "hass:battery" : "hass:battery-outline";
case "cold":
return activated ? "hass:thermometer" : "hass:snowflake";
case "connectivity":
return activated ? "hass:server-network-off" : "hass:server-network";
case "door":
return activated ? "hass:door-closed" : "hass:door-open";
case "garage_door":
return activated ? "hass:garage" : "hass:garage-open";
case "gas":
case "power":
case "problem":
case "safety":
case "smoke":
return activated ? "hass:verified" : "hass:alert";
case "heat":
return activated ? "hass:thermometer" : "hass:fire";
case "light":
return activated ? "hass:brightness-5" : "hass:brightness-7";
case "lock":
return activated ? "hass:lock" : "hass:lock-open";
case "moisture":
return activated ? "hass:water-off" : "hass:water";
case "motion":
return activated ? "hass:walk" : "hass:run";
case "occupancy":
return activated ? "hass:home-outline" : "hass:home";
case "opening":
return activated ? "hass:square" : "hass:square-outline";
case "plug":
return activated ? "hass:power-plug-off" : "hass:power-plug";
case "presence":
return activated ? "hass:home-outline" : "hass:home";
case "sound":
return activated ? "hass:music-note-off" : "hass:music-note";
case "vibration":
return activated ? "hass:crop-portrait" : "hass:vibrate";
case "window":
return activated ? "hass:window-closed" : "hass:window-open";
default:
return activated ? 'hass:radiobox-blank' : 'hass:checkbox-marked-circle';
return activated ? "hass:radiobox-blank" : "hass:checkbox-marked-circle";
}
}

View File

@@ -1,11 +1,14 @@
export default function canToggleDomain(hass, domain) {
const services = hass.services[domain];
if (!services) { return false; }
if (domain === 'lock') {
return 'lock' in services;
} if (domain === 'cover') {
return 'open_cover' in services;
if (!services) {
return false;
}
return 'turn_on' in services;
if (domain === "lock") {
return "lock" in services;
}
if (domain === "cover") {
return "open_cover" in services;
}
return "turn_on" in services;
}

View File

@@ -1,12 +1,12 @@
import canToggleDomain from './can_toggle_domain.js';
import computeStateDomain from './compute_state_domain.js';
import canToggleDomain from "./can_toggle_domain.js";
import computeStateDomain from "./compute_state_domain.js";
export default function canToggleState(hass, stateObj) {
const domain = computeStateDomain(stateObj);
if (domain === 'group') {
return stateObj.state === 'on' || stateObj.state === 'off';
if (domain === "group") {
return stateObj.state === "on" || stateObj.state === "off";
}
if (domain === 'climate') {
if (domain === "climate") {
return !!((stateObj.attributes || {}).supported_features & 4096);
}

Some files were not shown because too many files have changed in this diff Show More