Add support for the file selector (#13382)

This commit is contained in:
Paulus Schoutsen 2022-08-18 11:43:43 -04:00 committed by GitHub
parent 47b820d28f
commit 8c71885b4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 129 additions and 0 deletions

View File

@ -50,6 +50,7 @@ export const computeInitialHaFormData = (
"text" in selector || "text" in selector ||
"addon" in selector || "addon" in selector ||
"attribute" in selector || "attribute" in selector ||
"file" in selector ||
"icon" in selector || "icon" in selector ||
"theme" in selector "theme" in selector
) { ) {

View File

@ -0,0 +1,98 @@
import { mdiFile } from "@mdi/js";
import { html, LitElement, PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { removeFile, uploadFile } from "../../data/file_upload";
import { FileSelector } from "../../data/selector";
import { showAlertDialog } from "../../dialogs/generic/show-dialog-box";
import { HomeAssistant } from "../../types";
import "../ha-file-upload";
@customElement("ha-selector-file")
export class HaFileSelector extends LitElement {
@property() public hass!: HomeAssistant;
@property() public selector!: FileSelector;
@property() public value?: string;
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = true;
@state() private _filename?: { fileId: string; name: string };
@state() private _busy = false;
protected render() {
return html`
<ha-file-upload
.hass=${this.hass}
.accept=${this.selector.file.accept}
.icon=${mdiFile}
.label=${this.label}
.required=${this.required}
.disabled=${this.disabled}
.helper=${this.helper}
.uploading=${this._busy}
.value=${this.value ? this._filename?.name || "Unknown file" : ""}
@file-picked=${this._uploadFile}
@change=${this._removeFile}
></ha-file-upload>
`;
}
protected willUpdate(changedProps: PropertyValues) {
super.willUpdate(changedProps);
if (
changedProps.has("value") &&
this._filename &&
this.value !== this._filename.fileId
) {
this._filename = undefined;
}
}
private async _uploadFile(ev) {
this._busy = true;
const file = ev.detail.files![0];
try {
const fileId = await uploadFile(this.hass, file);
this._filename = { fileId, name: file.name };
fireEvent(this, "value-changed", { value: fileId });
} catch (err: any) {
showAlertDialog(this, {
text: this.hass.localize("ui.components.selectors.file.upload_failed", {
reason: err.message || err,
}),
});
} finally {
this._busy = false;
}
}
private _removeFile = async () => {
this._busy = true;
try {
await removeFile(this.hass, this.value!);
} catch (err) {
// Not ideal if removal fails, but will be cleaned up later
} finally {
this._busy = false;
}
this._filename = undefined;
fireEvent(this, "value-changed", { value: "" });
};
}
declare global {
interface HTMLElementTagNameMap {
"ha-selector-file": HaFileSelector;
}
}

View File

@ -14,6 +14,7 @@ import "./ha-selector-datetime";
import "./ha-selector-device"; import "./ha-selector-device";
import "./ha-selector-duration"; import "./ha-selector-duration";
import "./ha-selector-entity"; import "./ha-selector-entity";
import "./ha-selector-file";
import "./ha-selector-number"; import "./ha-selector-number";
import "./ha-selector-object"; import "./ha-selector-object";
import "./ha-selector-select"; import "./ha-selector-select";

22
src/data/file_upload.ts Normal file
View File

@ -0,0 +1,22 @@
import { HomeAssistant } from "../types";
export const uploadFile = async (hass: HomeAssistant, file: File) => {
const fd = new FormData();
fd.append("file", file);
const resp = await hass.fetchWithAuth("/api/file_upload", {
method: "POST",
body: fd,
});
if (resp.status === 413) {
throw new Error(`Uploaded file is too large (${file.name})`);
} else if (resp.status !== 200) {
throw new Error("Unknown error");
}
const data = await resp.json();
return data.file_id;
};
export const removeFile = async (hass: HomeAssistant, file_id: string) =>
hass.callApi("DELETE", "file_upload", {
file_id,
});

View File

@ -16,6 +16,7 @@ export type Selector =
| DeviceSelector | DeviceSelector
| DurationSelector | DurationSelector
| EntitySelector | EntitySelector
| FileSelector
| IconSelector | IconSelector
| LocationSelector | LocationSelector
| MediaSelector | MediaSelector
@ -120,6 +121,12 @@ export interface EntitySelector {
}; };
} }
export interface FileSelector {
file: {
accept: string;
};
}
export interface IconSelector { export interface IconSelector {
icon: { icon: {
placeholder?: string; placeholder?: string;