mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-21 08:16:36 +00:00
Use selectors for add-on network configuration (#12235)
* Use selectors for add-on network configuration * Show container port as UOM if advanced user * adjust
This commit is contained in:
parent
1dba849567
commit
bbca7b762b
@ -1,4 +1,3 @@
|
|||||||
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
@ -8,10 +7,13 @@ import {
|
|||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../../src/components/ha-alert";
|
import "../../../../src/components/ha-alert";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/components/ha-form/ha-form";
|
||||||
|
import type { HaFormSchema } from "../../../../src/components/ha-form/types";
|
||||||
import {
|
import {
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
HassioAddonSetOptionParams,
|
HassioAddonSetOptionParams,
|
||||||
@ -24,16 +26,6 @@ import { HomeAssistant } from "../../../../src/types";
|
|||||||
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
|
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
|
||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
|
|
||||||
interface NetworkItem {
|
|
||||||
description: string;
|
|
||||||
container: string;
|
|
||||||
host: number | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface NetworkItemInput extends PaperInputElement {
|
|
||||||
container: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("hassio-addon-network")
|
@customElement("hassio-addon-network")
|
||||||
class HassioAddonNetwork extends LitElement {
|
class HassioAddonNetwork extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -42,9 +34,13 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||||
|
|
||||||
|
@state() private _showOptional = false;
|
||||||
|
|
||||||
|
@state() private _configHasChanged = false;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@state() private _error?: string;
|
||||||
|
|
||||||
@state() private _config?: NetworkItem[];
|
@state() private _config?: Record<string, any>;
|
||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
@ -56,6 +52,10 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasHiddenOptions = Object.keys(this._config).find(
|
||||||
|
(entry) => this._config![entry] === null
|
||||||
|
);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card
|
||||||
.header=${this.supervisor.localize(
|
.header=${this.supervisor.localize(
|
||||||
@ -63,52 +63,49 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
|
<p>
|
||||||
|
${this.supervisor.localize(
|
||||||
|
"addon.configuration.network.introduction"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
${this._error
|
${this._error
|
||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
: ""}
|
: ""}
|
||||||
|
|
||||||
<table>
|
<ha-form
|
||||||
<tbody>
|
.data=${this._config}
|
||||||
<tr>
|
@value-changed=${this._configChanged}
|
||||||
<th>
|
.computeLabel=${this._computeLabel}
|
||||||
${this.supervisor.localize(
|
.computeHelper=${this._computeHelper}
|
||||||
"addon.configuration.network.container"
|
.schema=${this._createSchema(
|
||||||
)}
|
this._config,
|
||||||
</th>
|
this._showOptional,
|
||||||
<th>
|
this.hass.userData?.showAdvanced || false
|
||||||
${this.supervisor.localize(
|
)}
|
||||||
"addon.configuration.network.host"
|
></ha-form>
|
||||||
)}
|
|
||||||
</th>
|
|
||||||
<th>${this.supervisor.localize("common.description")}</th>
|
|
||||||
</tr>
|
|
||||||
${this._config!.map(
|
|
||||||
(item) => html`
|
|
||||||
<tr>
|
|
||||||
<td>${item.container}</td>
|
|
||||||
<td>
|
|
||||||
<paper-input
|
|
||||||
@value-changed=${this._configChanged}
|
|
||||||
placeholder=${this.supervisor.localize(
|
|
||||||
"addon.configuration.network.disabled"
|
|
||||||
)}
|
|
||||||
.value=${item.host ? String(item.host) : ""}
|
|
||||||
.container=${item.container}
|
|
||||||
no-label-float
|
|
||||||
></paper-input>
|
|
||||||
</td>
|
|
||||||
<td>${this._computeDescription(item)}</td>
|
|
||||||
</tr>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
${hasHiddenOptions
|
||||||
|
? html`<ha-formfield
|
||||||
|
class="show-optional"
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"addon.configuration.network.show_disabled"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<ha-switch
|
||||||
|
@change=${this._toggleOptional}
|
||||||
|
.checked=${this._showOptional}
|
||||||
|
>
|
||||||
|
</ha-switch>
|
||||||
|
</ha-formfield>`
|
||||||
|
: ""}
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<ha-progress-button class="warning" @click=${this._resetTapped}>
|
<ha-progress-button class="warning" @click=${this._resetTapped}>
|
||||||
${this.supervisor.localize("common.reset_defaults")}
|
${this.supervisor.localize("common.reset_defaults")}
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
<ha-progress-button @click=${this._saveTapped}>
|
<ha-progress-button
|
||||||
|
@click=${this._saveTapped}
|
||||||
|
.disabled=${!this._configHasChanged}
|
||||||
|
>
|
||||||
${this.supervisor.localize("common.save")}
|
${this.supervisor.localize("common.save")}
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
</div>
|
</div>
|
||||||
@ -123,50 +120,60 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeDescription = (item: NetworkItem): string =>
|
private _createSchema = memoizeOne(
|
||||||
this.addon.translations[this.hass.language]?.network?.[item.container]
|
(
|
||||||
?.description ||
|
config: Record<string, number>,
|
||||||
this.addon.translations.en?.network?.[item.container]?.description ||
|
showOptional: boolean,
|
||||||
item.description;
|
advanced: boolean
|
||||||
|
): HaFormSchema[] =>
|
||||||
|
(showOptional
|
||||||
|
? Object.keys(config)
|
||||||
|
: Object.keys(config).filter((entry) => config[entry] !== null)
|
||||||
|
).map((entry) => ({
|
||||||
|
name: entry,
|
||||||
|
selector: {
|
||||||
|
number: {
|
||||||
|
mode: "box",
|
||||||
|
min: 0,
|
||||||
|
max: 65535,
|
||||||
|
unit_of_measurement: advanced ? entry : undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
private _computeLabel = (_: HaFormSchema): string => "";
|
||||||
|
|
||||||
|
private _computeHelper = (item: HaFormSchema): string =>
|
||||||
|
this.addon.translations[this.hass.language]?.network?.[item.name] ||
|
||||||
|
this.addon.translations.en?.network?.[item.name] ||
|
||||||
|
this.addon.network_description?.[item.name] ||
|
||||||
|
item.name;
|
||||||
|
|
||||||
private _setNetworkConfig(): void {
|
private _setNetworkConfig(): void {
|
||||||
const network = this.addon.network || {};
|
this._config = this.addon.network || {};
|
||||||
const description = this.addon.network_description || {};
|
|
||||||
const items: NetworkItem[] = Object.keys(network).map((key) => ({
|
|
||||||
container: key,
|
|
||||||
host: network[key],
|
|
||||||
description: description[key],
|
|
||||||
}));
|
|
||||||
this._config = items.sort((a, b) => (a.container > b.container ? 1 : -1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _configChanged(ev: Event): Promise<void> {
|
private async _configChanged(ev: CustomEvent): Promise<void> {
|
||||||
const target = ev.target as NetworkItemInput;
|
this._configHasChanged = true;
|
||||||
this._config!.forEach((item) => {
|
this._config! = ev.detail.value;
|
||||||
if (
|
|
||||||
item.container === target.container &&
|
|
||||||
item.host !== parseInt(String(target.value), 10)
|
|
||||||
) {
|
|
||||||
item.host = target.value ? parseInt(String(target.value), 10) : null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _resetTapped(ev: CustomEvent): Promise<void> {
|
private async _resetTapped(ev: CustomEvent): Promise<void> {
|
||||||
const button = ev.currentTarget as any;
|
const button = ev.currentTarget as any;
|
||||||
button.progress = true;
|
|
||||||
|
|
||||||
const data: HassioAddonSetOptionParams = {
|
const data: HassioAddonSetOptionParams = {
|
||||||
network: null,
|
network: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||||
|
this._configHasChanged = false;
|
||||||
const eventdata = {
|
const eventdata = {
|
||||||
success: true,
|
success: true,
|
||||||
response: undefined,
|
response: undefined,
|
||||||
path: "option",
|
path: "option",
|
||||||
};
|
};
|
||||||
|
button.actionSuccess();
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
||||||
@ -177,19 +184,21 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
"error",
|
"error",
|
||||||
extractApiErrorMessage(err)
|
extractApiErrorMessage(err)
|
||||||
);
|
);
|
||||||
|
button.actionError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
button.progress = false;
|
private _toggleOptional() {
|
||||||
|
this._showOptional = !this._showOptional;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _saveTapped(ev: CustomEvent): Promise<void> {
|
private async _saveTapped(ev: CustomEvent): Promise<void> {
|
||||||
const button = ev.currentTarget as any;
|
const button = ev.currentTarget as any;
|
||||||
button.progress = true;
|
|
||||||
|
|
||||||
this._error = undefined;
|
this._error = undefined;
|
||||||
const networkconfiguration = {};
|
const networkconfiguration = {};
|
||||||
this._config!.forEach((item) => {
|
Object.entries(this._config!).forEach(([key, value]) => {
|
||||||
networkconfiguration[item.container] = parseInt(String(item.host), 10);
|
networkconfiguration[key] = value ?? null;
|
||||||
});
|
});
|
||||||
|
|
||||||
const data: HassioAddonSetOptionParams = {
|
const data: HassioAddonSetOptionParams = {
|
||||||
@ -198,11 +207,13 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||||
|
this._configHasChanged = false;
|
||||||
const eventdata = {
|
const eventdata = {
|
||||||
success: true,
|
success: true,
|
||||||
response: undefined,
|
response: undefined,
|
||||||
path: "option",
|
path: "option",
|
||||||
};
|
};
|
||||||
|
button.actionSuccess();
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
||||||
@ -213,8 +224,8 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
"error",
|
"error",
|
||||||
extractApiErrorMessage(err)
|
extractApiErrorMessage(err)
|
||||||
);
|
);
|
||||||
|
button.actionError();
|
||||||
}
|
}
|
||||||
button.progress = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
@ -232,6 +243,9 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
.show-optional {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,8 @@ export type AddonState = "started" | "stopped" | null;
|
|||||||
export type AddonRepository = "core" | "local" | string;
|
export type AddonRepository = "core" | "local" | string;
|
||||||
|
|
||||||
interface AddonTranslations {
|
interface AddonTranslations {
|
||||||
[key: string]: Record<string, Record<string, Record<string, string>>>;
|
network?: Record<string, string>;
|
||||||
|
configuration?: Record<string, { name?: string; description?: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HassioAddonInfo {
|
export interface HassioAddonInfo {
|
||||||
@ -91,7 +92,7 @@ export interface HassioAddonDetails extends HassioAddonInfo {
|
|||||||
slug: string;
|
slug: string;
|
||||||
startup: AddonStartup;
|
startup: AddonStartup;
|
||||||
stdin: boolean;
|
stdin: boolean;
|
||||||
translations: AddonTranslations;
|
translations: Record<string, AddonTranslations>;
|
||||||
watchdog: null | boolean;
|
watchdog: null | boolean;
|
||||||
webui: null | string;
|
webui: null | string;
|
||||||
}
|
}
|
||||||
|
@ -4171,7 +4171,8 @@
|
|||||||
"container": "Container",
|
"container": "Container",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"header": "Network",
|
"header": "Network",
|
||||||
"host": "Host"
|
"show_disabled": "Show disabled ports",
|
||||||
|
"introduction": "Change the ports on your host that are exposed by the add-on"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user