mirror of
https://github.com/home-assistant/frontend.git
synced 2026-07-15 16:54:03 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 153290593b | |||
| 189477a1d4 |
@@ -20,8 +20,8 @@ import {
|
|||||||
subscribeCategoryRegistry,
|
subscribeCategoryRegistry,
|
||||||
updateCategoryRegistryEntry,
|
updateCategoryRegistryEntry,
|
||||||
} from "../data/category_registry";
|
} from "../data/category_registry";
|
||||||
import { showConfirmationDialog } from "../dialogs/generic/show-dialog-box";
|
|
||||||
import { SubscribeMixin } from "../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../mixins/subscribe-mixin";
|
||||||
|
import { confirmDeleteCategory } from "../panels/config/category/confirm-delete-category";
|
||||||
import { showCategoryRegistryDetailDialog } from "../panels/config/category/show-dialog-category-registry-detail";
|
import { showCategoryRegistryDetailDialog } from "../panels/config/category/show-dialog-category-registry-detail";
|
||||||
import { haStyleScrollbar } from "../resources/styles";
|
import { haStyleScrollbar } from "../resources/styles";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
@@ -199,17 +199,7 @@ export class HaFilterCategories extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _deleteCategory(id: string) {
|
private async _deleteCategory(id: string) {
|
||||||
const confirm = await showConfirmationDialog(this, {
|
if (!(await confirmDeleteCategory(this, this.hass))) {
|
||||||
title: this.hass.localize(
|
|
||||||
"ui.panel.config.category.editor.confirm_delete"
|
|
||||||
),
|
|
||||||
text: this.hass.localize(
|
|
||||||
"ui.panel.config.category.editor.confirm_delete_text"
|
|
||||||
),
|
|
||||||
confirmText: this.hass.localize("ui.common.delete"),
|
|
||||||
destructive: true,
|
|
||||||
});
|
|
||||||
if (!confirm) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ import type { Store } from "home-assistant-js-websocket/dist/store";
|
|||||||
import { stringCompare } from "../common/string/compare";
|
import { stringCompare } from "../common/string/compare";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
import { debounce } from "../common/util/debounce";
|
import { debounce } from "../common/util/debounce";
|
||||||
|
import type { RegistryEntry } from "./registry";
|
||||||
|
|
||||||
export interface CategoryRegistryEntry {
|
export interface CategoryRegistryEntry extends RegistryEntry {
|
||||||
category_id: string;
|
category_id: string;
|
||||||
name: string;
|
name: string;
|
||||||
icon: string | null;
|
icon: string | null;
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||||
|
|
||||||
|
export const confirmDeleteCategory = (
|
||||||
|
element: HTMLElement,
|
||||||
|
hass: HomeAssistant
|
||||||
|
) =>
|
||||||
|
showConfirmationDialog(element, {
|
||||||
|
title: hass.localize("ui.panel.config.category.editor.confirm_delete"),
|
||||||
|
text: hass.localize("ui.panel.config.category.editor.confirm_delete_text"),
|
||||||
|
confirmText: hass.localize("ui.common.delete"),
|
||||||
|
destructive: true,
|
||||||
|
});
|
||||||
@@ -0,0 +1,369 @@
|
|||||||
|
import {
|
||||||
|
mdiDelete,
|
||||||
|
mdiHelpCircleOutline,
|
||||||
|
mdiPalette,
|
||||||
|
mdiPencil,
|
||||||
|
mdiPlus,
|
||||||
|
mdiRobot,
|
||||||
|
mdiScriptText,
|
||||||
|
mdiTag,
|
||||||
|
mdiTools,
|
||||||
|
} from "@mdi/js";
|
||||||
|
import { html, LitElement } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { storage } from "../../../common/decorators/storage";
|
||||||
|
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||||
|
import type {
|
||||||
|
DataTableColumnContainer,
|
||||||
|
DataTableRowData,
|
||||||
|
RowClickedEvent,
|
||||||
|
} from "../../../components/data-table/ha-data-table";
|
||||||
|
import "../../../components/ha-button";
|
||||||
|
import "../../../components/ha-dropdown";
|
||||||
|
import type { HaDropdownSelectEvent } from "../../../components/ha-dropdown";
|
||||||
|
import "../../../components/ha-dropdown-item";
|
||||||
|
import "../../../components/ha-icon";
|
||||||
|
import "../../../components/ha-icon-button";
|
||||||
|
import "../../../components/ha-icon-overflow-menu";
|
||||||
|
import "../../../components/ha-svg-icon";
|
||||||
|
import type {
|
||||||
|
CategoryRegistryEntry,
|
||||||
|
CategoryRegistryEntryMutableParams,
|
||||||
|
} from "../../../data/category_registry";
|
||||||
|
import {
|
||||||
|
createCategoryRegistryEntry,
|
||||||
|
deleteCategoryRegistryEntry,
|
||||||
|
subscribeCategoryRegistry,
|
||||||
|
updateCategoryRegistryEntry,
|
||||||
|
} from "../../../data/category_registry";
|
||||||
|
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||||
|
import "../../../layouts/hass-tabs-subpage-data-table";
|
||||||
|
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||||
|
import type { HomeAssistant, Route } from "../../../types";
|
||||||
|
import { areaConfigTabs } from "../common/area-config-tabs";
|
||||||
|
import {
|
||||||
|
getCreatedAtTableColumn,
|
||||||
|
getModifiedAtTableColumn,
|
||||||
|
} from "../common/data-table-columns";
|
||||||
|
import { confirmDeleteCategory } from "./confirm-delete-category";
|
||||||
|
import { showCategoryRegistryDetailDialog } from "./show-dialog-category-registry-detail";
|
||||||
|
|
||||||
|
const CATEGORY_SCOPE_CONFIGS = [
|
||||||
|
{
|
||||||
|
scope: "automation",
|
||||||
|
icon: mdiRobot,
|
||||||
|
translationKey: "ui.panel.config.automation.caption",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: "scene",
|
||||||
|
icon: mdiPalette,
|
||||||
|
translationKey: "ui.panel.config.scene.caption",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: "script",
|
||||||
|
icon: mdiScriptText,
|
||||||
|
translationKey: "ui.panel.config.script.caption",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: "helpers",
|
||||||
|
icon: mdiTools,
|
||||||
|
translationKey: "ui.panel.config.helpers.caption",
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
type CategoryScope = (typeof CATEGORY_SCOPE_CONFIGS)[number]["scope"];
|
||||||
|
|
||||||
|
type CategoriesByScope = Record<CategoryScope, CategoryRegistryEntry[]>;
|
||||||
|
|
||||||
|
interface CategoryRowData extends CategoryRegistryEntry, DataTableRowData {
|
||||||
|
id: string;
|
||||||
|
scope: CategoryScope;
|
||||||
|
scopeName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EMPTY_CATEGORIES_BY_SCOPE: CategoriesByScope = {
|
||||||
|
automation: [],
|
||||||
|
scene: [],
|
||||||
|
script: [],
|
||||||
|
helpers: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("ha-config-categories")
|
||||||
|
export class HaConfigCategories extends SubscribeMixin(LitElement) {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public narrow = false;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public route!: Route;
|
||||||
|
|
||||||
|
@state() private _categories: CategoriesByScope = EMPTY_CATEGORIES_BY_SCOPE;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
@storage({
|
||||||
|
storage: "sessionStorage",
|
||||||
|
key: "categories-table-search",
|
||||||
|
state: true,
|
||||||
|
subscribe: false,
|
||||||
|
})
|
||||||
|
private _filter = "";
|
||||||
|
|
||||||
|
private _columns = memoizeOne((localize: LocalizeFunc) => {
|
||||||
|
const columns: DataTableColumnContainer<CategoryRowData> = {
|
||||||
|
icon: {
|
||||||
|
title: "",
|
||||||
|
moveable: false,
|
||||||
|
showNarrow: true,
|
||||||
|
label: localize("ui.panel.config.category.headers.icon"),
|
||||||
|
type: "icon",
|
||||||
|
template: (category) =>
|
||||||
|
category.icon
|
||||||
|
? html`<ha-icon .icon=${category.icon}></ha-icon>`
|
||||||
|
: html`<ha-svg-icon .path=${mdiTag}></ha-svg-icon>`,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
title: localize("ui.panel.config.category.headers.name"),
|
||||||
|
main: true,
|
||||||
|
flex: 2,
|
||||||
|
sortable: true,
|
||||||
|
filterable: true,
|
||||||
|
},
|
||||||
|
scopeName: {
|
||||||
|
title: localize("ui.panel.config.category.headers.scope"),
|
||||||
|
defaultHidden: true,
|
||||||
|
filterable: true,
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
created_at: getCreatedAtTableColumn(localize, this.hass),
|
||||||
|
modified_at: getModifiedAtTableColumn(localize, this.hass),
|
||||||
|
actions: {
|
||||||
|
lastFixed: true,
|
||||||
|
title: "",
|
||||||
|
label: localize("ui.panel.config.generic.headers.actions"),
|
||||||
|
showNarrow: true,
|
||||||
|
type: "overflow-menu",
|
||||||
|
template: (category) => html`
|
||||||
|
<ha-icon-overflow-menu
|
||||||
|
narrow
|
||||||
|
.items=${[
|
||||||
|
{
|
||||||
|
label: this.hass.localize(
|
||||||
|
"ui.panel.config.category.editor.edit"
|
||||||
|
),
|
||||||
|
path: mdiPencil,
|
||||||
|
action: () => this._openDialog(category.scope, category),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.hass.localize(
|
||||||
|
"ui.panel.config.category.editor.delete"
|
||||||
|
),
|
||||||
|
path: mdiDelete,
|
||||||
|
action: () => this._deleteCategory(category),
|
||||||
|
warning: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
></ha-icon-overflow-menu>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return columns;
|
||||||
|
});
|
||||||
|
|
||||||
|
private _data = memoizeOne(
|
||||||
|
(
|
||||||
|
categories: CategoriesByScope,
|
||||||
|
localize: LocalizeFunc
|
||||||
|
): CategoryRowData[] =>
|
||||||
|
CATEGORY_SCOPE_CONFIGS.flatMap((scopeConfig) =>
|
||||||
|
categories[scopeConfig.scope].map((category) => ({
|
||||||
|
...category,
|
||||||
|
id: `${scopeConfig.scope}:${category.category_id}`,
|
||||||
|
scope: scopeConfig.scope,
|
||||||
|
scopeName: localize(scopeConfig.translationKey),
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
private _groupOrder = memoizeOne((localize: LocalizeFunc) =>
|
||||||
|
CATEGORY_SCOPE_CONFIGS.map((scopeConfig) =>
|
||||||
|
localize(scopeConfig.translationKey)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
protected hassSubscribe() {
|
||||||
|
return CATEGORY_SCOPE_CONFIGS.map((scopeConfig) =>
|
||||||
|
subscribeCategoryRegistry(
|
||||||
|
this.hass.connection,
|
||||||
|
scopeConfig.scope,
|
||||||
|
(categories) => this._setCategories(scopeConfig.scope, categories)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
return html`
|
||||||
|
<hass-tabs-subpage-data-table
|
||||||
|
.hass=${this.hass}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
back-path="/config"
|
||||||
|
.route=${this.route}
|
||||||
|
.tabs=${areaConfigTabs}
|
||||||
|
.columns=${this._columns(this.hass.localize)}
|
||||||
|
.data=${this._data(this._categories, this.hass.localize)}
|
||||||
|
.noDataText=${this.hass.localize(
|
||||||
|
"ui.panel.config.category.no_categories"
|
||||||
|
)}
|
||||||
|
has-fab
|
||||||
|
.initialGroupColumn=${"scopeName"}
|
||||||
|
.groupOrder=${this._groupOrder(this.hass.localize)}
|
||||||
|
.filter=${this._filter}
|
||||||
|
@search-changed=${this._handleSearchChange}
|
||||||
|
@row-click=${this._editCategory}
|
||||||
|
clickable
|
||||||
|
id="id"
|
||||||
|
>
|
||||||
|
<ha-icon-button
|
||||||
|
slot="toolbar-icon"
|
||||||
|
@click=${this._showHelp}
|
||||||
|
.label=${this.hass.localize("ui.common.help")}
|
||||||
|
.path=${mdiHelpCircleOutline}
|
||||||
|
></ha-icon-button>
|
||||||
|
<ha-dropdown slot="fab" @wa-select=${this._handleCreateScope}>
|
||||||
|
<ha-button slot="trigger" id="fab" size="large">
|
||||||
|
<ha-svg-icon slot="start" .path=${mdiPlus}></ha-svg-icon>
|
||||||
|
${this.hass.localize("ui.panel.config.category.editor.create")}
|
||||||
|
</ha-button>
|
||||||
|
${CATEGORY_SCOPE_CONFIGS.map(
|
||||||
|
(scopeConfig) => html`
|
||||||
|
<ha-dropdown-item .value=${scopeConfig.scope}>
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${scopeConfig.icon}
|
||||||
|
slot="icon"
|
||||||
|
></ha-svg-icon>
|
||||||
|
${this.hass.localize(scopeConfig.translationKey)}
|
||||||
|
</ha-dropdown-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-dropdown>
|
||||||
|
</hass-tabs-subpage-data-table>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _showHelp() {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this.hass.localize("ui.panel.config.category.caption"),
|
||||||
|
text: html`
|
||||||
|
${this.hass.localize("ui.panel.config.category.introduction")}
|
||||||
|
<p>${this.hass.localize("ui.panel.config.category.introduction2")}</p>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _setCategories(
|
||||||
|
scope: CategoryScope,
|
||||||
|
categories: CategoryRegistryEntry[]
|
||||||
|
) {
|
||||||
|
this._categories = {
|
||||||
|
...this._categories,
|
||||||
|
[scope]: categories,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleCreateScope = (ev: HaDropdownSelectEvent<CategoryScope>) => {
|
||||||
|
this._openDialog(ev.detail.item.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
private _editCategory(ev: CustomEvent<RowClickedEvent>) {
|
||||||
|
const category = this._data(this._categories, this.hass.localize).find(
|
||||||
|
(row) => row.id === ev.detail.id
|
||||||
|
);
|
||||||
|
if (!category) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._openDialog(category.scope, category);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _openDialog(scope: CategoryScope, entry?: CategoryRegistryEntry) {
|
||||||
|
showCategoryRegistryDetailDialog(this, {
|
||||||
|
scope,
|
||||||
|
entry,
|
||||||
|
createEntry: entry
|
||||||
|
? undefined
|
||||||
|
: (values) => this._createCategory(scope, values),
|
||||||
|
updateEntry: entry
|
||||||
|
? (values) => this._updateCategory(scope, entry, values)
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _createCategory(
|
||||||
|
scope: CategoryScope,
|
||||||
|
values: CategoryRegistryEntryMutableParams
|
||||||
|
): Promise<CategoryRegistryEntry> {
|
||||||
|
const category = await createCategoryRegistryEntry(
|
||||||
|
this.hass,
|
||||||
|
scope,
|
||||||
|
values
|
||||||
|
);
|
||||||
|
this._setCategories(scope, [...this._categories[scope], category]);
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _updateCategory(
|
||||||
|
scope: CategoryScope,
|
||||||
|
entry: CategoryRegistryEntry,
|
||||||
|
values: Partial<CategoryRegistryEntryMutableParams>
|
||||||
|
): Promise<CategoryRegistryEntry> {
|
||||||
|
const category = await updateCategoryRegistryEntry(
|
||||||
|
this.hass,
|
||||||
|
scope,
|
||||||
|
entry.category_id,
|
||||||
|
values
|
||||||
|
);
|
||||||
|
this._setCategories(
|
||||||
|
scope,
|
||||||
|
this._categories[scope].map((current) =>
|
||||||
|
current.category_id === entry.category_id ? category : current
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _deleteCategory(entry: CategoryRowData) {
|
||||||
|
if (!(await confirmDeleteCategory(this, this.hass))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await deleteCategoryRegistryEntry(
|
||||||
|
this.hass,
|
||||||
|
entry.scope,
|
||||||
|
entry.category_id
|
||||||
|
);
|
||||||
|
this._setCategories(
|
||||||
|
entry.scope,
|
||||||
|
this._categories[entry.scope].filter(
|
||||||
|
(category) => category.category_id !== entry.category_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
text:
|
||||||
|
err instanceof Error
|
||||||
|
? err.message
|
||||||
|
: this.hass.localize(
|
||||||
|
"ui.panel.config.category.editor.unknown_error"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleSearchChange(ev: CustomEvent) {
|
||||||
|
this._filter = ev.detail.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-config-categories": HaConfigCategories;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { mdiLabel, mdiMapMarkerRadius, mdiSofa, mdiTag } from "@mdi/js";
|
||||||
|
import type { PageNavigation } from "../../../layouts/hass-tabs-subpage";
|
||||||
|
|
||||||
|
export const areaConfigTabs: PageNavigation[] = [
|
||||||
|
{
|
||||||
|
component: "areas",
|
||||||
|
path: "/config/areas",
|
||||||
|
translationKey: "ui.panel.config.areas.caption",
|
||||||
|
iconPath: mdiSofa,
|
||||||
|
iconColor: "#2D338F",
|
||||||
|
core: true,
|
||||||
|
adminOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: "categories",
|
||||||
|
path: "/config/categories",
|
||||||
|
translationKey: "ui.panel.config.category.caption",
|
||||||
|
iconPath: mdiTag,
|
||||||
|
iconColor: "#2D338F",
|
||||||
|
core: true,
|
||||||
|
adminOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: "labels",
|
||||||
|
path: "/config/labels",
|
||||||
|
translationKey: "ui.panel.config.labels.caption",
|
||||||
|
iconPath: mdiLabel,
|
||||||
|
iconColor: "#2D338F",
|
||||||
|
core: true,
|
||||||
|
adminOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
component: "zone",
|
||||||
|
path: "/config/zone",
|
||||||
|
translationKey: "ui.panel.config.zone.caption",
|
||||||
|
iconPath: mdiMapMarkerRadius,
|
||||||
|
iconColor: "#E48629",
|
||||||
|
adminOnly: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -10,9 +10,7 @@ import {
|
|||||||
mdiFlask,
|
mdiFlask,
|
||||||
mdiHammer,
|
mdiHammer,
|
||||||
mdiInformationOutline,
|
mdiInformationOutline,
|
||||||
mdiLabel,
|
|
||||||
mdiLightningBolt,
|
mdiLightningBolt,
|
||||||
mdiMapMarkerRadius,
|
|
||||||
mdiMemory,
|
mdiMemory,
|
||||||
mdiMicrophone,
|
mdiMicrophone,
|
||||||
mdiNetwork,
|
mdiNetwork,
|
||||||
@@ -47,6 +45,7 @@ import type { RouterOptions } from "../../layouts/hass-router-page";
|
|||||||
import { HassRouterPage } from "../../layouts/hass-router-page";
|
import { HassRouterPage } from "../../layouts/hass-router-page";
|
||||||
import type { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
import type { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
||||||
import type { HomeAssistant, Route } from "../../types";
|
import type { HomeAssistant, Route } from "../../types";
|
||||||
|
import { areaConfigTabs } from "./common/area-config-tabs";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// for fire event
|
// for fire event
|
||||||
@@ -417,34 +416,7 @@ export const configSections: Record<string, PageNavigation[]> = {
|
|||||||
adminOnly: true,
|
adminOnly: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
areas: [
|
areas: areaConfigTabs,
|
||||||
{
|
|
||||||
component: "areas",
|
|
||||||
path: "/config/areas",
|
|
||||||
translationKey: "ui.panel.config.areas.caption",
|
|
||||||
iconPath: mdiSofa,
|
|
||||||
iconColor: "#2D338F",
|
|
||||||
core: true,
|
|
||||||
adminOnly: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
component: "labels",
|
|
||||||
path: "/config/labels",
|
|
||||||
translationKey: "ui.panel.config.labels.caption",
|
|
||||||
iconPath: mdiLabel,
|
|
||||||
iconColor: "#2D338F",
|
|
||||||
core: true,
|
|
||||||
adminOnly: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
component: "zone",
|
|
||||||
path: "/config/zone",
|
|
||||||
translationKey: "ui.panel.config.zone.caption",
|
|
||||||
iconPath: mdiMapMarkerRadius,
|
|
||||||
iconColor: "#E48629",
|
|
||||||
adminOnly: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
general: [
|
general: [
|
||||||
{
|
{
|
||||||
path: "/config/general",
|
path: "/config/general",
|
||||||
@@ -631,6 +603,10 @@ class HaPanelConfig extends HassRouterPage {
|
|||||||
tag: "ha-config-integrations",
|
tag: "ha-config-integrations",
|
||||||
load: () => import("./integrations/ha-config-integrations"),
|
load: () => import("./integrations/ha-config-integrations"),
|
||||||
},
|
},
|
||||||
|
categories: {
|
||||||
|
tag: "ha-config-categories",
|
||||||
|
load: () => import("./category/ha-config-categories"),
|
||||||
|
},
|
||||||
labels: {
|
labels: {
|
||||||
tag: "ha-config-labels",
|
tag: "ha-config-labels",
|
||||||
load: () => import("./labels/ha-config-labels"),
|
load: () => import("./labels/ha-config-labels"),
|
||||||
|
|||||||
@@ -163,6 +163,9 @@ export const getMyRedirects = (): Redirects => ({
|
|||||||
entities: {
|
entities: {
|
||||||
redirect: "/config/entities",
|
redirect: "/config/entities",
|
||||||
},
|
},
|
||||||
|
categories: {
|
||||||
|
redirect: "/config/categories",
|
||||||
|
},
|
||||||
labels: {
|
labels: {
|
||||||
redirect: "/config/labels",
|
redirect: "/config/labels",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2675,7 +2675,7 @@
|
|||||||
"secondary": "Manage who can access your home"
|
"secondary": "Manage who can access your home"
|
||||||
},
|
},
|
||||||
"areas": {
|
"areas": {
|
||||||
"main": "Areas, labels & zones",
|
"main": "Areas, categories, labels & zones",
|
||||||
"secondary": "Manage locations in and around your house"
|
"secondary": "Manage locations in and around your house"
|
||||||
},
|
},
|
||||||
"companion": {
|
"companion": {
|
||||||
@@ -3109,6 +3109,15 @@
|
|||||||
},
|
},
|
||||||
"category": {
|
"category": {
|
||||||
"caption": "Categories",
|
"caption": "Categories",
|
||||||
|
"description": "Group automations, scenes, scripts, and helpers",
|
||||||
|
"headers": {
|
||||||
|
"name": "Name",
|
||||||
|
"icon": "Icon",
|
||||||
|
"scope": "Type"
|
||||||
|
},
|
||||||
|
"no_categories": "You don't have any categories",
|
||||||
|
"introduction": "Categories can help you organize your automations, scenes, scripts, and helpers. Each type has its own categories.",
|
||||||
|
"introduction2": "Create categories here, then assign them from the matching settings page.",
|
||||||
"assign": {
|
"assign": {
|
||||||
"edit": "Edit category",
|
"edit": "Edit category",
|
||||||
"assign": "Assign category",
|
"assign": "Assign category",
|
||||||
|
|||||||
Reference in New Issue
Block a user