feat: Add permanent menu items for hidden menus (#1636)

This commit is contained in:
Dermot Duffy
2024-10-13 11:05:33 -07:00
committed by GitHub
parent 9ca56d061f
commit 0ec9afbad2
15 changed files with 230 additions and 85 deletions
+101 -22
View File
@@ -22,7 +22,7 @@ See the [conditional elements example](../../../examples.md?id=conditional-eleme
## `menu-icon` ## `menu-icon`
Add an arbitrary icon to the Frigate Card menu. Configuration is ~identical to that of the [Picture Elements Icon](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) except with a type name of `custom:frigate-card-menu-icon`. Add an arbitrary icon to the Frigate Card menu.
```yaml ```yaml
elements: elements:
@@ -30,6 +30,20 @@ elements:
# [...] # [...]
``` ```
Configuration is similar to a stock [Picture Elements Icon](https://www.home-assistant.io/lovelace/picture-elements/#icon-element).
| Parameter | Default | Description |
| ------------------------------------------------------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | | Must be `custom:frigate-card-menu-icon`. |
| `enabled` | `true` | Whether or not to show this menu item. |
| `entity` | | An optional Home Assistant entity for use with actions. |
| `icon` | | An required icon to display, e.g. `mdi:car` |
| `permanent` | `false` | If `false` the menu item is hidden when the menu has the `hidden` style and the menu is closed, otherwise it is shown (and sorted to the front). |
| `priority` | `50` | The menu item priority. Higher priority item are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`. |
| `style` | | Position and style the element using CSS. |
| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](../../actions/README.md) to take when this item is interacted with. |
| `title` | | An optional title to display. |
## `menu-submenu` ## `menu-submenu`
Add a configurable submenu dropdown. Add a configurable submenu dropdown.
@@ -40,12 +54,18 @@ elements:
# [...] # [...]
``` ```
Parameters for this element are identical to the parameters of the [stock Home Assistant Icon Element](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) with the exception of these parameters which differ: | Parameter | Default | Description |
| ------------------------------------------------------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Parameter | Description | | `type` | | Must be `custom:frigate-card-menu-submenu`. |
| --------- | ------------------------------------------- | | `enabled` | `true` | Whether or not to show this menu item. |
| `type` | Must be `custom:frigate-card-menu-submenu`. | | `entity` | | An optional Home Assistant entity for use with actions. |
| `items` | A list of menu items, as described below. | | `icon` | | An required icon to display, e.g. `mdi:car` |
| `items` | | A list of menu items, as described below. |
| `permanent` | `false` | If `false` the menu item is hidden when the menu has the `hidden` style and the menu is closed, otherwise it is shown (and sorted to the front). |
| `priority` | `50` | The menu item priority. Higher priority item are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`. |
| `style` | | Position and style the element using CSS. |
| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](../../actions/README.md) to take when this item is interacted with. |
| `title` | | An optional title to display. |
### Submenu items ### Submenu items
@@ -70,25 +90,46 @@ elements:
# [...] # [...]
``` ```
Parameters for the `custom:frigate-card-menu-submenu-select` element are identical to the parameters of the [stock Home Assistant State Icon Element](https://www.home-assistant.io/dashboards/picture-elements/#state-icon) with the exception of these parameters which differ: | Parameter | Default | Description |
| ------------------------------------------------------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Parameter | Description | | `type` | | Must be `custom:frigate-card-menu-submenu-select`. |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | `true` | Whether or not to show this menu item. |
| `type` | Must be `custom:frigate-card-menu-submenu-select`. | | `entity` | | An optional Home Assistant entity for use with actions. |
| `options` | An optional dictionary of overrides keyed by the option name that the given select entity supports. These options can be used to set or override submenu item parameters on a per-option basis. The format is as described in [Submenu Items](./README.md?id=submenu-items) above. | | `icon` | | An required icon to display, e.g. `mdi:car` |
| `options` | | An optional dictionary of overrides keyed by the option name that the given select entity supports. These options can be used to set or override submenu item parameters on a per-option basis. The format is as described in [Submenu Items](./README.md?id=submenu-items) above. |
| `permanent` | `false` | If `false` the menu item is hidden when the menu has the `hidden` style and the menu is closed, otherwise it is shown (and sorted to the front). |
| `priority` | `50` | The menu item priority. Higher priority item are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`. |
| `style` | | Position and style the element using CSS. |
| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](../../actions/README.md) to take when this item is interacted with. |
| `title` | | An optional title to display. |
See the `select` [submenu example](../../../examples.md?id=select-submenu). See the `select` [submenu example](../../../examples.md?id=select-submenu).
## `state-icon` ## `state-icon`
Add a state icon to the Frigate Card menu that represents the state of a Home Assistant entity. Configuration is ~identical to that of the [Picture Elements State Icon](https://www.home-assistant.io/lovelace/picture-elements/#state-icon) except with a type name of `custom:frigate-card-menu-state-icon`. Add a state icon to the Frigate Card menu that represents the state of a Home Assistant entity.
```yaml ```yaml
elements: elements:
- type: custom:frigate-card-menu-icon - type: custom:frigate-card-menu-state-icon
# [...] # [...]
``` ```
Configuration is similar to a stock [Picture Elements State Icon](https://www.home-assistant.io/lovelace/picture-elements/#state-icon).
| Parameter | Default | Description |
| ------------------------------------------------------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | | Must be `custom:frigate-card-menu-state-icon`. |
| `enabled` | `true` | Whether or not to show this menu item. |
| `entity` | | An optional Home Assistant entity for use with actions. |
| `icon` | | An required icon to display, e.g. `mdi:car` |
| `permanent` | `false` | If `false` the menu item is hidden when the menu has the `hidden` style and the menu is closed, otherwise it is shown (and sorted to the front). |
| `priority` | `50` | The menu item priority. Higher priority item are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`. |
| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](../../actions/README.md) to take when this item is interacted with. |
| `state_color` | `true` | Set to true to have icons colored when entity is active. |
| `style` | | Position and style the element using CSS. |
| `title` | | An optional title to display. |
## `status-bar-icon` ## `status-bar-icon`
Add an arbitrary icon to the status bar. Add an arbitrary icon to the status bar.
@@ -154,44 +195,82 @@ elements:
## Fully expanded reference ## Fully expanded reference
> [Actions](../../actions/README.md) are omitted for simplicity. ?> [Actions](../../actions/README.md) are omitted for simplicity.
[](../../common/expanded-warning.md ':include') [](../../common/expanded-warning.md ':include')
```yaml ```yaml
elements: elements:
- type: custom:frigate-card-menu-icon - type: custom:frigate-card-menu-icon
enabled: true
entity: light.office_main_lights
icon: mdi:car icon: mdi:car
permanent: false
priority: 50
style:
color: white
title: Vroom title: Vroom
- type: custom:frigate-card-menu-state-icon - type: custom:frigate-card-menu-state-icon
enabled: true
entity: light.office_main_lights entity: light.office_main_lights
title: Office lights
icon: mdi:chair-rolling icon: mdi:chair-rolling
permanent: false
priority: 50
state_color: true state_color: true
style:
color: white
title: Office lights
- type: custom:frigate-card-menu-submenu - type: custom:frigate-card-menu-submenu
enabled: true
entity: light.office_main_lights
icon: mdi:menu icon: mdi:menu
items: items:
- title: Lights - enabled: true
icon: mdi:lightbulb
entity: light.office_main_lights entity: light.office_main_lights
icon: mdi:lightbulb
selected: false
state_color: true
style:
color: white
tap_action: tap_action:
action: toggle action: toggle
- title: Google title: Lights
- enabled: true
icon: mdi:google icon: mdi:google
enabled: false selected: false
style:
color: white
tap_action: tap_action:
action: url action: url
url_path: https://www.google.com url_path: https://www.google.com
title: Google
permanent: false
priority: 50
style:
color: white
title: Office lights
- type: custom:frigate-card-menu-submenu-select - type: custom:frigate-card-menu-submenu-select
icon: mdi:lamps enabled: true
entity: input_select.kitchen_scene entity: input_select.kitchen_scene
icon: mdi:lamps
options: options:
items:
scene.kitchen_cooking_scene: scene.kitchen_cooking_scene:
enabled: true
icon: mdi:chef-hat icon: mdi:chef-hat
selected: false
state_color: true
style:
color: white
title: Cooking time! title: Cooking time!
scene.kitchen_tv_scene: scene.kitchen_tv_scene:
icon: mdi:television icon: mdi:television
title: TV! title: TV!
permanent: false
priority: 50
style:
color: white
title: 'Kitchen Scene'
# Show a pig icon if a variety of conditions are met. # Show a pig icon if a variety of conditions are met.
- type: custom:frigate-card-conditional - type: custom:frigate-card-conditional
elements: elements:
+7 -7
View File
@@ -51,12 +51,12 @@ menu:
### Options for each button ### Options for each button
| Option | Default | Description | | Option | Default | Description |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `alignment` | `matching` | Whether this button should have an alignment that is `matching` the menu alignment or `opposing` the menu. Can be used to create two separate groups of buttons on the menu. `priority` orders buttons within a given `alignment`. | | `alignment` | `matching` | Whether this button should have an alignment that is `matching` the menu alignment or `opposing` the menu. Can be used to create two separate groups of buttons on the menu. `priority` orders buttons within a given `alignment`. |
| `enabled` | `true` for `frigate`, `cameras`, `substreams`, `live`, `clips`, `snapshots`, `timeline`, `download`, `camera_ui`, `fullscreen`, `media_player`, `display_mode` and `ptz_home`. `false` for `image`, `expand`, `microphone`, `mute`, `play`, `recordings`, `screenshot`, `ptz_controls` | Whether or not to show the button. | | `enabled` | `true` for `frigate`, `cameras`, `substreams`, `live`, `clips`, `snapshots`, `timeline`, `download`, `camera_ui`, `fullscreen`, `media_player`, `display_mode` and `ptz_home`. `false` for `image`, `expand`, `microphone`, `mute`, `play`, `recordings`, `screenshot`, `ptz_controls` | Whether or not to show the button. |
| `icon` | | An icon to overriding the default for that button, e.g. `mdi:camera-front`. | | `icon` | | An icon to overriding the default for that button, e.g. `mdi:camera-front`. |
| `priority` | `50` | The button priority. Higher priority buttons are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`. | | `permanent` | `false` | If `false` the menu item is hidden when the menu has the `hidden` style and the menu is closed, otherwise it is shown (and sorted to the front). |
## `style` ## `style`
@@ -64,7 +64,7 @@ This card supports several menu styles.
| Key | Description | Screenshot | | Key | Description | Screenshot |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `hidden` | Hide the menu by default, expandable upon clicking the Frigate button. | ![](../images/menu-mode-hidden.png 'Menu hidden :size=400') | | `hidden` | Hide the menu by default. It may be toggled open as needed. | ![](../images/menu-mode-hidden.png 'Menu hidden :size=400') |
| `hover-card` | Overlay the menu over the card contents when the mouse is over the **card**, otherwise it is not shown. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png 'Menu hover-card :size=400') | | `hover-card` | Overlay the menu over the card contents when the mouse is over the **card**, otherwise it is not shown. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png 'Menu hover-card :size=400') |
| `hover` | Overlay the menu over the card contents when the mouse is over the **menu**, otherwise it is not shown. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png 'Menu hover :size=400') | | `hover` | Overlay the menu over the card contents when the mouse is over the **menu**, otherwise it is not shown. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png 'Menu hover :size=400') |
| `none` | No menu is shown. | ![](../images/menu-mode-none.png 'No menu :size=400') | | `none` | No menu is shown. | ![](../images/menu-mode-none.png 'No menu :size=400') |
-2
View File
@@ -85,8 +85,6 @@ export class ActionFactory {
case 'fullscreen': case 'fullscreen':
return new FullscreenAction(context, frigateCardAction, options?.config); return new FullscreenAction(context, frigateCardAction, options?.config);
case 'menu_toggle': case 'menu_toggle':
// This is a rare code path: this would only be used if someone has a
// menu toggle action configured outside of the menu itself.
return new MenuToggleAction(context, frigateCardAction, options?.config); return new MenuToggleAction(context, frigateCardAction, options?.config);
case 'camera_select': case 'camera_select':
return new CameraSelectAction(context, frigateCardAction, options?.config); return new CameraSelectAction(context, frigateCardAction, options?.config);
+5 -2
View File
@@ -66,7 +66,7 @@ export class MenuButtonController {
options?: MenuButtonControllerOptions, options?: MenuButtonControllerOptions,
): MenuItem[] { ): MenuItem[] {
return [ return [
this._getFrigateButton(config), this._getDefaultButton(config),
this._getCamerasButton(config, cameraManager, options?.view), this._getCamerasButton(config, cameraManager, options?.view),
this._getSubstreamsButton(config, cameraManager, options?.view), this._getSubstreamsButton(config, cameraManager, options?.view),
this._getLiveButton(config, options?.view, options?.viewManager), this._getLiveButton(config, options?.view, options?.viewManager),
@@ -105,7 +105,7 @@ export class MenuButtonController {
].filter(isTruthy); ].filter(isTruthy);
} }
protected _getFrigateButton(config: FrigateCardConfig): MenuItem { protected _getDefaultButton(config: FrigateCardConfig): MenuItem {
return { return {
// Use a magic icon value that the menu will use to render the custom // Use a magic icon value that the menu will use to render the custom
// Frigate icon. // Frigate icon.
@@ -113,6 +113,9 @@ export class MenuButtonController {
...config.menu.buttons.frigate, ...config.menu.buttons.frigate,
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
title: localize('config.menu.buttons.frigate'), title: localize('config.menu.buttons.frigate'),
// The default button always shows regardless of whether the menu is
// hidden or not.
permanent: true,
tap_action: tap_action:
config.menu?.style === 'hidden' config.menu?.style === 'hidden'
? (createGeneralAction('menu_toggle') as FrigateCardCustomAction) ? (createGeneralAction('menu_toggle') as FrigateCardCustomAction)
+29 -48
View File
@@ -1,11 +1,14 @@
import { HASSDomEvent, HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { HASSDomEvent, HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { LitElement } from 'lit'; import { LitElement } from 'lit';
import { orderBy } from 'lodash-es';
import { FRIGATE_ICON_SVG_PATH } from '../camera-manager/frigate/icon.js'; import { FRIGATE_ICON_SVG_PATH } from '../camera-manager/frigate/icon.js';
import type { import { dispatchActionExecutionRequest } from '../card-controller/actions/utils/execution-request.js';
ActionType, import {
ActionsConfig, FRIGATE_MENU_PRIORITY_MAX,
MenuConfig, type ActionType,
MenuItem, type ActionsConfig,
type MenuConfig,
type MenuItem,
} from '../config/types.js'; } from '../config/types.js';
import { FRIGATE_BUTTON_MENU_ICON } from '../const.js'; import { FRIGATE_BUTTON_MENU_ICON } from '../const.js';
import { StateParameters } from '../types.js'; import { StateParameters } from '../types.js';
@@ -15,7 +18,6 @@ import {
} from '../utils/action'; } from '../utils/action';
import { arrayify, isTruthy, setOrRemoveAttribute } from '../utils/basic.js'; import { arrayify, isTruthy, setOrRemoveAttribute } from '../utils/basic.js';
import { refreshDynamicStateParameters } from '../utils/ha/index.js'; import { refreshDynamicStateParameters } from '../utils/ha/index.js';
import { dispatchActionExecutionRequest } from '../card-controller/actions/utils/execution-request.js';
export class MenuController { export class MenuController {
protected _host: LitElement; protected _host: LitElement;
@@ -59,8 +61,6 @@ export class MenuController {
} }
public getButtons(alignment: 'matching' | 'opposing'): MenuItem[] { public getButtons(alignment: 'matching' | 'opposing'): MenuItem[] {
const style = this._config?.style;
const aligned = (button: MenuItem): boolean => { const aligned = (button: MenuItem): boolean => {
return ( return (
button.alignment === alignment || (alignment === 'matching' && !button.alignment) button.alignment === alignment || (alignment === 'matching' && !button.alignment)
@@ -71,16 +71,12 @@ export class MenuController {
return button.enabled !== false; return button.enabled !== false;
}; };
const suitableToShowIfHiddenMenu = (button: MenuItem): boolean => { const show = (button: MenuItem): boolean => {
// If the hidden menu isn't expanded, only show the Frigate button. return !this._isHidingMenu() || this._expanded || !!button.permanent;
return (
style !== 'hidden' || this._expanded || button.icon === FRIGATE_BUTTON_MENU_ICON
);
}; };
return this._buttons.filter( return this._buttons.filter(
(button) => (button) => enabled(button) && aligned(button) && show(button),
enabled(button) && aligned(button) && suitableToShowIfHiddenMenu(button),
); );
} }
@@ -126,7 +122,7 @@ export class MenuController {
let menuToggle = false; let menuToggle = false;
const toggleLessActions = actions.filter( const toggleLessActions = actions.filter(
(item) => isTruthy(item) && !this._isMenuToggleAction(item), (item) => isTruthy(item) && !this._isUnknownActionMenuToggleAction(item),
); );
if (toggleLessActions.length != actions.length) { if (toggleLessActions.length != actions.length) {
menuToggle = true; menuToggle = true;
@@ -176,42 +172,27 @@ export class MenuController {
} }
protected _sortButtons(): void { protected _sortButtons(): void {
const style = this._config?.style; this._buttons = orderBy(
const sortButtons = (a: MenuItem, b: MenuItem): number => { this._buttons,
// If the menu is hidden, the Frigate button must come first. (button) => {
if (style === 'hidden') { const priority = button.priority ?? 0;
if (a.icon === FRIGATE_BUTTON_MENU_ICON) { // If the menu is hidden, the buttons that toggle the menu must come
return -1; // first.
} else if (b.icon === FRIGATE_BUTTON_MENU_ICON) { return (
return 1; priority +
} (this._isHidingMenu() && button.permanent ? FRIGATE_MENU_PRIORITY_MAX : 0)
} );
},
// Otherwise sort by priority. ['desc'],
if ( );
a.priority === undefined ||
(b.priority !== undefined && b.priority > a.priority)
) {
return 1;
}
if (
b.priority === undefined ||
(a.priority !== undefined && b.priority < a.priority)
) {
return -1;
}
return 0;
};
this._buttons.sort(sortButtons);
} }
protected _isHidingMenu(): boolean { protected _isHidingMenu(): boolean {
return this._config?.style === 'hidden' ?? false; return this._config?.style === 'hidden';
} }
protected _isMenuToggleAction(action: ActionType): boolean { protected _isUnknownActionMenuToggleAction(action: ActionType): boolean {
const frigateCardAction = convertActionToCardCustomAction(action); const parsedAction = convertActionToCardCustomAction(action);
return !!frigateCardAction && frigateCardAction.frigate_card_action == 'menu_toggle'; return !!parsedAction && parsedAction.frigate_card_action == 'menu_toggle';
} }
} }
+1
View File
@@ -591,6 +591,7 @@ const menuBaseSchema = z.object({
.optional(), .optional(),
alignment: z.enum(['matching', 'opposing']).default('matching').optional(), alignment: z.enum(['matching', 'opposing']).default('matching').optional(),
icon: z.string().optional(), icon: z.string().optional(),
permanent: z.boolean().default(false).optional(),
}); });
const menuIconSchema = menuBaseSchema.merge(iconSchema).extend({ const menuIconSchema = menuBaseSchema.merge(iconSchema).extend({
+7
View File
@@ -1292,6 +1292,13 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
label: localize('config.menu.buttons.alignment'), label: localize('config.menu.buttons.alignment'),
}, },
)} )}
${this._renderSwitch(
`${CONF_MENU_BUTTONS}.${button}.permanent`,
this._defaults.menu.buttons[button]?.permanent ?? false,
{
label: localize('config.menu.buttons.permanent'),
},
)}
${this._renderNumberInput(`${CONF_MENU_BUTTONS}.${button}.priority`, { ${this._renderNumberInput(`${CONF_MENU_BUTTONS}.${button}.priority`, {
max: FRIGATE_MENU_PRIORITY_MAX, max: FRIGATE_MENU_PRIORITY_MAX,
default: this._defaults.menu.buttons[button]?.priority, default: this._defaults.menu.buttons[button]?.priority,
+1
View File
@@ -363,6 +363,7 @@
"media_player": "Envia al reproductor multimèdia", "media_player": "Envia al reproductor multimèdia",
"microphone": "Micròfon", "microphone": "Micròfon",
"mute": "Silenciar / Activar el so", "mute": "Silenciar / Activar el so",
"permanent": "",
"play": "Reproduir / Pausa", "play": "Reproduir / Pausa",
"priority": "Prioritat", "priority": "Prioritat",
"ptz_controls": "", "ptz_controls": "",
+1
View File
@@ -363,6 +363,7 @@
"media_player": "Send to media player", "media_player": "Send to media player",
"microphone": "Microphone", "microphone": "Microphone",
"mute": "Mute / Unmute", "mute": "Mute / Unmute",
"permanent": "Show when the menu is hidden",
"play": "Play / Pause", "play": "Play / Pause",
"priority": "Priority", "priority": "Priority",
"ptz_controls": "Show PTZ controls", "ptz_controls": "Show PTZ controls",
+1
View File
@@ -363,6 +363,7 @@
"media_player": "Envoyer au lecteur multimédia", "media_player": "Envoyer au lecteur multimédia",
"microphone": "Microphone", "microphone": "Microphone",
"mute": "Désactiver/Réactiver le son", "mute": "Désactiver/Réactiver le son",
"permanent": "",
"play": "Jouer / Pause", "play": "Jouer / Pause",
"priority": "Priorité", "priority": "Priorité",
"ptz_controls": "", "ptz_controls": "",
+1
View File
@@ -363,6 +363,7 @@
"media_player": "Invia a Media Player", "media_player": "Invia a Media Player",
"microphone": "", "microphone": "",
"mute": "", "mute": "",
"permanent": "",
"play": "", "play": "",
"priority": "Priorità", "priority": "Priorità",
"ptz_controls": "", "ptz_controls": "",
+1
View File
@@ -363,6 +363,7 @@
"media_player": "Enviar para o reprodutor de mídia", "media_player": "Enviar para o reprodutor de mídia",
"microphone": "", "microphone": "",
"mute": "", "mute": "",
"permanent": "",
"play": "", "play": "",
"priority": "Prioridade", "priority": "Prioridade",
"ptz_controls": "", "ptz_controls": "",
+1
View File
@@ -363,6 +363,7 @@
"media_player": "Enviar para o reprodutor de mídia", "media_player": "Enviar para o reprodutor de mídia",
"microphone": "", "microphone": "",
"mute": "", "mute": "",
"permanent": "",
"play": "", "play": "",
"priority": "Prioridade", "priority": "Prioridade",
"ptz_controls": "", "ptz_controls": "",
@@ -81,13 +81,14 @@ describe('MenuButtonController', () => {
controller = new MenuButtonController(); controller = new MenuButtonController();
}); });
describe('should have frigate menu button', () => { describe('should have default menu button', () => {
it('with hidden menu style', () => { it('with hidden menu style', () => {
const buttons = calculateButtons(controller); const buttons = calculateButtons(controller);
expect(buttons).toContainEqual({ expect(buttons).toContainEqual({
icon: 'frigate', icon: 'frigate',
enabled: true, enabled: true,
permanent: true,
priority: 50, priority: 50,
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
title: 'Frigate menu / Default view', title: 'Frigate menu / Default view',
@@ -104,6 +105,7 @@ describe('MenuButtonController', () => {
expect(buttons).toContainEqual({ expect(buttons).toContainEqual({
icon: 'frigate', icon: 'frigate',
enabled: true, enabled: true,
permanent: true,
priority: 50, priority: 50,
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
title: 'Frigate menu / Default view', title: 'Frigate menu / Default view',
+71 -3
View File
@@ -72,8 +72,14 @@ describe('MenuController', () => {
}); });
describe('should set and sort buttons', () => { describe('should set and sort buttons', () => {
it('by priority', () => { it('without a hidden menu', () => {
const controller = new MenuController(createLitElement()); const controller = new MenuController(createLitElement());
controller.setMenuConfig(
createMenuConfig({
style: 'overlay',
}),
);
controller.setButtons([ controller.setButtons([
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
@@ -97,6 +103,9 @@ describe('MenuController', () => {
icon: 'mdi:horse', icon: 'mdi:horse',
priority: 40, priority: 40,
alignment: 'matching', alignment: 'matching',
// Will have no effect without a hidden menu.
permanent: true,
}, },
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
@@ -118,6 +127,7 @@ describe('MenuController', () => {
icon: 'mdi:horse', icon: 'mdi:horse',
priority: 40, priority: 40,
alignment: 'matching', alignment: 'matching',
permanent: true,
}, },
{ {
alignment: 'matching', alignment: 'matching',
@@ -139,7 +149,7 @@ describe('MenuController', () => {
]); ]);
}); });
it('with frigate button first', () => { it('with an expanded hidden menu', () => {
const controller = new MenuController(createLitElement()); const controller = new MenuController(createLitElement());
controller.setMenuConfig( controller.setMenuConfig(
createMenuConfig({ createMenuConfig({
@@ -151,13 +161,14 @@ describe('MenuController', () => {
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
icon: 'mdi:cow', icon: 'mdi:cow',
priority: 100, priority: 99,
alignment: 'matching', alignment: 'matching',
}, },
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
icon: 'frigate', icon: 'frigate',
alignment: 'matching', alignment: 'matching',
permanent: true,
}, },
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
@@ -172,19 +183,73 @@ describe('MenuController', () => {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
icon: 'frigate', icon: 'frigate',
alignment: 'matching', alignment: 'matching',
permanent: true,
}, },
{
type: 'custom:frigate-card-menu-icon',
icon: 'mdi:sheep',
priority: 100,
alignment: 'matching',
},
{
type: 'custom:frigate-card-menu-icon',
icon: 'mdi:cow',
priority: 99,
alignment: 'matching',
},
]);
});
it('with a non-expanded hidden menu', () => {
const controller = new MenuController(createLitElement());
controller.setMenuConfig(
createMenuConfig({
style: 'hidden',
}),
);
controller.setExpanded(false);
controller.setButtons([
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
icon: 'mdi:cow', icon: 'mdi:cow',
priority: 100, priority: 100,
alignment: 'matching', alignment: 'matching',
}, },
{
type: 'custom:frigate-card-menu-icon',
icon: 'frigate',
alignment: 'matching',
permanent: true,
},
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
icon: 'mdi:sheep', icon: 'mdi:sheep',
priority: 100, priority: 100,
alignment: 'matching', alignment: 'matching',
}, },
{
type: 'custom:frigate-card-menu-icon',
icon: 'mdi:cow',
alignment: 'matching',
priority: 100,
permanent: true,
},
]);
expect(controller.getButtons('matching')).toEqual([
{
type: 'custom:frigate-card-menu-icon',
icon: 'mdi:cow',
alignment: 'matching',
priority: 100,
permanent: true,
},
{
type: 'custom:frigate-card-menu-icon',
icon: 'frigate',
alignment: 'matching',
permanent: true,
},
]); ]);
}); });
}); });
@@ -266,6 +331,7 @@ describe('MenuController', () => {
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
icon: 'frigate', icon: 'frigate',
permanent: true,
}, },
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
@@ -277,6 +343,7 @@ describe('MenuController', () => {
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
icon: 'frigate', icon: 'frigate',
permanent: true,
}, },
]); ]);
@@ -286,6 +353,7 @@ describe('MenuController', () => {
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',
icon: 'frigate', icon: 'frigate',
permanent: true,
}, },
{ {
type: 'custom:frigate-card-menu-icon', type: 'custom:frigate-card-menu-icon',