mirror of
https://github.com/home-assistant/frontend.git
synced 2026-10-21 05:03:28 +00:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
624865b2a9 | ||
|
|
a321b07bba | ||
|
|
cfd5b4fd8d | ||
|
|
2944efe1b7 | ||
|
|
9ec5e94c29 | ||
|
|
bcb123850d |
No files matched your search
@@ -2,10 +2,14 @@
|
||||
|
||||
import fs from "fs-extra";
|
||||
import gulp from "gulp";
|
||||
import { createHash } from "node:crypto";
|
||||
import { createRequire } from "node:module";
|
||||
import path from "path";
|
||||
import paths from "../paths.cjs";
|
||||
import { ensureMapAssets, mapAssetsDir } from "./map-assets.js";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
const npmPath = (...parts) =>
|
||||
path.resolve(paths.root_dir, "node_modules", ...parts);
|
||||
const polyPath = (...parts) => path.resolve(paths.root_dir, ...parts);
|
||||
@@ -83,9 +87,24 @@ async function copyMapPanel(staticDir) {
|
||||
|
||||
function copyZXingWasm(staticDir) {
|
||||
const staticPath = genStaticPath(staticDir);
|
||||
copyFileDir(
|
||||
npmPath("zxing-wasm/dist/reader/zxing_reader.wasm"),
|
||||
staticPath("js")
|
||||
// Resolve through barcode-detector, the wasm must match the zxing-wasm JS it bundles
|
||||
const zxingWasm = createRequire(require.resolve("barcode-detector")).resolve(
|
||||
"zxing-wasm/reader/zxing_reader.wasm"
|
||||
);
|
||||
const {
|
||||
ZXING_WASM_SHA256,
|
||||
ZXING_WASM_VERSION,
|
||||
} = require("barcode-detector/pure");
|
||||
const wasm = fs.readFileSync(zxingWasm);
|
||||
if (createHash("sha256").update(wasm).digest("hex") !== ZXING_WASM_SHA256) {
|
||||
throw new Error(
|
||||
`${zxingWasm} does not match the zxing-wasm ${ZXING_WASM_VERSION} bundled in barcode-detector`
|
||||
);
|
||||
}
|
||||
// Versioned file name, see locateFile in ha-qr-scanner
|
||||
fs.outputFileSync(
|
||||
staticPath("js", `zxing_reader-${ZXING_WASM_VERSION}.wasm`),
|
||||
wasm
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,9 @@ gulp.task("rspack-watch-app", () => {
|
||||
: createAppConfig({ isProdBuild: false, latestBuild: true })
|
||||
).watch({ poll: isWsl }, doneHandler());
|
||||
gulp.watch(
|
||||
path.join(paths.translations_src, "en.json"),
|
||||
// Watch the folder via a glob; git replaces en.json on checkout/stash,
|
||||
// which can permanently drop a watch on the file itself
|
||||
path.join(paths.translations_src, "*.json"),
|
||||
gulp.series("build-translations", "copy-translations-app")
|
||||
);
|
||||
});
|
||||
|
||||
@@ -40,6 +40,21 @@ const TOOLCHAIN_PACKAGES = [
|
||||
"caniuse-lite",
|
||||
];
|
||||
|
||||
// Not direct dependencies: read the copy the package that loads them uses.
|
||||
const TOOLCHAIN_PACKAGE_PARENTS = {
|
||||
terser: "terser-webpack-plugin",
|
||||
"caniuse-lite": "browserslist",
|
||||
};
|
||||
|
||||
const toolchainVersion = (pkg) => {
|
||||
const parent = TOOLCHAIN_PACKAGE_PARENTS[pkg];
|
||||
const lookup = parent && [
|
||||
path.dirname(require.resolve(`${parent}/package.json`)),
|
||||
];
|
||||
return require(require.resolve(`${pkg}/package.json`, { paths: lookup }))
|
||||
.version;
|
||||
};
|
||||
|
||||
// Our own build logic — the config, loaders and babel plugins. Their contents
|
||||
// (not their paths) go into the cache version, so a change invalidates the
|
||||
// cache the same way `buildDependencies` would, but without tying validity to
|
||||
@@ -63,9 +78,7 @@ const PATCHES_DIR = path.join(paths.root_dir, "patches");
|
||||
// stays valid when reused on a different machine or checkout path.
|
||||
const cacheVersion = () => {
|
||||
const parts = [
|
||||
...TOOLCHAIN_PACKAGES.map(
|
||||
(pkg) => `${pkg}@${require(`${pkg}/package.json`).version}`
|
||||
),
|
||||
...TOOLCHAIN_PACKAGES.map((pkg) => `${pkg}@${toolchainVersion(pkg)}`),
|
||||
...CONFIG_FILES.map(
|
||||
(file) => `${path.basename(file)}:${fs.readFileSync(file, "utf8")}`
|
||||
),
|
||||
|
||||
+3
-2
@@ -133,14 +133,15 @@
|
||||
"workbox-routing": "7.4.1",
|
||||
"workbox-strategies": "7.4.1",
|
||||
"xss": "1.0.15",
|
||||
"zrender": "6.1.0",
|
||||
"zxing-wasm": "3.1.5"
|
||||
"zrender": "6.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ampproject/remapping": "2.3.0",
|
||||
"@babel/core": "8.0.7",
|
||||
"@babel/helper-compilation-targets": "8.0.7",
|
||||
"@babel/helper-define-polyfill-provider": "1.0.0",
|
||||
"@babel/plugin-transform-class-properties": "8.0.1",
|
||||
"@babel/plugin-transform-private-methods": "8.0.1",
|
||||
"@babel/plugin-transform-runtime": "8.0.6",
|
||||
"@babel/preset-env": "8.0.7",
|
||||
"@bundle-stats/plugin-webpack-filter": "4.22.3",
|
||||
|
||||
Generated
+6
-11
@@ -462,9 +462,6 @@ importers:
|
||||
zrender:
|
||||
specifier: 6.1.0
|
||||
version: 6.1.0
|
||||
zxing-wasm:
|
||||
specifier: 3.1.5
|
||||
version: 3.1.5
|
||||
devDependencies:
|
||||
'@ampproject/remapping':
|
||||
specifier: 2.3.0
|
||||
@@ -478,6 +475,12 @@ importers:
|
||||
'@babel/helper-define-polyfill-provider':
|
||||
specifier: 1.0.0
|
||||
version: 1.0.0(@babel/[email protected])
|
||||
'@babel/plugin-transform-class-properties':
|
||||
specifier: 8.0.1
|
||||
version: 8.0.1(@babel/[email protected])
|
||||
'@babel/plugin-transform-private-methods':
|
||||
specifier: 8.0.1
|
||||
version: 8.0.1(@babel/[email protected])
|
||||
'@babel/plugin-transform-runtime':
|
||||
specifier: 8.0.6
|
||||
version: 8.0.6(@babel/[email protected])
|
||||
@@ -7836,9 +7839,6 @@ packages:
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-3lC9BJk4fR5ZJxcGjb0hVnDFOW7KpLXHIebiBmVd4FDRQZVeObztoTKxRUPxlWwSgxrMRONK0u50hBD1aTYEKg==}
|
||||
|
||||
[email protected]:
|
||||
resolution: {integrity: sha512-jmxXvTCR/qZxMz2XwR6V+nL2BlDTD1aux7ZWSH9BV77TG9u4k0VyHba/NCCHBHJ60Wg6VV0QL/SMlJczKhJI4w==}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@ampproject/[email protected]':
|
||||
@@ -15838,8 +15838,3 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/emscripten': 1.41.6
|
||||
type-fest: 5.10.0
|
||||
|
||||
[email protected]:
|
||||
dependencies:
|
||||
'@types/emscripten': 1.41.6
|
||||
type-fest: 5.10.0
|
||||
@@ -98,6 +98,11 @@
|
||||
"groupName": "date-fns",
|
||||
"matchPackageNames": ["date-fns", "date-fns-tz"]
|
||||
},
|
||||
{
|
||||
"description": "Group ECharts with zrender, which we import directly and must match the version echarts depends on",
|
||||
"groupName": "echarts",
|
||||
"matchPackageNames": ["echarts", "zrender"]
|
||||
},
|
||||
{
|
||||
"description": "Group formatjs monorepo package",
|
||||
"groupName": "formatjs",
|
||||
|
||||
@@ -14,7 +14,6 @@ export type LocalizeKeys =
|
||||
| `ui.card.weather.attributes.${string}`
|
||||
| `ui.card.weather.cardinal_direction.${string}`
|
||||
| `ui.card.lawn_mower.actions.${string}`
|
||||
| `ui.common.${string}`
|
||||
| `ui.components.calendar.event.rrule.${string}`
|
||||
| `ui.components.selectors.file.${string}`
|
||||
| `ui.dialogs.entity_registry.editor.${string}`
|
||||
|
||||
@@ -38,6 +38,10 @@ export class HaBaseTimeInput extends LitElement {
|
||||
*/
|
||||
@property() label?: string;
|
||||
|
||||
/** Accessible name for the input when it has no visible label. */
|
||||
@property({ attribute: "accessible-label" })
|
||||
public accessibleLabel?: string;
|
||||
|
||||
/**
|
||||
* Helper for the input
|
||||
*/
|
||||
@@ -178,6 +182,7 @@ export class HaBaseTimeInput extends LitElement {
|
||||
class="time-input-wrap"
|
||||
role="group"
|
||||
aria-labelledby=${ifDefined(this.label ? "label" : undefined)}
|
||||
aria-label=${ifDefined(this.label ? undefined : this.accessibleLabel)}
|
||||
>
|
||||
${
|
||||
this.enableSign
|
||||
|
||||
@@ -50,6 +50,10 @@ export class HaDateInput extends LitElement {
|
||||
|
||||
@property() public label?: string;
|
||||
|
||||
/** Accessible name for the input when it has no visible label. */
|
||||
@property({ attribute: "accessible-label" })
|
||||
public accessibleLabel?: string;
|
||||
|
||||
@property() public helper?: string;
|
||||
|
||||
@property({ attribute: "can-clear", type: Boolean }) public canClear = false;
|
||||
@@ -65,6 +69,7 @@ export class HaDateInput extends LitElement {
|
||||
.label=${this.label ?? ""}
|
||||
.hint=${this.helper ?? ""}
|
||||
.disabled=${this.disabled}
|
||||
.accessibleLabel=${this.accessibleLabel}
|
||||
readonly
|
||||
@click=${this._openDialog}
|
||||
@keydown=${this._keyDown}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { customElement, property, query, state } from "lit/decorators";
|
||||
// and "qr-scanner" defaults to a suboptimal implementation if it is not available.
|
||||
// The following import makes a better implementation available that is based on a
|
||||
// WebAssembly port of ZXing:
|
||||
import { prepareZXingModule } from "barcode-detector";
|
||||
import { prepareZXingModule, ZXING_WASM_VERSION } from "barcode-detector";
|
||||
import type QrScanner from "qr-scanner";
|
||||
import { consume } from "../common/decorators/consume";
|
||||
import { consumeLocalize } from "../common/decorators/consume-context-entry";
|
||||
@@ -29,7 +29,8 @@ prepareZXingModule({
|
||||
overrides: {
|
||||
locateFile: (path: string, prefix: string) => {
|
||||
if (path.endsWith(".wasm")) {
|
||||
return "/static/js/zxing_reader.wasm";
|
||||
// Versioned, /static is cached for a month and the glue only works with its own wasm
|
||||
return `/static/js/zxing_reader-${ZXING_WASM_VERSION}.wasm`;
|
||||
}
|
||||
return prefix + path;
|
||||
},
|
||||
|
||||
@@ -15,6 +15,10 @@ export class HaTimeInput extends LitElement {
|
||||
|
||||
@property() public label?: string;
|
||||
|
||||
/** Accessible name for the input when it has no visible label. */
|
||||
@property({ attribute: "accessible-label" })
|
||||
public accessibleLabel?: string;
|
||||
|
||||
@property() public helper?: string;
|
||||
|
||||
@property({ type: Boolean }) public disabled = false;
|
||||
@@ -61,6 +65,7 @@ export class HaTimeInput extends LitElement {
|
||||
return html`
|
||||
<ha-base-time-input
|
||||
.label=${this.label}
|
||||
.accessibleLabel=${this.accessibleLabel}
|
||||
.hours=${hours}
|
||||
.minutes=${minutes}
|
||||
.seconds=${seconds}
|
||||
|
||||
@@ -441,7 +441,7 @@ class SupervisorAppConfig extends DirtyStateProviderMixin<
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.apps.configuration.confirm.reset_options.text"
|
||||
),
|
||||
confirmText: this.hass.localize("ui.common.reset_options"),
|
||||
confirmText: this.hass.localize("ui.common.reset"),
|
||||
dismissText: this.hass.localize("ui.common.cancel"),
|
||||
destructive: true,
|
||||
});
|
||||
|
||||
@@ -44,11 +44,14 @@ class HuiDateEntityRow extends LitElement implements LovelaceRow {
|
||||
|
||||
const unavailable = stateObj.state === UNAVAILABLE;
|
||||
|
||||
const name = this.hass.formatEntityName(stateObj, this._config.name);
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||
<ha-date-input
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${unavailable}
|
||||
.accessibleLabel=${name}
|
||||
.value=${
|
||||
stateObj.state === UNAVAILABLE || stateObj.state === UNKNOWN
|
||||
? undefined
|
||||
|
||||
@@ -72,6 +72,7 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
|
||||
</ha-date-input>
|
||||
<ha-time-input
|
||||
.value=${time}
|
||||
.accessibleLabel=${name}
|
||||
.disabled=${unavailable}
|
||||
.locale=${this.hass.locale}
|
||||
@value-changed=${this._timeChanged}
|
||||
|
||||
@@ -68,6 +68,7 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
|
||||
? html`
|
||||
<ha-date-input
|
||||
.label=${stateObj.attributes.has_time ? name : undefined}
|
||||
.accessibleLabel=${stateObj.attributes.has_time ? undefined : name}
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
.value=${stateToIsoDateString(stateObj)}
|
||||
@@ -88,6 +89,7 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
|
||||
? stateObj.state.split(" ")[1]
|
||||
: stateObj.state
|
||||
}
|
||||
.accessibleLabel=${name}
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
@value-changed=${this._timeChanged}
|
||||
|
||||
@@ -44,6 +44,8 @@ class HuiTimeEntityRow extends LitElement implements LovelaceRow {
|
||||
|
||||
const unavailable = stateObj.state === UNAVAILABLE;
|
||||
|
||||
const name = this.hass.formatEntityName(stateObj, this._config.name);
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||
<ha-time-input
|
||||
@@ -52,6 +54,7 @@ class HuiTimeEntityRow extends LitElement implements LovelaceRow {
|
||||
? undefined
|
||||
: stateObj.state
|
||||
}
|
||||
.accessibleLabel=${name}
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${unavailable}
|
||||
@value-changed=${this._timeChanged}
|
||||
|
||||
@@ -29,6 +29,7 @@ const marketplaceTableParams = {
|
||||
source: "string?",
|
||||
sort: "string?",
|
||||
direction: "string?",
|
||||
group: "string?",
|
||||
} satisfies Redirect["params"];
|
||||
|
||||
export const getMyRedirects = (): Redirects => ({
|
||||
|
||||
@@ -500,6 +500,7 @@
|
||||
"submit": "Submit",
|
||||
"rename": "Rename",
|
||||
"reset": "Reset",
|
||||
"retry": "Retry",
|
||||
"search": "[%key:ui::components::data-table::search%]",
|
||||
"ok": "OK",
|
||||
"yes": "Yes",
|
||||
|
||||
Reference in new issue
Block a user