20240603.0 (#20974)

This commit is contained in:
Bram Kragten 2024-06-03 18:56:01 +02:00 committed by GitHub
commit 52f3ff3306
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 638 additions and 335 deletions

View File

@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Send bundle stats and build information to RelativeCI
uses: relative-ci/agent-action@v2.1.10
uses: relative-ci/agent-action@v2.1.11
with:
key: ${{ secrets[format('RELATIVE_CI_KEY_{0}_{1}', matrix.bundle, matrix.build)] }}
token: ${{ github.token }}

View File

@ -19,15 +19,15 @@ export const mockLovelace = (
hass.mockWS("lovelace/resources", () => Promise.resolve([]));
};
customElements.whenDefined("hui-view").then(() => {
customElements.whenDefined("hui-card").then(() => {
// eslint-disable-next-line
const HUIView = customElements.get("hui-view");
const HUIView = customElements.get("hui-card");
// Patch HUI-VIEW to make the lovelace object available to the demo card
const oldCreateCard = HUIView!.prototype.createCardElement;
const oldCreateCard = HUIView!.prototype.createElement;
HUIView!.prototype.createCardElement = function (config) {
HUIView!.prototype.createElement = function (config) {
const el = oldCreateCard.call(this, config);
if (el.tagName === "HA-DEMO-CARD") {
if (config.type === "custom:ha-demo-card") {
(el as HADemoCard).lovelace = this.lovelace;
}
return el;

View File

@ -27,7 +27,7 @@
"dependencies": {
"@babel/runtime": "7.24.6",
"@braintree/sanitize-url": "7.0.2",
"@codemirror/autocomplete": "6.16.0",
"@codemirror/autocomplete": "6.16.2",
"@codemirror/commands": "6.5.0",
"@codemirror/language": "6.10.1",
"@codemirror/legacy-modes": "6.4.0",
@ -133,7 +133,7 @@
"tinykeys": "2.1.0",
"tsparticles-engine": "2.12.0",
"tsparticles-preset-links": "2.12.0",
"ua-parser-js": "1.0.37",
"ua-parser-js": "1.0.38",
"unfetch": "5.0.0",
"vis-data": "7.1.9",
"vis-network": "9.1.9",
@ -185,8 +185,8 @@
"@types/tar": "6.1.13",
"@types/ua-parser-js": "0.7.39",
"@types/webspeechapi": "0.0.29",
"@typescript-eslint/eslint-plugin": "7.10.0",
"@typescript-eslint/parser": "7.10.0",
"@typescript-eslint/eslint-plugin": "7.11.0",
"@typescript-eslint/parser": "7.11.0",
"@web/dev-server": "0.1.38",
"@web/dev-server-rollup": "0.4.1",
"babel-loader": "9.1.3",
@ -199,7 +199,7 @@
"eslint-config-prettier": "9.1.0",
"eslint-import-resolver-webpack": "0.13.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-lit": "1.13.0",
"eslint-plugin-lit": "1.14.0",
"eslint-plugin-lit-a11y": "4.1.2",
"eslint-plugin-unused-imports": "4.0.0",
"eslint-plugin-wc": "2.1.0",
@ -233,7 +233,7 @@
"sinon": "18.0.0",
"source-map-url": "0.4.1",
"systemjs": "6.15.1",
"tar": "7.1.0",
"tar": "7.2.0",
"terser-webpack-plugin": "5.3.10",
"transform-async-modules-webpack-plugin": "1.1.1",
"ts-lit-plugin": "2.0.2",
@ -244,7 +244,7 @@
"webpack-manifest-plugin": "5.0.0",
"webpack-stats-plugin": "1.1.3",
"webpackbar": "6.0.1",
"workbox-build": "7.1.0"
"workbox-build": "7.1.1"
},
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
"resolutions": {

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20240530.0"
version = "20240603.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"

View File

@ -198,8 +198,7 @@ export class HaIconPicker extends LitElement {
static get styles() {
return css`
ha-icon,
ha-svg-icon {
*[slot="icon"] {
color: var(--primary-text-color);
position: relative;
bottom: 2px;

View File

@ -48,7 +48,7 @@ class HaEntityMarker extends LitElement {
width: 48px;
height: 48px;
font-size: var(--ha-marker-font-size, 1.5em);
border-radius: 50%;
border-radius: var(--ha-marker-border-radius, 50%);
border: 1px solid var(--ha-marker-color, var(--primary-color));
color: var(--primary-text-color);
background-color: var(--card-background-color);

View File

@ -12,14 +12,6 @@ export interface RecorderInfo {
thread_running: boolean;
}
export interface RecordedEntities {
entity_ids: string[];
}
export interface RecordedExcludedEntities {
recorded_ids: string[];
excluded_ids: string[];
}
export type StatisticType = "change" | "state" | "sum" | "min" | "max" | "mean";
export interface Statistics {
@ -332,25 +324,3 @@ export const getDisplayUnit = (
export const isExternalStatistic = (statisticsId: string): boolean =>
statisticsId.includes(":");
let recordedExcludedEntitiesCache: RecordedExcludedEntities | undefined;
export const getRecordedExcludedEntities = async (
hass: HomeAssistant
): Promise<RecordedExcludedEntities> => {
if (recordedExcludedEntitiesCache) {
return recordedExcludedEntitiesCache;
}
const recordedEntities = await hass.callWS<RecordedEntities>({
type: "recorder/recorded_entities",
});
recordedExcludedEntitiesCache = {
recorded_ids: recordedEntities.entity_ids,
excluded_ids: Object.keys(hass.states).filter(
(id) => !recordedEntities.entity_ids.includes(id)
),
};
return recordedExcludedEntitiesCache;
};

View File

@ -756,6 +756,7 @@ export class HaVoiceCommandDialog extends LitElement {
max-height: 100%;
}
.message {
white-space: pre-line;
font-size: 18px;
clear: both;
margin: 8px 0;
@ -792,10 +793,14 @@ export class HaVoiceCommandDialog extends LitElement {
direction: var(--direction);
}
.message a {
.message.user a {
color: var(--text-primary-color);
}
.message.hass a {
color: var(--primary-text-color);
}
.message img {
width: 100%;
border-radius: 10px;

View File

@ -145,6 +145,14 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
@state() private _filteredAutomations?: string[] | null;
@storage({
storage: "sessionStorage",
key: "automation-table-search",
state: true,
subscribe: false,
})
private _filter = "";
@storage({
storage: "sessionStorage",
key: "automation-table-filters-full",
@ -547,6 +555,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
"ui.panel.config.automation.picker.no_automations"
)}
@clear-filter=${this._clearFilter}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
hasFab
clickable
class=${this.narrow ? "narrow" : ""}
@ -924,6 +934,10 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
this._applyFilters();
};
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
private _filterChanged(ev) {
const type = ev.target.localName;
this._filters = { ...this._filters, [type]: ev.detail };

View File

@ -107,6 +107,14 @@ class HaBlueprintOverview extends LitElement {
})
private _activeCollapsed?: string;
@storage({
storage: "sessionStorage",
key: "blueprint-table-search",
state: true,
subscribe: false,
})
private _filter: string = "";
private _processedBlueprints = memoizeOne(
(
blueprints: Record<string, Blueprints>,
@ -308,6 +316,8 @@ class HaBlueprintOverview extends LitElement {
@sorting-changed=${this._handleSortingChanged}
@grouping-changed=${this._handleGroupingChanged}
@collapsed-changed=${this._handleCollapseChanged}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
>
<ha-icon-button
slot="toolbar-icon"
@ -542,6 +552,10 @@ class HaBlueprintOverview extends LitElement {
this._activeCollapsed = ev.detail.value;
}
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
static get styles(): CSSResultGroup {
return haStyle;
}

View File

@ -122,7 +122,13 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
@state() private _selected: string[] = [];
@state() private _filter: string = history.state?.filter || "";
@storage({
storage: "sessionStorage",
key: "devices-table-search",
state: true,
subscribe: false,
})
private _filter: string = history.state?.filter || "";
@storage({
storage: "sessionStorage",
@ -199,38 +205,33 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
}
private _setFiltersFromUrl() {
if (this._searchParms.has("domain")) {
this._filters = {
...this._filters,
"ha-filter-states": {
value: [
...((this._filters["ha-filter-states"]?.value as string[]) || []),
"disabled",
],
items: undefined,
},
"ha-filter-integrations": {
value: [this._searchParms.get("domain")!],
items: undefined,
},
};
}
if (this._searchParms.has("config_entry")) {
this._filters = {
...this._filters,
"ha-filter-states": {
value: [
...((this._filters["ha-filter-states"]?.value as string[]) || []),
"disabled",
],
items: undefined,
},
config_entry: {
value: [this._searchParms.get("config_entry")!],
items: undefined,
},
};
const domain = this._searchParms.get("domain");
const configEntry = this._searchParms.get("config_entry");
if (!domain && !configEntry) {
return;
}
this._filter = history.state?.filter || "";
this._filters = {
"ha-filter-states": {
value: [
...((this._filters["ha-filter-states"]?.value as string[]) || []),
"disabled",
],
items: undefined,
},
"ha-filter-integrations": {
value: domain ? [domain] : [],
items: undefined,
},
config_entry: {
value: configEntry ? [configEntry] : [],
items: undefined,
},
};
if (this._searchParms.has("label")) {
this._filterLabel();
}

View File

@ -144,7 +144,13 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
@consume({ context: fullEntitiesContext, subscribe: true })
_entities!: EntityRegistryEntry[];
@state() private _filter: string = history.state?.filter || "";
@storage({
storage: "sessionStorage",
key: "entities-table-search",
state: true,
subscribe: false,
})
private _filter: string = history.state?.filter || "";
@state() private _searchParms = new URLSearchParams(window.location.search);
@ -703,7 +709,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
)
).length
}
.filter=${this._filter}
selectable
.selected=${this._selected.length}
.initialGroupColumn=${this._activeGrouping}
@ -715,6 +720,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
@selection-changed=${this._handleSelectionChanged}
clickable
@clear-filter=${this._clearFilter}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
@row-click=${this._openEditEntry}
id="entity_id"
@ -943,6 +949,7 @@ ${
}
protected firstUpdated() {
this._setFiltersFromUrl();
if (Object.keys(this._filters).length) {
return;
}
@ -952,39 +959,36 @@ ${
items: undefined,
},
};
this._setFiltersFromUrl();
fetchEntitySourcesWithCache(this.hass).then((sources) => {
this._entitySources = sources;
});
}
private _setFiltersFromUrl() {
if (this._searchParms.has("domain")) {
this._filters = {
...this._filters,
"ha-filter-states": {
value: [],
items: undefined,
},
"ha-filter-integrations": {
value: [this._searchParms.get("domain")!],
items: undefined,
},
};
}
if (this._searchParms.has("config_entry")) {
this._filters = {
...this._filters,
"ha-filter-states": {
value: [],
items: undefined,
},
config_entry: {
value: [this._searchParms.get("config_entry")!],
items: undefined,
},
};
const domain = this._searchParms.get("domain");
const configEntry = this._searchParms.get("config_entry");
if (!domain && !configEntry) {
return;
}
this._filter = history.state?.filter || "";
this._filters = {
"ha-filter-states": {
value: [],
items: undefined,
},
"ha-filter-integrations": {
value: domain ? [domain] : [],
items: undefined,
},
config_entry: {
value: configEntry ? [configEntry] : [],
items: undefined,
},
};
if (this._searchParms.has("label")) {
this._filterLabel();
}

View File

@ -159,6 +159,14 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
})
private _activeCollapsed?: string;
@storage({
storage: "sessionStorage",
key: "helpers-table-search",
state: true,
subscribe: false,
})
private _filter = "";
@state() private _stateItems: HassEntity[] = [];
@state() private _entityEntries?: Record<string, EntityRegistryEntry>;
@ -559,6 +567,8 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
.activeFilters=${this._activeFilters}
@clear-filter=${this._clearFilter}
@row-click=${this._openEditDialog}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
hasFab
clickable
.noDataText=${this.hass.localize(
@ -1070,6 +1080,10 @@ ${rejected
this._activeCollapsed = ev.detail.value;
}
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@ -453,7 +453,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
const attention = ATTENTION_SOURCES.includes(
flow.context.source
);
return html`<ha-list-item-new
return html` <ha-list-item-new
class="config_entry ${attention ? "attention" : ""}"
>
${flow.localized_title}
@ -477,8 +477,15 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
></ha-button>
</ha-list-item-new>`;
})}
${attentionEntries.map((item) =>
this._renderConfigEntry(item)
${attentionEntries.map(
(item, index) =>
html`${this._renderConfigEntry(item)}
${index < attentionEntries.length - 1
? html` <md-divider
role="separator"
tabindex="-1"
></md-divider>`
: ""} `
)}
</ha-list-new>
</ha-card>`
@ -502,7 +509,16 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
</div>`
: nothing}
<ha-list-new>
${normalEntries.map((item) => this._renderConfigEntry(item))}
${normalEntries.map(
(item, index) =>
html`${this._renderConfigEntry(item)}
${index < normalEntries.length - 1
? html` <md-divider
role="separator"
tabindex="-1"
></md-divider>`
: ""} `
)}
</ha-list-new>
<div class="card-actions">
<ha-button @click=${this._addIntegration}>
@ -667,19 +683,21 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
const configPanel = this._configPanel(item.domain, this.hass.panels);
return html`<ha-list-item-new
return html` <ha-list-item-new
class=${classMap({
config_entry: true,
"state-not-loaded": item!.state === "not_loaded",
"state-failed-unload": item!.state === "failed_unload",
"state-setup": item!.state === "setup_in_progress",
"state-error": ERROR_STATES.includes(item!.state),
"state-disabled": item.disabled_by !== null,
})}
data-entry-id=${item.entry_id}
.disabled=${item.disabled_by}
.configEntry=${item}
>
${item.title || domainToName(this.hass.localize, item.domain)}
<div slot="headline">
${item.title || domainToName(this.hass.localize, item.domain)}
</div>
<div slot="supporting-text">
<div>${devicesLine}</div>
${stateText
@ -726,67 +744,62 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
.path=${mdiDotsVertical}
></ha-icon-button>
${item.supports_options && stateText
? html`<ha-list-item
@request-selected=${this._showOptions}
graphic="icon"
>
<ha-svg-icon slot="graphic" .path=${mdiCog}></ha-svg-icon>
? html`<ha-menu-item @click=${this._showOptions}>
<ha-svg-icon slot="start" .path=${mdiCog}></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.integrations.config_entry.configure"
)}
</ha-list-item>`
</ha-menu-item>`
: ""}
${item.disabled_by && devices.length
? html`<a
href=${devices.length === 1
? `/config/devices/device/${devices[0].id}`
: `/config/devices/dashboard?historyBack=1&config_entry=${item.entry_id}`}
>
<ha-list-item hasMeta graphic="icon">
<ha-svg-icon .path=${mdiDevices} slot="graphic"></ha-svg-icon>
? html`
<ha-menu-item
.href=${devices.length === 1
? `/config/devices/device/${devices[0].id}`
: `/config/devices/dashboard?historyBack=1&config_entry=${item.entry_id}`}
>
<ha-svg-icon .path=${mdiDevices} slot="start"></ha-svg-icon>
${this.hass.localize(
`ui.panel.config.integrations.config_entry.devices`,
{ count: devices.length }
)}
<ha-icon-next slot="meta"></ha-icon-next>
</ha-list-item>
</a>`
<ha-icon-next slot="end"></ha-icon-next>
</ha-menu-item>
`
: ""}
${item.disabled_by && services.length
? html`<a
href=${services.length === 1
? html`<ha-menu-item
.href=${services.length === 1
? `/config/devices/device/${services[0].id}`
: `/config/devices/dashboard?historyBack=1&config_entry=${item.entry_id}`}
>
<ha-list-item hasMeta graphic="icon">
<ha-svg-icon
.path=${mdiHandExtendedOutline}
slot="graphic"
></ha-svg-icon>
${this.hass.localize(
`ui.panel.config.integrations.config_entry.services`,
{ count: services.length }
)}
<ha-icon-next slot="meta"></ha-icon-next>
</ha-list-item>
</a>`
<ha-svg-icon
.path=${mdiHandExtendedOutline}
slot="start"
></ha-svg-icon>
${this.hass.localize(
`ui.panel.config.integrations.config_entry.services`,
{ count: services.length }
)}
<ha-icon-next slot="end"></ha-icon-next>
</ha-menu-item> `
: ""}
${item.disabled_by && entities.length
? html`<a
href=${`/config/entities?historyBack=1&config_entry=${item.entry_id}`}
>
<ha-list-item hasMeta graphic="icon">
? html`
<ha-menu-item
.href=${`/config/entities?historyBack=1&config_entry=${item.entry_id}`}
>
<ha-svg-icon
.path=${mdiShapeOutline}
slot="graphic"
slot="start"
></ha-svg-icon>
${this.hass.localize(
`ui.panel.config.integrations.config_entry.entities`,
{ count: entities.length }
)}
<ha-icon-next slot="meta"></ha-icon-next>
</ha-list-item>
</a>`
<ha-icon-next slot="end"></ha-icon-next>
</ha-menu-item>
`
: ""}
${!item.disabled_by &&
RECOVERABLE_STATES.includes(item.state) &&
@ -814,7 +827,7 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
${this._diagnosticHandler && item.state === "loaded"
? html`
<ha-menu-item
href=${getConfigEntryDiagnosticsDownloadUrl(item.entry_id)}
.href=${getConfigEntryDiagnosticsDownloadUrl(item.entry_id)}
target="_blank"
@click=${this._signUrl}
>
@ -1402,18 +1415,8 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
margin-top: 16px;
}
ha-list-item-new.discovered {
--mdc-list-item-meta-size: auto;
--mdc-list-item-meta-display: flex;
height: 72px;
}
ha-list-item-new.config_entry {
overflow: visible;
--mdc-list-item-meta-size: auto;
--mdc-list-item-meta-display: flex;
}
ha-button-menu-new ha-menu-item {
--mdc-icon-size: 24px;
}
ha-list-item-new.config_entry::after {
position: absolute;
top: 8px;
@ -1424,9 +1427,6 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
pointer-events: none;
content: "";
}
ha-button-menu-new {
flex: 0;
}
a {
text-decoration: none;
}
@ -1483,6 +1483,10 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) {
overflow: hidden;
text-overflow: ellipsis;
}
.state-disabled [slot="headline"],
.state-disabled [slot="supporting-text"] {
opacity: var(--md-list-item-disabled-opacity, 0.3);
}
ha-list-new {
margin-top: 8px;
margin-bottom: 8px;

View File

@ -51,6 +51,14 @@ export class HaConfigLabels extends LitElement {
@state() private _labels: LabelRegistryEntry[] = [];
@storage({
storage: "sessionStorage",
key: "labels-table-search",
state: true,
subscribe: false,
})
private _filter = "";
@storage({
key: "labels-table-sort",
state: false,
@ -160,6 +168,8 @@ export class HaConfigLabels extends LitElement {
hasFab
.initialSorting=${this._activeSorting}
@sorting-changed=${this._handleSortingChanged}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
@row-click=${this._editLabel}
clickable
id="label_id"
@ -283,6 +293,10 @@ export class HaConfigLabels extends LitElement {
private _handleSortingChanged(ev: CustomEvent) {
this._activeSorting = ev.detail;
}
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
}
declare global {

View File

@ -70,6 +70,14 @@ export class HaConfigLovelaceDashboards extends LitElement {
@state() private _dashboards: LovelaceDashboard[] = [];
@storage({
storage: "sessionStorage",
key: "lovelace-dashboards-table-search",
state: true,
subscribe: false,
})
private _filter: string = "";
@storage({
key: "lovelace-dashboards-table-sort",
state: false,
@ -304,6 +312,8 @@ export class HaConfigLovelaceDashboards extends LitElement {
.data=${this._getItems(this._dashboards)}
.initialSorting=${this._activeSorting}
@sorting-changed=${this._handleSortingChanged}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
@row-click=${this._editDashboard}
id="url_path"
hasFab
@ -453,6 +463,10 @@ export class HaConfigLovelaceDashboards extends LitElement {
private _handleSortingChanged(ev: CustomEvent) {
this._activeSorting = ev.detail;
}
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
}
declare global {

View File

@ -52,6 +52,14 @@ export class HaConfigLovelaceRescources extends LitElement {
@state() private _resources: LovelaceResource[] = [];
@storage({
storage: "sessionStorage",
key: "lovelace-resources-table-search",
state: true,
subscribe: false,
})
private _filter = "";
@storage({
key: "lovelace-resources-table-sort",
state: false,
@ -138,6 +146,8 @@ export class HaConfigLovelaceRescources extends LitElement {
)}
.initialSorting=${this._activeSorting}
@sorting-changed=${this._handleSortingChanged}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
@row-click=${this._editResource}
hasFab
clickable
@ -252,6 +262,10 @@ export class HaConfigLovelaceRescources extends LitElement {
this._activeSorting = ev.detail;
}
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@ -137,6 +137,14 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
@state() private _filteredScenes?: string[] | null;
@storage({
storage: "sessionStorage",
key: "scene-table-search",
state: true,
subscribe: false,
})
private _filter = "";
@storage({
storage: "sessionStorage",
key: "scene-table-filters-full",
@ -543,6 +551,8 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
"ui.panel.config.scene.picker.no_scenes"
)}
@clear-filter=${this._clearFilter}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
hasFab
clickable
@row-click=${this._handleRowClicked}
@ -1141,6 +1151,10 @@ ${rejected
this._activeCollapsed = ev.detail.value;
}
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@ -141,6 +141,14 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
@state() private _filteredScripts?: string[] | null;
@storage({
storage: "sessionStorage",
key: "script-table-search",
state: true,
subscribe: false,
})
private _filter = "";
@storage({
storage: "sessionStorage",
key: "script-table-filters-full",
@ -558,6 +566,8 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
"ui.panel.config.script.picker.no_scripts"
)}
@clear-filter=${this._clearFilter}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
hasFab
clickable
class=${this.narrow ? "narrow" : ""}
@ -800,6 +810,10 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
`;
}
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
private _filterExpanded(ev) {
if (ev.detail.expanded) {
this._expandedFilter = ev.target.localName;

View File

@ -35,6 +35,7 @@ import { documentationUrl } from "../../../util/documentation-url";
import { configSections } from "../ha-panel-config";
import { showTagDetailDialog } from "./show-dialog-tag-detail";
import "./tag-image";
import { storage } from "../../../common/decorators/storage";
export interface TagRowData extends Tag {
display_name: string;
@ -57,6 +58,14 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
return this.hass.auth.external?.config.canWriteTag;
}
@storage({
storage: "sessionStorage",
key: "tags-table-search",
state: true,
subscribe: false,
})
private _filter = "";
private _columns = memoizeOne(
(narrow: boolean, _language, localize: LocalizeFunc) => {
const columns: DataTableColumnContainer<TagRowData> = {
@ -189,6 +198,8 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
)}
.data=${this._data(this._tags)}
.noDataText=${this.hass.localize("ui.panel.config.tag.no_tags")}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
hasFab
>
<ha-icon-button
@ -323,6 +334,10 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
return false;
}
}
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
}
declare global {

View File

@ -46,6 +46,14 @@ export class HaConfigUsers extends LitElement {
@storage({ key: "users-table-grouping", state: false, subscribe: false })
private _activeGrouping?: string;
@storage({
storage: "sessionStorage",
key: "users-table-search",
state: true,
subscribe: false,
})
private _filter = "";
@storage({
key: "users-table-collapsed",
state: false,
@ -184,6 +192,8 @@ export class HaConfigUsers extends LitElement {
@sorting-changed=${this._handleSortingChanged}
@grouping-changed=${this._handleGroupingChanged}
@collapsed-changed=${this._handleCollapseChanged}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
@row-click=${this._editUser}
hasFab
clickable
@ -283,6 +293,10 @@ export class HaConfigUsers extends LitElement {
private _handleCollapseChanged(ev: CustomEvent) {
this._activeCollapsed = ev.detail.value;
}
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
}
declare global {

View File

@ -80,7 +80,13 @@ export class VoiceAssistantsExpose extends LitElement {
@state() private _extEntities?: Record<string, ExtEntityRegistryEntry>;
@state() private _filter: string = history.state?.filter || "";
@storage({
storage: "sessionStorage",
key: "voice-expose-table-search",
state: true,
subscribe: false,
})
private _filter = "";
@state() private _searchParms = new URLSearchParams(window.location.search);
@ -634,7 +640,6 @@ export class VoiceAssistantsExpose extends LitElement {
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
history.replaceState({ filter: this._filter }, "");
}
private _handleSelectionChanged(

View File

@ -6,7 +6,6 @@ import {
} from "@mdi/js";
import { ActionDetail } from "@material/mwc-list";
import { differenceInHours } from "date-fns";
import { HassEntity } from "home-assistant-js-websocket";
import {
HassServiceTarget,
UnsubscribeFunc,
@ -46,11 +45,7 @@ import {
computeHistory,
subscribeHistory,
} from "../../data/history";
import {
fetchStatistics,
Statistics,
getRecordedExcludedEntities,
} from "../../data/recorder";
import { Statistics, fetchStatistics } from "../../data/recorder";
import {
expandAreaTarget,
expandDeviceTarget,
@ -100,8 +95,6 @@ class HaPanelHistory extends LitElement {
private _interval?: number;
private _excludedEntities?: string[];
public constructor() {
super();
@ -192,7 +185,6 @@ class HaPanelHistory extends LitElement {
.hass=${this.hass}
.value=${this._targetPickerValue}
.disabled=${this._isLoading}
.entityFilter=${this._entityFilter}
addOnTop
@value-changed=${this._targetsChanged}
></ha-target-picker>
@ -219,10 +211,6 @@ class HaPanelHistory extends LitElement {
`;
}
private _entityFilter = (entity: HassEntity): boolean =>
!this._excludedEntities ||
!this._excludedEntities.includes(entity.entity_id);
private mergeHistoryResults(
ltsResult: HistoryResult,
historyResult: HistoryResult
@ -374,17 +362,8 @@ class HaPanelHistory extends LitElement {
}
}
private async _getRecordedExcludedEntities() {
const { recorded_ids: _recordedIds, excluded_ids: excludedIds } =
await getRecordedExcludedEntities(this.hass);
this._excludedEntities = excludedIds;
}
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
this._getRecordedExcludedEntities();
const searchParams = extractSearchParamsObject();
if (searchParams.back === "1" && history.length > 1) {
this._showBack = true;

View File

@ -12,11 +12,19 @@ import {
import { createCardElement } from "../create-element/create-card-element";
import type { Lovelace, LovelaceCard, LovelaceLayoutOptions } from "../types";
declare global {
interface HASSDomEvents {
"card-visibility-changed": { value: boolean };
}
}
@customElement("hui-card")
export class HuiCard extends ReactiveElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public lovelace!: Lovelace;
@property({ attribute: false }) public lovelace?: Lovelace;
@property({ attribute: false }) public isPanel = false;
@state() public _config?: LovelaceCardConfig;
@ -59,14 +67,25 @@ export class HuiCard extends ReactiveElement {
return configOptions;
}
// Public to make demo happy
public createElement(config: LovelaceCardConfig) {
const element = createCardElement(config) as LovelaceCard;
element.hass = this.hass;
element.editMode = this.lovelace?.editMode;
// Update element when the visibility of the card changes (e.g. conditional card or filter card)
element.addEventListener("card-visibility-changed", (ev) => {
ev.stopPropagation();
this._updateElement();
});
return element;
}
public setConfig(config: LovelaceCardConfig): void {
if (this._config === config) {
return;
}
this._config = config;
this._element = createCardElement(config);
this._element.hass = this.hass;
this._element.editMode = this.lovelace.editMode;
this._element = this.createElement(config);
while (this.lastChild) {
this.removeChild(this.lastChild);
@ -82,11 +101,14 @@ export class HuiCard extends ReactiveElement {
this._element.hass = this.hass;
}
if (changedProperties.has("lovelace")) {
this._element.editMode = this.lovelace.editMode;
this._element.editMode = this.lovelace?.editMode;
}
if (changedProperties.has("hass") || changedProperties.has("lovelace")) {
this._updateElement();
}
if (changedProperties.has("isPanel")) {
this._element.isPanel = this.isPanel;
}
}
}
@ -118,9 +140,16 @@ export class HuiCard extends ReactiveElement {
if (!this._element) {
return;
}
if (this._element.hidden) {
this.style.setProperty("display", "none");
this.toggleAttribute("hidden", true);
return;
}
const visible =
forceVisible ||
this.lovelace.editMode ||
this.lovelace?.editMode ||
!this._config?.visibility ||
checkConditionsMet(this._config.visibility, this.hass);

View File

@ -1,4 +1,5 @@
import { customElement } from "lit/decorators";
import { fireEvent } from "../../../common/dom/fire_event";
import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
import { computeCardSize } from "../common/compute-card-size";
import { HuiConditionalBase } from "../components/hui-conditional-base";
@ -58,6 +59,15 @@ class HuiConditionalCard extends HuiConditionalBase implements LovelaceCard {
this.replaceChild(this._element, this.lastChild);
}
}
protected setVisibility(conditionMet: boolean): void {
const visible = this.editMode || conditionMet;
const previouslyHidden = this.hidden;
super.setVisibility(conditionMet);
if (previouslyHidden !== this.hidden) {
fireEvent(this, "card-visibility-changed", { value: visible });
}
}
}
declare global {

View File

@ -15,6 +15,7 @@ import { createCardElement } from "../create-element/create-card-element";
import { EntityFilterEntityConfig } from "../entity-rows/types";
import { LovelaceCard } from "../types";
import { EntityFilterCardConfig } from "./types";
import { fireEvent } from "../../../common/dom/fire_event";
@customElement("hui-entity-filter-card")
export class HuiEntityFilterCard
@ -162,9 +163,14 @@ export class HuiEntityFilterCard
return false;
});
if (entitiesList.length === 0 && this._config.show_empty === false) {
if (
entitiesList.length === 0 &&
this._config.show_empty === false &&
!this.hidden
) {
this.style.display = "none";
this.toggleAttribute("hidden", true);
fireEvent(this, "card-visibility-changed", { value: false });
return;
}
@ -194,8 +200,11 @@ export class HuiEntityFilterCard
this.appendChild(this._element);
}
this.style.display = "block";
this.toggleAttribute("hidden", false);
if (this.hidden) {
this.style.display = "block";
this.toggleAttribute("hidden", false);
fireEvent(this, "card-visibility-changed", { value: true });
}
}
private _haveEntitiesChanged(oldHass: HomeAssistant | null): boolean {

View File

@ -104,6 +104,7 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
disconnectedCallback(): void {
super.disconnectedCallback();
this._unsubItems?.then((unsub) => unsub());
this._unsubItems = undefined;
}
public getCardSize(): number {

View File

@ -6,14 +6,20 @@ import { HomeAssistant } from "../../../types";
import { ConditionalCardConfig } from "../cards/types";
import {
Condition,
checkConditionsMet,
attachConditionMediaQueriesListeners,
checkConditionsMet,
extractMediaQueries,
validateConditionalConfig,
} from "../common/validate-condition";
import { ConditionalRowConfig, LovelaceRow } from "../entity-rows/types";
import { LovelaceCard } from "../types";
declare global {
interface HASSDomEvents {
"visibility-changed": { value: boolean };
}
}
@customElement("hui-conditional-base")
export class HuiConditionalBase extends ReactiveElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@ -95,7 +101,7 @@ export class HuiConditionalBase extends ReactiveElement {
supportedConditions,
(matches) => {
if (hasOnlyMediaQuery) {
this._setVisibility(matches);
this.setVisibility(matches);
return;
}
this._updateVisibility();
@ -129,17 +135,18 @@ export class HuiConditionalBase extends ReactiveElement {
this.hass!
);
this._setVisibility(conditionMet);
this.setVisibility(conditionMet);
}
private _setVisibility(conditionMet: boolean) {
protected setVisibility(conditionMet: boolean) {
if (!this._element || !this.hass) {
return;
}
const visible = this.editMode || conditionMet;
this.toggleAttribute("hidden", !visible);
this.style.setProperty("display", visible ? "" : "none");
if (this.hidden !== !visible) {
this.toggleAttribute("hidden", !visible);
this.style.setProperty("display", visible ? "" : "none");
}
if (visible) {
this._element.hass = this.hass;
if (!this._element!.parentElement) {

View File

@ -1,11 +1,22 @@
import { customElement } from "lit/decorators";
import "@polymer/paper-tabs/paper-tab";
import "@polymer/paper-tabs/paper-tabs";
import { CSSResultGroup, TemplateResult, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
import { getCardElementClass } from "../../create-element/create-card-element";
import type { LovelaceCardEditor, LovelaceConfigForm } from "../../types";
import { HuiElementEditor } from "../hui-element-editor";
import "./hui-card-visibility-editor";
const TABS = ["config", "visibility"] as const;
@customElement("hui-card-element-editor")
export class HuiCardElementEditor extends HuiElementEditor<LovelaceCardConfig> {
@state() private _curTab: (typeof TABS)[number] = TABS[0];
@property({ type: Boolean, attribute: "show-visibility-tab" })
public showVisibilityTab = false;
protected async getConfigElement(): Promise<LovelaceCardEditor | undefined> {
const elClass = await getCardElementClass(this.configElementType!);
@ -27,6 +38,73 @@ export class HuiCardElementEditor extends HuiElementEditor<LovelaceCardConfig> {
return undefined;
}
private _handleTabSelected(ev: CustomEvent): void {
if (!ev.detail.value) {
return;
}
this._curTab = ev.detail.value.id;
}
private _configChanged(ev: CustomEvent): void {
ev.stopPropagation();
this.value = ev.detail.value;
}
protected renderConfigElement(): TemplateResult {
if (!this.showVisibilityTab) return super.renderConfigElement();
let content: TemplateResult<1> | typeof nothing = nothing;
switch (this._curTab) {
case "config":
content = html`${super.renderConfigElement()}`;
break;
case "visibility":
content = html`
<hui-card-visibility-editor
.hass=${this.hass}
.config=${this.value}
@value-changed=${this._configChanged}
></hui-card-visibility-editor>
`;
break;
}
return html`
<paper-tabs
scrollable
hide-scroll-buttons
.selected=${TABS.indexOf(this._curTab)}
@selected-item-changed=${this._handleTabSelected}
>
${TABS.map(
(tab, index) => html`
<paper-tab id=${tab} .dialogInitialFocus=${index === 0}>
${this.hass.localize(
`ui.panel.lovelace.editor.edit_card.tab-${tab}`
)}
</paper-tab>
`
)}
</paper-tabs>
${content}
`;
}
static get styles(): CSSResultGroup {
return [
HuiElementEditor.styles,
css`
paper-tabs {
--paper-tabs-selection-bar-color: var(--primary-color);
color: var(--primary-text-color);
text-transform: uppercase;
margin-bottom: 16px;
border-bottom: 1px solid var(--divider-color);
}
`,
];
}
}
declare global {

View File

@ -0,0 +1,51 @@
import { LitElement, html } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-alert";
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
import { HomeAssistant } from "../../../../types";
import { Condition } from "../../common/validate-condition";
import "../conditions/ha-card-conditions-editor";
@customElement("hui-card-visibility-editor")
export class HuiCardVisibilityEditor extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public config!: LovelaceCardConfig;
render() {
const conditions = this.config.visibility ?? [];
return html`
<ha-alert alert-type="info">
${this.hass.localize(
`ui.panel.lovelace.editor.edit_card.visibility.explanation`
)}
</ha-alert>
<ha-card-conditions-editor
.hass=${this.hass}
.conditions=${conditions}
@value-changed=${this._valueChanged}
>
</ha-card-conditions-editor>
`;
}
private _valueChanged(ev: CustomEvent): void {
ev.stopPropagation();
const conditions = ev.detail.value as Condition[];
const newConfig: LovelaceCardConfig = {
...this.config,
visibility: conditions,
};
if (newConfig.visibility?.length === 0) {
delete newConfig.visibility;
}
fireEvent(this, "value-changed", { value: newConfig });
}
}
declare global {
interface HTMLElementTagNameMap {
"hui-card-visibility-editor": HuiCardVisibilityEditor;
}
}

View File

@ -234,6 +234,7 @@ export class HuiDialogEditCard
<div class="content">
<div class="element-editor">
<hui-card-element-editor
.showVisibilityTab=${this._cardConfig?.type !== "conditional"}
.hass=${this.hass}
.lovelace=${this._params.lovelaceConfig}
.value=${this._cardConfig}
@ -407,30 +408,31 @@ export class HuiDialogEditCard
--code-mirror-max-height: calc(100vh - 176px);
}
ha-dialog {
--mdc-dialog-max-width: 100px;
--dialog-z-index: 6;
--dialog-surface-position: fixed;
--dialog-surface-top: 40px;
--mdc-dialog-max-width: 90vw;
--dialog-content-padding: 24px 12px;
}
@media all and (max-width: 450px), all and (max-height: 500px) {
/* overrule the ha-style-dialog max-height on small screens */
ha-dialog {
--mdc-dialog-max-height: 100%;
height: 100%;
--mdc-dialog-max-height: 100%;
--dialog-surface-top: 0px;
--mdc-dialog-max-width: 100vw;
}
}
@media all and (min-width: 850px) {
ha-dialog {
--mdc-dialog-min-width: 845px;
--mdc-dialog-max-height: calc(100% - 72px);
}
}
ha-dialog {
--mdc-dialog-max-width: 845px;
--dialog-z-index: 6;
.content {
width: 1000px;
max-width: calc(90vw - 48px);
}
@media all and (min-width: 451px) and (min-height: 501px) {
ha-dialog {
--mdc-dialog-max-width: 90vw;
}
:host([large]) .content {
width: calc(90vw - 48px);
}
@ -444,8 +446,8 @@ export class HuiDialogEditCard
.content {
display: flex;
flex-direction: column;
margin: 0 -10px;
}
.content hui-card-preview {
margin: 4px auto;
max-width: 390px;
@ -454,15 +456,7 @@ export class HuiDialogEditCard
margin: 0 10px;
}
@media (min-width: 1200px) {
ha-dialog {
--mdc-dialog-max-width: calc(100% - 32px);
--mdc-dialog-min-width: 1000px;
--dialog-surface-position: fixed;
--dialog-surface-top: 40px;
--mdc-dialog-max-height: calc(100% - 72px);
}
@media (min-width: 1000px) {
.content {
flex-direction: row;
}

View File

@ -20,13 +20,14 @@ import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
import { LovelaceStrategyConfig } from "../../../data/lovelace/config/strategy";
import { LovelaceConfig } from "../../../data/lovelace/config/types";
import type { HomeAssistant } from "../../../types";
import { LovelaceCardFeatureConfig } from "../card-features/types";
import type { LovelaceRowConfig } from "../entity-rows/types";
import { LovelaceHeaderFooterConfig } from "../header-footer/types";
import { LovelaceCardFeatureConfig } from "../card-features/types";
import type {
LovelaceConfigForm,
LovelaceGenericElementEditor,
} from "../types";
import "./card-editor/hui-card-visibility-editor";
import type { HuiFormEditor } from "./config-elements/hui-form-editor";
import "./config-elements/hui-generic-entity-row-editor";
import { GUISupportError } from "./gui-support-error";
@ -198,6 +199,10 @@ export abstract class HuiElementEditor<T, C = any> extends LitElement {
return this.value ? (this.value as any).type : undefined;
}
protected renderConfigElement(): TemplateResult {
return html`${this._configElement}`;
}
protected render(): TemplateResult {
return html`
<div class="wrapper">
@ -211,7 +216,7 @@ export abstract class HuiElementEditor<T, C = any> extends LitElement {
class="center margin-bot"
></ha-circular-progress>
`
: this._configElement}
: this.renderConfigElement()}
</div>
`
: html`

View File

@ -26,15 +26,22 @@ import { parseLovelaceCardPath } from "../editor/lovelace-path";
import { generateLovelaceSectionStrategy } from "../strategies/get-strategy";
import type { Lovelace } from "../types";
import { DEFAULT_SECTION_LAYOUT } from "./const";
import { fireEvent } from "../../../common/dom/fire_event";
declare global {
interface HASSDomEvents {
"section-visibility-changed": { value: boolean };
}
}
@customElement("hui-section")
export class HuiSection extends ReactiveElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public lovelace!: Lovelace;
@property({ attribute: false }) public config!: LovelaceSectionRawConfig;
@property({ attribute: false }) public lovelace?: Lovelace;
@property({ type: Number }) public index!: number;
@property({ type: Number }) public viewIndex!: number;
@ -215,12 +222,16 @@ export class HuiSection extends ReactiveElement {
}
const visible =
forceVisible ||
this.lovelace.editMode ||
this.lovelace?.editMode ||
!this.config.visibility ||
checkConditionsMet(this.config.visibility, this.hass);
this.style.setProperty("display", visible ? "" : "none");
this.toggleAttribute("hidden", !visible);
if (this.hidden !== !visible) {
this.style.setProperty("display", visible ? "" : "none");
this.toggleAttribute("hidden", !visible);
fireEvent(this, "section-visibility-changed", { value: visible });
}
if (!visible && this._layoutElement.parentElement) {
this.removeChild(this._layoutElement);
} else if (visible && !this._layoutElement.parentElement) {
@ -235,6 +246,7 @@ export class HuiSection extends ReactiveElement {
this._layoutElementType = config.type;
this._layoutElement.addEventListener("ll-create-card", (ev) => {
ev.stopPropagation();
if (!this.lovelace) return;
showCreateCardDialog(this, {
lovelaceConfig: this.lovelace.config,
saveConfig: this.lovelace.saveConfig,
@ -244,6 +256,7 @@ export class HuiSection extends ReactiveElement {
});
this._layoutElement.addEventListener("ll-edit-card", (ev) => {
ev.stopPropagation();
if (!this.lovelace) return;
const { cardIndex } = parseLovelaceCardPath(ev.detail.path);
showEditCardDialog(this, {
lovelaceConfig: this.lovelace.config,
@ -254,6 +267,7 @@ export class HuiSection extends ReactiveElement {
});
this._layoutElement.addEventListener("ll-delete-card", (ev) => {
ev.stopPropagation();
if (!this.lovelace) return;
if (ev.detail.confirm) {
confDeleteCard(this, this.hass!, this.lovelace!, ev.detail.path);
} else {

View File

@ -54,29 +54,22 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
return this._sectionConfigKeys.get(sectionConfig)!;
}
private _sectionObserver?: MutationObserver;
private _computeSectionsCount() {
this._sectionCount = this.sections.filter(
(section) => !section.hidden
).length;
}
connectedCallback(): void {
super.connectedCallback();
this.addEventListener("section-visibility-changed", () => {
this._computeSectionsCount();
});
}
willUpdate(changedProperties: PropertyValues<typeof this>): void {
if (!this._sectionObserver) {
this._sectionObserver = new MutationObserver(() => {
this._computeSectionsCount();
});
}
if (changedProperties.has("sections")) {
this._computeSectionsCount();
this._sectionObserver.disconnect();
this.sections.forEach((section) => {
this._sectionObserver!.observe(section, {
attributes: true,
attributeFilter: ["hidden"],
});
});
}
}

View File

@ -74,8 +74,7 @@ export class HUIView extends ReactiveElement {
private _viewConfigTheme?: string;
// Public to make demo happy
public createCardElement(cardConfig: LovelaceCardConfig) {
private _createCardElement(cardConfig: LovelaceCardConfig) {
const element = document.createElement("hui-card");
element.hass = this.hass;
element.lovelace = this.lovelace;
@ -371,7 +370,7 @@ export class HUIView extends ReactiveElement {
}
this._cards = config.cards.map((cardConfig) => {
const element = this.createCardElement(cardConfig);
const element = this._createCardElement(cardConfig);
return element;
});
}
@ -393,7 +392,7 @@ export class HUIView extends ReactiveElement {
cardElToReplace: HuiCard,
config: LovelaceCardConfig
): void {
const newCardEl = this.createCardElement(config);
const newCardEl = this._createCardElement(config);
if (cardElToReplace.parentElement) {
cardElToReplace.parentElement!.replaceChild(newCardEl, cardElToReplace);
}

View File

@ -5518,7 +5518,12 @@
"decrease_position": "Decrease card position",
"increase_position": "Increase card position",
"options": "More options",
"search_cards": "Search cards"
"search_cards": "Search cards",
"tab-config": "Config",
"tab-visibility": "Visibility",
"visibility": {
"explanation": "The card will be shown when ALL conditions below are fulfilled. If no conditions are set, the card will always be shown."
}
},
"move_card": {
"header": "Choose a view to move the card to",

154
yarn.lock
View File

@ -1461,9 +1461,9 @@ __metadata:
languageName: node
linkType: hard
"@codemirror/autocomplete@npm:6.16.0":
version: 6.16.0
resolution: "@codemirror/autocomplete@npm:6.16.0"
"@codemirror/autocomplete@npm:6.16.2":
version: 6.16.2
resolution: "@codemirror/autocomplete@npm:6.16.2"
dependencies:
"@codemirror/language": "npm:^6.0.0"
"@codemirror/state": "npm:^6.0.0"
@ -1474,7 +1474,7 @@ __metadata:
"@codemirror/state": ^6.0.0
"@codemirror/view": ^6.0.0
"@lezer/common": ^1.0.0
checksum: 10/a29e27f69d17bce014d1d34ab4cd7c607b139cb3cd529aad554f2b0badb9d2924412b0ab3f4eb44901ea4250cdb033e0c6b81134ee8991bdbcd128ecb3b94d75
checksum: 10/0573740e55d80347df92f9ef638dc2f0dbecb99db1740daae45942fe8c39d40b90a7417ae7bf35129743d7525509a2e97fd853795652ea8b82687a712b668761
languageName: node
linkType: hard
@ -4600,15 +4600,15 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/eslint-plugin@npm:7.10.0":
version: 7.10.0
resolution: "@typescript-eslint/eslint-plugin@npm:7.10.0"
"@typescript-eslint/eslint-plugin@npm:7.11.0":
version: 7.11.0
resolution: "@typescript-eslint/eslint-plugin@npm:7.11.0"
dependencies:
"@eslint-community/regexpp": "npm:^4.10.0"
"@typescript-eslint/scope-manager": "npm:7.10.0"
"@typescript-eslint/type-utils": "npm:7.10.0"
"@typescript-eslint/utils": "npm:7.10.0"
"@typescript-eslint/visitor-keys": "npm:7.10.0"
"@typescript-eslint/scope-manager": "npm:7.11.0"
"@typescript-eslint/type-utils": "npm:7.11.0"
"@typescript-eslint/utils": "npm:7.11.0"
"@typescript-eslint/visitor-keys": "npm:7.11.0"
graphemer: "npm:^1.4.0"
ignore: "npm:^5.3.1"
natural-compare: "npm:^1.4.0"
@ -4619,44 +4619,44 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 10/dfe505cdf718dd29e8637b902e4c544c6b7d246d2051fd1936090423eb3dadfe2bd757de51e565e6fd80e74cf1918e191c26fee6df515100484ec3efd9b8d111
checksum: 10/be95ed0bbd5b34c47239677ea39d531bcd8a18717a67d70a297bed5b0050b256159856bb9c1e894ac550d011c24bb5b4abf8056c5d70d0d5895f0cc1accd14ea
languageName: node
linkType: hard
"@typescript-eslint/parser@npm:7.10.0":
version: 7.10.0
resolution: "@typescript-eslint/parser@npm:7.10.0"
"@typescript-eslint/parser@npm:7.11.0":
version: 7.11.0
resolution: "@typescript-eslint/parser@npm:7.11.0"
dependencies:
"@typescript-eslint/scope-manager": "npm:7.10.0"
"@typescript-eslint/types": "npm:7.10.0"
"@typescript-eslint/typescript-estree": "npm:7.10.0"
"@typescript-eslint/visitor-keys": "npm:7.10.0"
"@typescript-eslint/scope-manager": "npm:7.11.0"
"@typescript-eslint/types": "npm:7.11.0"
"@typescript-eslint/typescript-estree": "npm:7.11.0"
"@typescript-eslint/visitor-keys": "npm:7.11.0"
debug: "npm:^4.3.4"
peerDependencies:
eslint: ^8.56.0
peerDependenciesMeta:
typescript:
optional: true
checksum: 10/1fa71049b2debf2f7f5366fb433e3d4c8e1591c2061a15fa8797d14623a2b6984340a59e7717acc013ce8c6a2ed32c5c0e811fe948b5936d41c2a5a09b61d130
checksum: 10/0a32417aec62d7de04427323ab3fc8159f9f02429b24f739d8748e8b54fc65b0e3dbae8e4779c4b795f0d8e5f98a4d83a43b37ea0f50ebda51546cdcecf73caa
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:7.10.0":
version: 7.10.0
resolution: "@typescript-eslint/scope-manager@npm:7.10.0"
"@typescript-eslint/scope-manager@npm:7.11.0":
version: 7.11.0
resolution: "@typescript-eslint/scope-manager@npm:7.11.0"
dependencies:
"@typescript-eslint/types": "npm:7.10.0"
"@typescript-eslint/visitor-keys": "npm:7.10.0"
checksum: 10/838a7a9573577d830b2f65801ce045abe6fad08ac7e04bac4cc9b2e5b7cbac07e645de9c79b9485f4cc361fe25da5319025aa0336fad618023fff62e4e980638
"@typescript-eslint/types": "npm:7.11.0"
"@typescript-eslint/visitor-keys": "npm:7.11.0"
checksum: 10/79eff310405c6657ff092641e3ad51c6698c6708b915ecef945ebdd1737bd48e1458c5575836619f42dec06143ec0e3a826f3e551af590d297367da3d08f329e
languageName: node
linkType: hard
"@typescript-eslint/type-utils@npm:7.10.0":
version: 7.10.0
resolution: "@typescript-eslint/type-utils@npm:7.10.0"
"@typescript-eslint/type-utils@npm:7.11.0":
version: 7.11.0
resolution: "@typescript-eslint/type-utils@npm:7.11.0"
dependencies:
"@typescript-eslint/typescript-estree": "npm:7.10.0"
"@typescript-eslint/utils": "npm:7.10.0"
"@typescript-eslint/typescript-estree": "npm:7.11.0"
"@typescript-eslint/utils": "npm:7.11.0"
debug: "npm:^4.3.4"
ts-api-utils: "npm:^1.3.0"
peerDependencies:
@ -4664,23 +4664,23 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 10/e62db9ffbfbccce60258108f7ed025005e04df18da897ff1b30049e3c10a47150e94c2fb5ac0ab9711ebb60517521213dcccbea6d08125107a87a67088a79042
checksum: 10/ab6ebeff68a60fc40d0ace88e03d6b4242b8f8fe2fa300db161780d58777b57f69fa077cd482e1b673316559459bd20b8cc89a7f9f30e644bfed8293f77f0e4b
languageName: node
linkType: hard
"@typescript-eslint/types@npm:7.10.0":
version: 7.10.0
resolution: "@typescript-eslint/types@npm:7.10.0"
checksum: 10/76075a7b87ddfff8e7e4aebf3d225e67bf79ead12a7709999d4d5c31611d9c0813ca69a9298f320efb018fe493ce3763c964a0e670a4c953d8eff000f10672c0
"@typescript-eslint/types@npm:7.11.0":
version: 7.11.0
resolution: "@typescript-eslint/types@npm:7.11.0"
checksum: 10/c6a0b47ef43649a59c9d51edfc61e367b55e519376209806b1c98385a8385b529e852c7a57e081fb15ef6a5dc0fc8e90bd5a508399f5ac2137f4d462e89cdc30
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:7.10.0":
version: 7.10.0
resolution: "@typescript-eslint/typescript-estree@npm:7.10.0"
"@typescript-eslint/typescript-estree@npm:7.11.0":
version: 7.11.0
resolution: "@typescript-eslint/typescript-estree@npm:7.11.0"
dependencies:
"@typescript-eslint/types": "npm:7.10.0"
"@typescript-eslint/visitor-keys": "npm:7.10.0"
"@typescript-eslint/types": "npm:7.11.0"
"@typescript-eslint/visitor-keys": "npm:7.11.0"
debug: "npm:^4.3.4"
globby: "npm:^11.1.0"
is-glob: "npm:^4.0.3"
@ -4690,31 +4690,31 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
checksum: 10/d11d0c45749c9bd4a187b6dfdf5600e36ba8c87667cd2020d9158667c47c32ec0bcb1ef3b7eee5577b667def5f7f33d8131092a0f221b3d3e8105078800f923f
checksum: 10/b98b101e42d3b91003510a5c5a83f4350b6c1cf699bf2e409717660579ffa71682bc280c4f40166265c03f9546ed4faedc3723e143f1ab0ed7f5990cc3dff0ae
languageName: node
linkType: hard
"@typescript-eslint/utils@npm:7.10.0":
version: 7.10.0
resolution: "@typescript-eslint/utils@npm:7.10.0"
"@typescript-eslint/utils@npm:7.11.0":
version: 7.11.0
resolution: "@typescript-eslint/utils@npm:7.11.0"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.4.0"
"@typescript-eslint/scope-manager": "npm:7.10.0"
"@typescript-eslint/types": "npm:7.10.0"
"@typescript-eslint/typescript-estree": "npm:7.10.0"
"@typescript-eslint/scope-manager": "npm:7.11.0"
"@typescript-eslint/types": "npm:7.11.0"
"@typescript-eslint/typescript-estree": "npm:7.11.0"
peerDependencies:
eslint: ^8.56.0
checksum: 10/62327b585295f9c3aa2508aefac639d562b6f7f270a229aa3a2af8dbd055f4a4d230a8facae75a8a53bb8222b0041162072d259add56b541f8bdfda8da36ea5f
checksum: 10/fbef14e166a70ccc4527c0731e0338acefa28218d1a018aa3f5b6b1ad9d75c56278d5f20bda97cf77da13e0a67c4f3e579c5b2f1c2e24d676960927921b55851
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:7.10.0":
version: 7.10.0
resolution: "@typescript-eslint/visitor-keys@npm:7.10.0"
"@typescript-eslint/visitor-keys@npm:7.11.0":
version: 7.11.0
resolution: "@typescript-eslint/visitor-keys@npm:7.11.0"
dependencies:
"@typescript-eslint/types": "npm:7.10.0"
"@typescript-eslint/types": "npm:7.11.0"
eslint-visitor-keys: "npm:^3.4.3"
checksum: 10/44b555a075bdff38e3e13c454ceaac50aa2546635e81f907d1ea84822c8887487d1d6bb4ff690f627da9585dc19ad07e228847c162c30bb06c46fb119899d8cc
checksum: 10/1f2cf1214638e9e78e052393c9e24295196ec4781b05951659a3997e33f8699a760ea3705c17d770e10eda2067435199e0136ab09e5fac63869e22f2da184d89
languageName: node
linkType: hard
@ -7631,16 +7631,16 @@ __metadata:
languageName: node
linkType: hard
"eslint-plugin-lit@npm:1.13.0, eslint-plugin-lit@npm:^1.10.1":
version: 1.13.0
resolution: "eslint-plugin-lit@npm:1.13.0"
"eslint-plugin-lit@npm:1.14.0, eslint-plugin-lit@npm:^1.10.1":
version: 1.14.0
resolution: "eslint-plugin-lit@npm:1.14.0"
dependencies:
parse5: "npm:^6.0.1"
parse5-htmlparser2-tree-adapter: "npm:^6.0.1"
requireindex: "npm:^1.2.0"
peerDependencies:
eslint: ">= 5"
checksum: 10/e8d2bca442ec7c1436e5a6299df8e8ee980a5f8db9a1c7bff8fcc0e3983a133303134ace398e6695b4b96c3b384f2ed0601fa7d0ad15ffe9421922c31df5349a
checksum: 10/25daccae8b38970b881044ee72d4e4da82de5ed5cc466ce31209925903326d74a5bf50cb8c6c9d268a16eac178e377a83201f9ca777bc79355a49c1ea9d91364
languageName: node
linkType: hard
@ -8924,7 +8924,7 @@ __metadata:
"@babel/runtime": "npm:7.24.6"
"@braintree/sanitize-url": "npm:7.0.2"
"@bundle-stats/plugin-webpack-filter": "npm:4.13.2"
"@codemirror/autocomplete": "npm:6.16.0"
"@codemirror/autocomplete": "npm:6.16.2"
"@codemirror/commands": "npm:6.5.0"
"@codemirror/language": "npm:6.10.1"
"@codemirror/legacy-modes": "npm:6.4.0"
@ -9014,8 +9014,8 @@ __metadata:
"@types/tar": "npm:6.1.13"
"@types/ua-parser-js": "npm:0.7.39"
"@types/webspeechapi": "npm:0.0.29"
"@typescript-eslint/eslint-plugin": "npm:7.10.0"
"@typescript-eslint/parser": "npm:7.10.0"
"@typescript-eslint/eslint-plugin": "npm:7.11.0"
"@typescript-eslint/parser": "npm:7.11.0"
"@vaadin/combo-box": "npm:24.3.13"
"@vaadin/vaadin-themable-mixin": "npm:24.3.13"
"@vibrant/color": "npm:3.2.1-alpha.1"
@ -9047,7 +9047,7 @@ __metadata:
eslint-config-prettier: "npm:9.1.0"
eslint-import-resolver-webpack: "npm:0.13.8"
eslint-plugin-import: "npm:2.29.1"
eslint-plugin-lit: "npm:1.13.0"
eslint-plugin-lit: "npm:1.14.0"
eslint-plugin-lit-a11y: "npm:4.1.2"
eslint-plugin-unused-imports: "npm:4.0.0"
eslint-plugin-wc: "npm:2.1.0"
@ -9104,7 +9104,7 @@ __metadata:
stacktrace-js: "npm:2.0.2"
superstruct: "npm:1.0.4"
systemjs: "npm:6.15.1"
tar: "npm:7.1.0"
tar: "npm:7.2.0"
terser-webpack-plugin: "npm:5.3.10"
tinykeys: "npm:2.1.0"
transform-async-modules-webpack-plugin: "npm:1.1.1"
@ -9112,7 +9112,7 @@ __metadata:
tsparticles-engine: "npm:2.12.0"
tsparticles-preset-links: "npm:2.12.0"
typescript: "npm:5.4.5"
ua-parser-js: "npm:1.0.37"
ua-parser-js: "npm:1.0.38"
unfetch: "npm:5.0.0"
vis-data: "npm:7.1.9"
vis-network: "npm:9.1.9"
@ -9125,7 +9125,7 @@ __metadata:
webpack-stats-plugin: "npm:1.1.3"
webpackbar: "npm:6.0.1"
weekstart: "npm:2.0.0"
workbox-build: "npm:7.1.0"
workbox-build: "npm:7.1.1"
workbox-cacheable-response: "npm:7.1.0"
workbox-core: "npm:7.1.0"
workbox-expiration: "npm:7.1.0"
@ -13723,9 +13723,9 @@ __metadata:
languageName: node
linkType: hard
"tar@npm:7.1.0":
version: 7.1.0
resolution: "tar@npm:7.1.0"
"tar@npm:7.2.0":
version: 7.2.0
resolution: "tar@npm:7.2.0"
dependencies:
"@isaacs/fs-minipass": "npm:^4.0.0"
chownr: "npm:^3.0.0"
@ -13733,7 +13733,7 @@ __metadata:
minizlib: "npm:^3.0.1"
mkdirp: "npm:^3.0.1"
yallist: "npm:^5.0.0"
checksum: 10/87c2caa631dcf212cc50cc7fc4402b429d9083cf76f21d9ec63eba7a703b78804b2185bbe072f4c6cac8263dc8e7df786dfdfd53ef5bfbf7b46b480535794ea5
checksum: 10/29e4ebd5057e754442921e3f46fdec3316e00a85009762c389c52d07fee11f1c85397849ae34949e43080c703d3c5ecfabffa6efcbb077315f72142a9b7a51da
languageName: node
linkType: hard
@ -14285,10 +14285,10 @@ __metadata:
languageName: node
linkType: hard
"ua-parser-js@npm:1.0.37":
version: 1.0.37
resolution: "ua-parser-js@npm:1.0.37"
checksum: 10/56508f2428ebac64382c4d41da14189e5013e3e2a5f5918aff4bee3ba77df1f4eaad6f81f90c24999f1cf12cc1596764684497fec07e0ff5182ce9a323a8c05b
"ua-parser-js@npm:1.0.38":
version: 1.0.38
resolution: "ua-parser-js@npm:1.0.38"
checksum: 10/f2345e9bd0f9c5f85bcaa434535fae88f4bb891538e568106f0225b2c2937fbfbeb5782bd22320d07b6b3d68b350b8861574c1d7af072ff9b2362fb72d326fd9
languageName: node
linkType: hard
@ -15105,9 +15105,9 @@ __metadata:
languageName: node
linkType: hard
"workbox-build@npm:7.1.0":
version: 7.1.0
resolution: "workbox-build@npm:7.1.0"
"workbox-build@npm:7.1.1":
version: 7.1.1
resolution: "workbox-build@npm:7.1.1"
dependencies:
"@apideck/better-ajv-errors": "npm:^0.3.1"
"@babel/core": "npm:^7.24.4"
@ -15146,7 +15146,7 @@ __metadata:
workbox-streams: "npm:7.1.0"
workbox-sw: "npm:7.1.0"
workbox-window: "npm:7.1.0"
checksum: 10/6d2086899e65f7728fe3c2cc7d14dbc18bec2ae8c2e1e681f552e0162b8c138b2c2a235ddcf820b3b966cb06b60319fcaa9eb1831f35f1fab1da77fa4238dcbd
checksum: 10/65eb75fc67fd14f415e6978c1f6431c21d6b27bdaec7e5438d8586719c6b09aaad5cec6ecd89684d1d414ff3b52c4eb2de3d748e1e0873b5a6ab3a2531fe034b
languageName: node
linkType: hard