mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-22 16:56:35 +00:00
Allow picking users (#2768)
* Allow picking users * Update ha-user-badge.ts
This commit is contained in:
parent
2d3d4db4dd
commit
c7796e9557
@ -6,7 +6,6 @@ import {
|
||||
PropertyValues,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
@ -14,27 +13,12 @@ import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import "./ha-icon";
|
||||
|
||||
import "../components/user/ha-user-badge";
|
||||
import isComponentLoaded from "../common/config/is_component_loaded";
|
||||
import { HomeAssistant, Panel } from "../types";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { DEFAULT_PANEL } from "../common/const";
|
||||
|
||||
const computeInitials = (name: string) => {
|
||||
if (!name) {
|
||||
return "user";
|
||||
}
|
||||
return (
|
||||
name
|
||||
.trim()
|
||||
// Split by space and take first 3 words
|
||||
.split(" ")
|
||||
.slice(0, 3)
|
||||
// Of each word, take first letter
|
||||
.map((s) => s.substr(0, 1))
|
||||
.join("")
|
||||
);
|
||||
};
|
||||
|
||||
const computeUrl = (urlPath) => `/${urlPath}`;
|
||||
|
||||
const computePanels = (hass: HomeAssistant) => {
|
||||
@ -93,22 +77,13 @@ class HaSidebar extends LitElement {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const initials = hass.user ? computeInitials(hass.user.name) : "";
|
||||
|
||||
return html`
|
||||
<app-toolbar>
|
||||
<div main-title>Home Assistant</div>
|
||||
${hass.user
|
||||
? html`
|
||||
<a
|
||||
href="/profile"
|
||||
class="${classMap({
|
||||
"profile-badge": true,
|
||||
long: initials.length > 2,
|
||||
})}"
|
||||
>
|
||||
<paper-ripple></paper-ripple>
|
||||
${initials}
|
||||
<a href="/profile">
|
||||
<ha-user-badge user=${hass.user}></ha-user-badge>
|
||||
</a>
|
||||
`
|
||||
: ""}
|
||||
@ -344,23 +319,6 @@ class HaSidebar extends LitElement {
|
||||
.dev-tools a {
|
||||
color: var(--sidebar-icon-color);
|
||||
}
|
||||
|
||||
.profile-badge {
|
||||
/* for ripple */
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 40px;
|
||||
line-height: 40px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
background-color: var(--light-primary-color);
|
||||
text-decoration: none;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.profile-badge.long {
|
||||
font-size: 80%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
77
src/components/user/ha-user-badge.ts
Normal file
77
src/components/user/ha-user-badge.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import {
|
||||
LitElement,
|
||||
TemplateResult,
|
||||
css,
|
||||
CSSResult,
|
||||
html,
|
||||
property,
|
||||
customElement,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import { User } from "../../data/auth";
|
||||
import { CurrentUser } from "../../types";
|
||||
|
||||
const computeInitials = (name: string) => {
|
||||
if (!name) {
|
||||
return "user";
|
||||
}
|
||||
return (
|
||||
name
|
||||
.trim()
|
||||
// Split by space and take first 3 words
|
||||
.split(" ")
|
||||
.slice(0, 3)
|
||||
// Of each word, take first letter
|
||||
.map((s) => s.substr(0, 1))
|
||||
.join("")
|
||||
);
|
||||
};
|
||||
|
||||
@customElement("ha-user-badge")
|
||||
class StateBadge extends LitElement {
|
||||
@property() public user?: User | CurrentUser;
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
const user = this.user;
|
||||
|
||||
const initials = user ? computeInitials(user.name) : "?";
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="${classMap({
|
||||
"profile-badge": true,
|
||||
long: initials.length > 2,
|
||||
})}"
|
||||
>
|
||||
${initials}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
.profile-badge {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
width: 40px;
|
||||
line-height: 40px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
background-color: var(--light-primary-color);
|
||||
text-decoration: none;
|
||||
color: var(--primary-text-color);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.profile-badge.long {
|
||||
font-size: 80%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-user-badge": StateBadge;
|
||||
}
|
||||
}
|
104
src/components/user/ha-user-picker.ts
Normal file
104
src/components/user/ha-user-picker.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import memoizeOne from "memoize-one";
|
||||
import {
|
||||
LitElement,
|
||||
TemplateResult,
|
||||
html,
|
||||
css,
|
||||
CSSResult,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { User, fetchUsers } from "../../data/auth";
|
||||
import compare from "../../common/string/compare";
|
||||
|
||||
class HaEntityPicker extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
@property() public label?: string;
|
||||
@property() public value?: string;
|
||||
@property() public users?: User[];
|
||||
|
||||
private _sortedUsers = memoizeOne((users?: User[]) => {
|
||||
if (!users || users.length === 1) {
|
||||
return users || [];
|
||||
}
|
||||
const sorted = [...users];
|
||||
sorted.sort((a, b) => compare(a.name, b.name));
|
||||
return sorted;
|
||||
});
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<paper-dropdown-menu-light .label=${this.label}>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected=${this._value}
|
||||
attr-for-selected="data-user-id"
|
||||
@iron-select=${this._userChanged}
|
||||
>
|
||||
<paper-icon-item data-user-id="">
|
||||
No user
|
||||
</paper-icon-item>
|
||||
${this._sortedUsers(this.users).map(
|
||||
(user) => html`
|
||||
<paper-icon-item data-user-id=${user.id}>
|
||||
<ha-user-badge .user=${user} slot="item-icon"></ha-user-badge>
|
||||
${user.name}
|
||||
</paper-icon-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu-light>
|
||||
`;
|
||||
}
|
||||
|
||||
private get _value() {
|
||||
return this.value || "";
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
if (this.users === undefined) {
|
||||
fetchUsers(this.hass!).then((users) => {
|
||||
this.users = users;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _userChanged(ev) {
|
||||
const newValue = ev.detail.item.dataset.userId;
|
||||
|
||||
if (newValue !== this._value) {
|
||||
this.value = ev.detail.value;
|
||||
setTimeout(() => {
|
||||
fireEvent(this, "value-changed", { value: newValue });
|
||||
fireEvent(this, "change");
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
:host {
|
||||
display: inline-block;
|
||||
}
|
||||
paper-dropdown-menu-light {
|
||||
display: block;
|
||||
}
|
||||
paper-listbox {
|
||||
min-width: 200px;
|
||||
}
|
||||
paper-icon-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-user-picker", HaEntityPicker);
|
@ -1,5 +1,26 @@
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
export interface AuthProvider {
|
||||
name: string;
|
||||
id: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface Credential {
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface User {
|
||||
id: string;
|
||||
name: string;
|
||||
is_owner: boolean;
|
||||
is_active: boolean;
|
||||
system_generated: boolean;
|
||||
group_ids: string[];
|
||||
credentials: Credential[];
|
||||
}
|
||||
|
||||
export const fetchUsers = async (hass: HomeAssistant) =>
|
||||
hass.callWS<User[]>({
|
||||
type: "config/auth/list",
|
||||
});
|
||||
|
@ -3,12 +3,17 @@ import {
|
||||
Connection,
|
||||
getCollection,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { User } from "../types";
|
||||
import { CurrentUser } from "../types";
|
||||
|
||||
export const userCollection = (conn: Connection) =>
|
||||
getCollection(conn, "_usr", () => getUser(conn) as Promise<User>, undefined);
|
||||
getCollection(
|
||||
conn,
|
||||
"_usr",
|
||||
() => getUser(conn) as Promise<CurrentUser>,
|
||||
undefined
|
||||
);
|
||||
|
||||
export const subscribeUser = (
|
||||
conn: Connection,
|
||||
onChange: (user: User) => void
|
||||
onChange: (user: CurrentUser) => void
|
||||
) => userCollection(conn).subscribe(onChange);
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
customElement,
|
||||
} from "lit-element";
|
||||
import "../components/ha-menu-button";
|
||||
import { haStyle } from "../resources/ha-style";
|
||||
import { haStyle } from "../resources/styles";
|
||||
|
||||
@customElement("hass-loading-screen")
|
||||
class HassLoadingScreen extends LitElement {
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
customElement,
|
||||
CSSResult,
|
||||
} from "lit-element";
|
||||
import { haStyle } from "../resources/ha-style";
|
||||
import { haStyle } from "../resources/styles";
|
||||
|
||||
@customElement("hass-subpage")
|
||||
class HassSubpage extends LitElement {
|
||||
|
@ -12,7 +12,7 @@ import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { AreaRegistryDetailDialogParams } from "./show-dialog-area-registry-detail";
|
||||
import { PolymerChangedEvent } from "../../../polymer-types";
|
||||
import { haStyleDialog } from "../../../resources/ha-style";
|
||||
import { haStyleDialog } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { AreaRegistryEntryMutableParams } from "../../../data/area_registry";
|
||||
|
||||
|
@ -21,7 +21,7 @@ import Automation from "../js/automation";
|
||||
import unmountPreact from "../../../common/preact/unmount";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
|
||||
import { haStyle } from "../../../resources/ha-style";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { AutomationEntity, AutomationConfig } from "../../../data/automation";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
|
@ -18,7 +18,7 @@ import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { WebhookDialogParams } from "./types";
|
||||
import { haStyle } from "../../../resources/ha-style";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
|
||||
const inputLabel = "Public URL – Click to copy to clipboard";
|
||||
|
||||
|
@ -12,7 +12,7 @@ import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { EntityRegistryDetailDialogParams } from "./show-dialog-entity-registry-detail";
|
||||
import { PolymerChangedEvent } from "../../../polymer-types";
|
||||
import { haStyleDialog } from "../../../resources/ha-style";
|
||||
import { haStyleDialog } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import computeDomain from "../../../common/entity/compute_domain";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
@ -9,29 +9,37 @@ import {
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@material/mwc-button";
|
||||
|
||||
import "../../../components/entity/ha-entities-picker";
|
||||
import "../../../components/user/ha-user-picker";
|
||||
import { PersonDetailDialogParams } from "./show-dialog-person-detail";
|
||||
import { PolymerChangedEvent } from "../../../polymer-types";
|
||||
import { haStyleDialog } from "../../../resources/ha-style";
|
||||
import { haStyleDialog } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { PersonMutableParams } from "../../../data/person";
|
||||
|
||||
class DialogPersonDetail extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
@property() private _name!: string;
|
||||
@property() private _userId?: string;
|
||||
@property() private _deviceTrackers!: string[];
|
||||
@property() private _error?: string;
|
||||
@property() private _params?: PersonDetailDialogParams;
|
||||
@property() private _submitting?: boolean;
|
||||
@property() private _submitting: boolean = false;
|
||||
|
||||
public async showDialog(params: PersonDetailDialogParams): Promise<void> {
|
||||
this._params = params;
|
||||
this._error = undefined;
|
||||
this._name = this._params.entry ? this._params.entry.name : "";
|
||||
this._deviceTrackers = this._params.entry
|
||||
? this._params.entry.device_trackers || []
|
||||
: [];
|
||||
if (this._params.entry) {
|
||||
this._name = this._params.entry.name || "";
|
||||
this._userId = this._params.entry.user_id || undefined;
|
||||
this._deviceTrackers = this._params.entry.device_trackers || [];
|
||||
} else {
|
||||
this._name = "";
|
||||
this._userId = undefined;
|
||||
this._deviceTrackers = [];
|
||||
}
|
||||
await this.updateComplete;
|
||||
}
|
||||
|
||||
@ -61,6 +69,13 @@ class DialogPersonDetail extends LitElement {
|
||||
error-message="Name is required"
|
||||
.invalid=${nameInvalid}
|
||||
></paper-input>
|
||||
<ha-user-picker
|
||||
label="Linked User"
|
||||
.hass=${this.hass}
|
||||
.value=${this._userId}
|
||||
.users=${this._params.users}
|
||||
@value-changed=${this._userChanged}
|
||||
></ha-user-picker>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.person.detail.device_tracker_intro"
|
||||
@ -108,6 +123,11 @@ class DialogPersonDetail extends LitElement {
|
||||
this._name = ev.detail.value;
|
||||
}
|
||||
|
||||
private _userChanged(ev: PolymerChangedEvent<string>) {
|
||||
this._error = undefined;
|
||||
this._userId = ev.detail.value;
|
||||
}
|
||||
|
||||
private _deviceTrackersChanged(ev: PolymerChangedEvent<string[]>) {
|
||||
this._error = undefined;
|
||||
this._deviceTrackers = ev.detail.value;
|
||||
@ -119,8 +139,7 @@ class DialogPersonDetail extends LitElement {
|
||||
const values: PersonMutableParams = {
|
||||
name: this._name.trim(),
|
||||
device_trackers: this._deviceTrackers,
|
||||
// Temp, we will add this in a future PR.
|
||||
user_id: null,
|
||||
user_id: this._userId || null,
|
||||
};
|
||||
if (this._params!.entry) {
|
||||
await this._params!.updateEntry(values);
|
||||
@ -129,7 +148,7 @@ class DialogPersonDetail extends LitElement {
|
||||
}
|
||||
this._params = undefined;
|
||||
} catch (err) {
|
||||
this._error = err;
|
||||
this._error = err ? err.message : "Unknown error";
|
||||
} finally {
|
||||
this._submitting = false;
|
||||
}
|
||||
@ -162,6 +181,9 @@ class DialogPersonDetail extends LitElement {
|
||||
.form {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
ha-user-picker {
|
||||
margin-top: 16px;
|
||||
}
|
||||
mwc-button.warning {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
@ -27,12 +27,14 @@ import {
|
||||
showPersonDetailDialog,
|
||||
loadPersonDetailDialog,
|
||||
} from "./show-dialog-person-detail";
|
||||
import { User, fetchUsers } from "../../../data/auth";
|
||||
|
||||
class HaConfigPerson extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public isWide?: boolean;
|
||||
private _storageItems?: Person[];
|
||||
private _configItems?: Person[];
|
||||
private _usersLoad?: Promise<User[]>;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
@ -62,7 +64,7 @@ class HaConfigPerson extends LitElement {
|
||||
${this._configItems.length > 0
|
||||
? html`
|
||||
<p>
|
||||
Note: people configured via configuration.yaml cannot be
|
||||
Note: persons configured via configuration.yaml cannot be
|
||||
edited via the UI.
|
||||
</p>
|
||||
`
|
||||
@ -81,7 +83,7 @@ class HaConfigPerson extends LitElement {
|
||||
${this._storageItems.length === 0
|
||||
? html`
|
||||
<div class="empty">
|
||||
Looks like you have no people yet!
|
||||
Looks like you have not created any persons yet.
|
||||
<mwc-button @click=${this._createPerson}>
|
||||
CREATE PERSON</mwc-button
|
||||
>
|
||||
@ -91,7 +93,7 @@ class HaConfigPerson extends LitElement {
|
||||
</paper-card>
|
||||
${this._configItems.length > 0
|
||||
? html`
|
||||
<paper-card heading="Configuration.yaml people">
|
||||
<paper-card heading="Configuration.yaml persons">
|
||||
${this._configItems.map((entry) => {
|
||||
return html`
|
||||
<paper-item>
|
||||
@ -123,6 +125,7 @@ class HaConfigPerson extends LitElement {
|
||||
}
|
||||
|
||||
private async _fetchData() {
|
||||
this._usersLoad = fetchUsers(this.hass!);
|
||||
const personData = await fetchPersons(this.hass!);
|
||||
|
||||
this._storageItems = personData.storage.sort((ent1, ent2) =>
|
||||
@ -142,9 +145,27 @@ class HaConfigPerson extends LitElement {
|
||||
this._openDialog(entry);
|
||||
}
|
||||
|
||||
private _openDialog(entry?: Person) {
|
||||
private _allowedUsers(users: User[], currentPerson?: Person) {
|
||||
const used = new Set();
|
||||
for (const coll of [this._configItems, this._storageItems]) {
|
||||
for (const pers of coll!) {
|
||||
if (pers.user_id) {
|
||||
used.add(pers.user_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
const currentUserId = currentPerson ? currentPerson.user_id : undefined;
|
||||
return users.filter(
|
||||
(user) => user.id === currentUserId || !used.has(user.id)
|
||||
);
|
||||
}
|
||||
|
||||
private async _openDialog(entry?: Person) {
|
||||
const users = await this._usersLoad!;
|
||||
|
||||
showPersonDetailDialog(this, {
|
||||
entry,
|
||||
users: this._allowedUsers(users, entry),
|
||||
createEntry: async (values) => {
|
||||
const created = await createPerson(this.hass!, values);
|
||||
this._storageItems = this._storageItems!.concat(created).sort(
|
||||
@ -191,6 +212,7 @@ All devices in this area will become unassigned.`)
|
||||
}
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
}
|
||||
paper-item {
|
||||
padding-top: 4px;
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { Person, PersonMutableParams } from "../../../data/person";
|
||||
import { User } from "../../../data/auth";
|
||||
|
||||
export interface PersonDetailDialogParams {
|
||||
entry?: Person;
|
||||
users: User[];
|
||||
createEntry: (values: PersonMutableParams) => Promise<unknown>;
|
||||
updateEntry: (updates: Partial<PersonMutableParams>) => Promise<unknown>;
|
||||
removeEntry: () => Promise<boolean>;
|
||||
|
@ -115,4 +115,4 @@ class HaUserPicker extends EventsMixin(
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("ha-user-picker", HaUserPicker);
|
||||
customElements.define("ha-config-user-picker", HaUserPicker);
|
@ -6,9 +6,10 @@ import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
|
||||
import NavigateMixin from "../../../mixins/navigate-mixin";
|
||||
|
||||
import "./ha-user-picker";
|
||||
import "./ha-config-user-picker";
|
||||
import "./ha-user-editor";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { fetchUsers } from "../../../data/auth";
|
||||
|
||||
/*
|
||||
* @appliesMixin NavigateMixin
|
||||
@ -23,7 +24,10 @@ class HaConfigUsers extends NavigateMixin(PolymerElement) {
|
||||
></app-route>
|
||||
|
||||
<template is="dom-if" if='[[_equals(_routeData.user, "picker")]]'>
|
||||
<ha-user-picker hass="[[hass]]" users="[[_users]]"></ha-user-picker>
|
||||
<ha-config-user-picker
|
||||
hass="[[hass]]"
|
||||
users="[[_users]]"
|
||||
></ha-config-user-picker>
|
||||
</template>
|
||||
<template
|
||||
is="dom-if"
|
||||
@ -93,9 +97,7 @@ class HaConfigUsers extends NavigateMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
async _loadData() {
|
||||
this._users = await this.hass.callWS({
|
||||
type: "config/auth/list",
|
||||
});
|
||||
this._users = await fetchUsers(this.hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { Cluster } from "../../../data/zha";
|
||||
import "../../../layouts/ha-app-layout";
|
||||
import { haStyle } from "../../../resources/ha-style";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ZHAClusterSelectedParams, ZHANodeSelectedParams } from "./types";
|
||||
import "./zha-cluster-attributes";
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
readAttributeValue,
|
||||
ZHADevice,
|
||||
} from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/ha-style";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import {
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
fetchCommandsForCluster,
|
||||
ZHADevice,
|
||||
} from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/ha-style";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import {
|
||||
|
@ -12,7 +12,7 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import { Cluster, fetchClustersForZhaNode, ZHADevice } from "../../../data/zha";
|
||||
import { haStyle } from "../../../resources/ha-style";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
|
@ -13,7 +13,7 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { haStyle } from "../../../resources/ha-style";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
import "../../../components/entity/state-badge";
|
||||
|
@ -11,7 +11,7 @@ import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import { haStyle } from "../../../resources/ha-style";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
|
||||
|
@ -15,7 +15,7 @@ import "@polymer/paper-listbox/paper-listbox";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import { haStyle } from "../../../resources/ha-style";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { ItemSelectedEvent, NodeServiceData } from "./types";
|
||||
|
@ -11,7 +11,7 @@ import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
|
||||
import { SystemLogDetailDialogParams } from "./show-dialog-system-log-detail";
|
||||
import { PolymerChangedEvent } from "../../polymer-types";
|
||||
import { haStyleDialog } from "../../resources/ha-style";
|
||||
import { haStyleDialog } from "../../resources/styles";
|
||||
|
||||
class DialogSystemLogDetail extends LitElement {
|
||||
private _params?: SystemLogDetailDialogParams;
|
||||
|
@ -12,7 +12,7 @@ import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "../../components/ha-menu-button";
|
||||
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { haStyle } from "../../resources/ha-style";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
|
||||
import "./system-log-card";
|
||||
import "./error-log-card";
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
|
||||
import { haStyleDialog } from "../../../../resources/ha-style";
|
||||
import { haStyleDialog } from "../../../../resources/styles";
|
||||
|
||||
import "./hui-card-picker";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import yaml from "js-yaml";
|
||||
|
||||
import { haStyleDialog } from "../../../../resources/ha-style";
|
||||
import { haStyleDialog } from "../../../../resources/styles";
|
||||
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
|
@ -14,7 +14,7 @@ import "@polymer/paper-dialog/paper-dialog";
|
||||
import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog";
|
||||
import "@material/mwc-button";
|
||||
|
||||
import { haStyleDialog } from "../../../resources/ha-style";
|
||||
import { haStyleDialog } from "../../../resources/styles";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
|
@ -14,7 +14,7 @@ import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
|
||||
import { haStyleDialog } from "../../../../resources/ha-style";
|
||||
import { haStyleDialog } from "../../../../resources/styles";
|
||||
|
||||
import "./hui-lovelace-editor";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
|
@ -18,7 +18,7 @@ import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
|
||||
import { haStyleDialog } from "../../../../resources/ha-style";
|
||||
import { haStyleDialog } from "../../../../resources/styles";
|
||||
|
||||
import "../../components/hui-entity-editor";
|
||||
import "./hui-view-editor";
|
||||
|
@ -13,7 +13,7 @@ import { struct } from "./common/structs/struct";
|
||||
import { Lovelace } from "./types";
|
||||
|
||||
import "../../components/ha-icon";
|
||||
import { haStyle } from "../../resources/ha-style";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import "./components/hui-yaml-editor";
|
||||
// This is not a duplicate import, one is for types, one is for element.
|
||||
// tslint:disable-next-line
|
||||
|
@ -48,7 +48,7 @@ import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog";
|
||||
import { showEditLovelaceDialog } from "./editor/lovelace-editor/show-edit-lovelace-dialog";
|
||||
import { Lovelace } from "./types";
|
||||
import { afterNextRender } from "../../common/util/render-status";
|
||||
import { haStyle } from "../../resources/ha-style";
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import { computeRTL, computeRTLDirection } from "../../common/util/compute_rtl";
|
||||
|
||||
// CSS and JS should only be imported once. Modules and HTML are safe.
|
||||
|
@ -1,93 +1,6 @@
|
||||
import "@polymer/paper-styles/paper-styles";
|
||||
import "@polymer/polymer/polymer-legacy";
|
||||
import { css } from "lit-element";
|
||||
|
||||
export const haStyle = css`
|
||||
:host {
|
||||
@apply --paper-font-body1;
|
||||
}
|
||||
|
||||
app-header-layout,
|
||||
ha-app-layout {
|
||||
background-color: var(--primary-background-color);
|
||||
}
|
||||
|
||||
app-header,
|
||||
app-toolbar {
|
||||
background-color: var(--primary-color);
|
||||
font-weight: 400;
|
||||
color: var(--text-primary-color, white);
|
||||
}
|
||||
|
||||
app-toolbar ha-menu-button + [main-title],
|
||||
app-toolbar paper-icon-button + [main-title] {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply --paper-font-title;
|
||||
}
|
||||
|
||||
button.link {
|
||||
background: none;
|
||||
color: inherit;
|
||||
border: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card-actions a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.card-actions .warning {
|
||||
--mdc-theme-primary: var(--google-red-500);
|
||||
}
|
||||
`;
|
||||
|
||||
export const haStyleDialog = css`
|
||||
/* prevent clipping of positioned elements */
|
||||
paper-dialog-scrollable {
|
||||
--paper-dialog-scrollable: {
|
||||
-webkit-overflow-scrolling: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* force smooth scrolling for iOS 10 */
|
||||
paper-dialog-scrollable.can-scroll {
|
||||
--paper-dialog-scrollable: {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-dialog-buttons {
|
||||
align-items: flex-end;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.paper-dialog-buttons .warning {
|
||||
--mdc-theme-primary: var(--google-red-500);
|
||||
}
|
||||
|
||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||
paper-dialog {
|
||||
margin: 0;
|
||||
width: 100% !important;
|
||||
max-height: calc(100% - 64px);
|
||||
|
||||
position: fixed !important;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
overflow: scroll;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
import { haStyle, haStyleDialog } from "./styles";
|
||||
|
||||
const documentContainer = document.createElement("template");
|
||||
documentContainer.setAttribute("style", "display: none;");
|
||||
|
88
src/resources/styles.ts
Normal file
88
src/resources/styles.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import { css } from "lit-element";
|
||||
|
||||
export const haStyle = css`
|
||||
:host {
|
||||
@apply --paper-font-body1;
|
||||
}
|
||||
|
||||
app-header-layout,
|
||||
ha-app-layout {
|
||||
background-color: var(--primary-background-color);
|
||||
}
|
||||
|
||||
app-header,
|
||||
app-toolbar {
|
||||
background-color: var(--primary-color);
|
||||
font-weight: 400;
|
||||
color: var(--text-primary-color, white);
|
||||
}
|
||||
|
||||
app-toolbar ha-menu-button + [main-title],
|
||||
app-toolbar paper-icon-button + [main-title] {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply --paper-font-title;
|
||||
}
|
||||
|
||||
button.link {
|
||||
background: none;
|
||||
color: inherit;
|
||||
border: none;
|
||||
padding: 0;
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card-actions a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.card-actions .warning {
|
||||
--mdc-theme-primary: var(--google-red-500);
|
||||
}
|
||||
`;
|
||||
|
||||
export const haStyleDialog = css`
|
||||
/* prevent clipping of positioned elements */
|
||||
paper-dialog-scrollable {
|
||||
--paper-dialog-scrollable: {
|
||||
-webkit-overflow-scrolling: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* force smooth scrolling for iOS 10 */
|
||||
paper-dialog-scrollable.can-scroll {
|
||||
--paper-dialog-scrollable: {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-dialog-buttons {
|
||||
align-items: flex-end;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.paper-dialog-buttons .warning {
|
||||
--mdc-theme-primary: var(--google-red-500);
|
||||
}
|
||||
|
||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||
paper-dialog {
|
||||
margin: 0;
|
||||
width: 100% !important;
|
||||
max-height: calc(100% - 64px);
|
||||
|
||||
position: fixed !important;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
overflow: scroll;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
}
|
||||
}
|
||||
`;
|
@ -54,7 +54,7 @@ export interface MFAModule {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface User {
|
||||
export interface CurrentUser {
|
||||
id: string;
|
||||
is_owner: boolean;
|
||||
name: string;
|
||||
@ -130,7 +130,7 @@ export interface HomeAssistant {
|
||||
|
||||
dockedSidebar: boolean;
|
||||
moreInfoEntityId: string;
|
||||
user: User;
|
||||
user: CurrentUser;
|
||||
callService: (
|
||||
domain: string,
|
||||
service: string,
|
||||
|
Loading…
x
Reference in New Issue
Block a user