fix: Expose gallery and media views as media type agnostic (#2335)
This commit is contained in:
@@ -157,6 +157,15 @@ advanced_camera_card_action: folders
|
|||||||
| --------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
|
| --------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
|
||||||
| `folder` | The first configured folder (under [`folders`](../../folders.md)). | An optional id of the folder to show, see the `id` parameter under [`folders` configuration](../../folders.md). |
|
| `folder` | The first configured folder (under [`folders`](../../folders.md)). | An optional id of the folder to show, see the `id` parameter under [`folders` configuration](../../folders.md). |
|
||||||
|
|
||||||
|
## `gallery`
|
||||||
|
|
||||||
|
Change to the `gallery` view.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
action: custom:advanced-camera-card-action
|
||||||
|
advanced_camera_card_action: gallery
|
||||||
|
```
|
||||||
|
|
||||||
## `fullscreen`
|
## `fullscreen`
|
||||||
|
|
||||||
Toggle fullscreen.
|
Toggle fullscreen.
|
||||||
@@ -237,6 +246,15 @@ advanced_camera_card_action: live_substream_select
|
|||||||
| `advanced_camera_card_action` | Must be `live_substream_select`. |
|
| `advanced_camera_card_action` | Must be `live_substream_select`. |
|
||||||
| `camera` | The [camera ID](../../cameras/README.md?id=cameras) of the substream to select. |
|
| `camera` | The [camera ID](../../cameras/README.md?id=cameras) of the substream to select. |
|
||||||
|
|
||||||
|
## `media`
|
||||||
|
|
||||||
|
Change to the `media` view.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
action: custom:advanced-camera-card-action
|
||||||
|
advanced_camera_card_action: media
|
||||||
|
```
|
||||||
|
|
||||||
## `log`
|
## `log`
|
||||||
|
|
||||||
Log a message to the Javascript console.
|
Log a message to the Javascript console.
|
||||||
@@ -463,6 +481,24 @@ action: custom:advanced-camera-card-action
|
|||||||
advanced_camera_card_action: recordings
|
advanced_camera_card_action: recordings
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `review`
|
||||||
|
|
||||||
|
Change to the `review` view.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
action: custom:advanced-camera-card-action
|
||||||
|
advanced_camera_card_action: review
|
||||||
|
```
|
||||||
|
|
||||||
|
## `reviews`
|
||||||
|
|
||||||
|
Change to the `reviews` view.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
action: custom:advanced-camera-card-action
|
||||||
|
advanced_camera_card_action: reviews
|
||||||
|
```
|
||||||
|
|
||||||
## `reload`
|
## `reload`
|
||||||
|
|
||||||
Reload the entire dashboard.
|
Reload the entire dashboard.
|
||||||
@@ -591,6 +627,33 @@ elements:
|
|||||||
tap_action:
|
tap_action:
|
||||||
action: custom:advanced-camera-card-action
|
action: custom:advanced-camera-card-action
|
||||||
advanced_camera_card_action: camera_ui
|
advanced_camera_card_action: camera_ui
|
||||||
|
- type: custom:advanced-camera-card-menu-icon
|
||||||
|
icon: mdi:play-box-multiple
|
||||||
|
title: Show media gallery
|
||||||
|
tap_action:
|
||||||
|
action: custom:advanced-camera-card-action
|
||||||
|
advanced_camera_card_action: gallery
|
||||||
|
hold_action:
|
||||||
|
action: custom:advanced-camera-card-action
|
||||||
|
advanced_camera_card_action: media
|
||||||
|
- type: custom:advanced-camera-card-menu-icon
|
||||||
|
icon: mdi:filmstrip
|
||||||
|
title: Show most recent media
|
||||||
|
tap_action:
|
||||||
|
action: custom:advanced-camera-card-action
|
||||||
|
advanced_camera_card_action: media
|
||||||
|
- type: custom:advanced-camera-card-menu-icon
|
||||||
|
icon: mdi:alpha-r-circle-outline
|
||||||
|
title: Show most recent review
|
||||||
|
tap_action:
|
||||||
|
action: custom:advanced-camera-card-action
|
||||||
|
advanced_camera_card_action: review
|
||||||
|
- type: custom:advanced-camera-card-menu-icon
|
||||||
|
icon: mdi:alpha-s-circle-outline
|
||||||
|
title: Show reviews
|
||||||
|
tap_action:
|
||||||
|
action: custom:advanced-camera-card-action
|
||||||
|
advanced_camera_card_action: reviews
|
||||||
- type: custom:advanced-camera-card-menu-icon
|
- type: custom:advanced-camera-card-menu-icon
|
||||||
icon: mdi:alpha-d-circle
|
icon: mdi:alpha-d-circle
|
||||||
title: Show most recent clip
|
title: Show most recent clip
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ cameras:
|
|||||||
| `events` | `[events, clips, snapshots]` | Whether to trigger the camera when `events` occur (whether or not media is available) or whenever updated `clips` or `snapshots` are detected. Detection support varies by camera [engine](engine.md). |
|
| `events` | `[events, clips, snapshots]` | Whether to trigger the camera when `events` occur (whether or not media is available) or whenever updated `clips` or `snapshots` are detected. Detection support varies by camera [engine](engine.md). |
|
||||||
| `motion` | `false` | Whether to not to trigger the camera by automatically detecting and using the motion `binary_sensor` for this camera. This autodetection only works for Frigate cameras, and only when the motion `binary_sensor` entity has been enabled in Home Assistant. |
|
| `motion` | `false` | Whether to not to trigger the camera by automatically detecting and using the motion `binary_sensor` for this camera. This autodetection only works for Frigate cameras, and only when the motion `binary_sensor` entity has been enabled in Home Assistant. |
|
||||||
| `occupancy` | `false` | Whether to not to trigger the camera by automatically detecting and using the occupancy `binary_sensor` for this camera and its configured zones and labels. This autodetection only works for Frigate cameras, and only when the occupancy `binary_sensor` entity has been enabled in Home Assistant. If this camera has configured zones, only occupancy sensors for those zones are used -- if the overall _camera_ occupancy sensor is also required, it can be manually added to `entities`. If this camera has configured labels, only occupancy sensors for those labels are used. |
|
| `occupancy` | `false` | Whether to not to trigger the camera by automatically detecting and using the occupancy `binary_sensor` for this camera and its configured zones and labels. This autodetection only works for Frigate cameras, and only when the occupancy `binary_sensor` entity has been enabled in Home Assistant. If this camera has configured zones, only occupancy sensors for those zones are used -- if the overall _camera_ occupancy sensor is also required, it can be manually added to `entities`. If this camera has configured labels, only occupancy sensors for those labels are used. |
|
||||||
| `reviews` | | Configuration for triggering on Frigate review items. See below. Frigate-specific. |
|
| `reviews` | | Configuration for triggering on review items. Currently only supported by Frigate. See below. |
|
||||||
|
|
||||||
### `reviews`
|
### `reviews`
|
||||||
|
|
||||||
|
|||||||
@@ -361,9 +361,9 @@ conditions:
|
|||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> Internally, views associated with the media viewer (e.g. `clip`, `snapshot`,
|
> Internally, views associated with the media viewer (e.g. `clip`, `snapshot`,
|
||||||
> `recording`) are translated to a special view called `media` after the relevant
|
> `review` `recording`) are translated to the `media` view after the relevant
|
||||||
> media is fetched. When including views as part of a [condition](conditions.md),
|
> media is fetched. When including views as part of a
|
||||||
> you may need to refer to this special `media` view.
|
> [condition](conditions.md), you may need to refer to the `media` view.
|
||||||
|
|
||||||
## Fully expanded reference
|
## Fully expanded reference
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
# `media_gallery`
|
# `media_gallery`
|
||||||
|
|
||||||
The `media_gallery` is used for providing an overview of all `clips`,
|
The `media_gallery` is used for providing an overview of all `clips`,
|
||||||
`snapshots`, `recordings`, `reviews` and `folder` contents in a thumbnail
|
`snapshots`, `recordings`, `reviews` and `folders`.
|
||||||
gallery.
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
media_gallery:
|
media_gallery:
|
||||||
# [...]
|
# [...]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Default | Description |
|
| Option | Default | Description |
|
||||||
| ---------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `actions` | | [Actions](actions/README.md) to use for all views that use the `media_gallery` (e.g. `clips`, `folder`, `snapshots`, `recordings`). |
|
| `actions` | | [Actions](actions/README.md) to use for all views that use the `media_gallery` (e.g. `clips`, `snapshots`, `recordings`, `reviews`, `folders`, `gallery`). |
|
||||||
| `controls` | | Configuration for the Media Gallery controls. See below. |
|
| `controls` | | Configuration for the Media Gallery controls. See below. |
|
||||||
|
|
||||||
## `controls`
|
## `controls`
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# `media_viewer`
|
# `media_viewer`
|
||||||
|
|
||||||
The `media_player` section configures viewing all `clip`, `snapshot` or `recording` media, in either a media carousel or grid.
|
The `media_viewer` section configures viewing all `clip`, `snapshot`, `recording`, `review`, `folder` or `media` view, in either a media carousel or grid.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
media_viewer:
|
media_viewer:
|
||||||
@@ -9,7 +9,7 @@ media_viewer:
|
|||||||
|
|
||||||
| Option | Default | Description |
|
| Option | Default | Description |
|
||||||
| --------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `actions` | | [Actions](actions/README.md) to use for all views that use the `media_viewer` (e.g. `clip`, `snapshot`). |
|
| `actions` | | [Actions](actions/README.md) to use for all views that use the `media_viewer` (e.g. `media`, `clip`, `snapshot`, `recording`, `review`, `folder`). |
|
||||||
| `auto_mute` | `[unselected, hidden]` | A list of conditions in which media items are muted. `unselected` will automatically mute when a media item is unselected in the carousel or grid. `hidden` will automatically mute when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically mute. |
|
| `auto_mute` | `[unselected, hidden]` | A list of conditions in which media items are muted. `unselected` will automatically mute when a media item is unselected in the carousel or grid. `hidden` will automatically mute when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically mute. |
|
||||||
| `auto_pause` | `[unselected, hidden]` | A list of conditions in which media items are automatically paused. `unselected` will automatically pause when a media item is unselected in the carousel or grid. `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. |
|
| `auto_pause` | `[unselected, hidden]` | A list of conditions in which media items are automatically paused. `unselected` will automatically pause when a media item is unselected in the carousel or grid. `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. |
|
||||||
| `auto_play` | `[selected, visible]` | A list of conditions in which media items are automatically played. `selected` will automatically play when a media item is selected in a carousel or grid. `visible` will automatically play when a media item becomes visible (e.g. browser tab change, or visible in a grid but not selected). Use an empty list (`[]`) to never automatically play. |
|
| `auto_play` | `[selected, visible]` | A list of conditions in which media items are automatically played. `selected` will automatically play when a media item is selected in a carousel or grid. `visible` will automatically play when a media item becomes visible (e.g. browser tab change, or visible in a grid but not selected). Use an empty list (`[]`) to never automatically play. |
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ action will be taken on card startup.
|
|||||||
| Option | Default | Description |
|
| Option | Default | Description |
|
||||||
| ------------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `interaction_mode` | `inactive` | Whether actions should be taken when the card is being interacted with. If `all`, actions will always left be taken regardless. If `inactive` actions will only be taken if the card has _not_ had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card _has_ had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed. |
|
| `interaction_mode` | `inactive` | Whether actions should be taken when the card is being interacted with. If `all`, actions will always left be taken regardless. If `inactive` actions will only be taken if the card has _not_ had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card _has_ had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed. |
|
||||||
| `trigger` | `update` | If set to `update` the current view is updated in place. If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip` or `snapshot`) will be chosen to match a newly available media item (please note that only some [camera engines](cameras/engine.md) support new media detection, e.g. `frigate`). If set to `none` no action is taken. |
|
| `trigger` | `update` | If set to `update` the current view is updated in place. If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip`, `snapshot`, `review`) will be chosen to match a newly available media item (please note that only some [camera engines](cameras/engine.md) support new media detection, e.g. `frigate`). If set to `none` no action is taken. |
|
||||||
| `untrigger` | `none` | If set to `default` the the default view of the card will be reloaded. If set to `none` no action will be taken. |
|
| `untrigger` | `none` | If set to `default` the the default view of the card will be reloaded. If set to `none` no action will be taken. |
|
||||||
|
|
||||||
## Supported views
|
## Supported views
|
||||||
@@ -143,12 +143,14 @@ This card supports several different views.
|
|||||||
| `clips` | Shows a gallery of clips for this camera. |
|
| `clips` | Shows a gallery of clips for this camera. |
|
||||||
| `folder` | Shows a viewer for the media from the default [`folder`](./folders.md). |
|
| `folder` | Shows a viewer for the media from the default [`folder`](./folders.md). |
|
||||||
| `folders` | Shows a gallery of media and subfolders from the default [`folder`](./folders.md). |
|
| `folders` | Shows a gallery of media and subfolders from the default [`folder`](./folders.md). |
|
||||||
|
| `gallery` | Shows a gallery of media for this camera's default [media type](./cameras/README.md?id=media). |
|
||||||
| `image` | Shows a static image specified by the `image` parameter, can be used as a discrete default view or a screensaver (via `view.interaction_seconds`). |
|
| `image` | Shows a static image specified by the `image` parameter, can be used as a discrete default view or a screensaver (via `view.interaction_seconds`). |
|
||||||
| `live` | Shows the live camera view with the configured [live provider](./cameras/live-provider.md). |
|
| `live` | Shows the live camera view with the configured [live provider](./cameras/live-provider.md). |
|
||||||
|
| `media` | Shows a viewer for the most recent media for this camera. |
|
||||||
| `recording` | Shows a viewer for the most recent recording for this camera. Can also be accessed by holding down the `recordings` menu icon. |
|
| `recording` | Shows a viewer for the most recent recording for this camera. Can also be accessed by holding down the `recordings` menu icon. |
|
||||||
| `recordings` | Shows a gallery of recent (last day) recordings for this camera and its dependents. |
|
| `recordings` | Shows a gallery of recent (last day) recordings for this camera and its dependents. |
|
||||||
| `review` | Shows a viewer for the most recent unreviewed review item (e.g. alerts/detections in Frigate). |
|
| `review` | Shows a viewer for the most recent unreviewed review item (e.g. alerts/detections in Frigate). |
|
||||||
| `reviews` | Shows a viewer for the most recent unreviewed review item (e.g. alerts/detections in Frigate). |
|
| `reviews` | Shows a gallery of reviews for this camera and its dependents. |
|
||||||
| `snapshot` | Shows a viewer for the most recent snapshot for this camera. Can also be accessed by holding down the `snapshots` menu icon. |
|
| `snapshot` | Shows a viewer for the most recent snapshot for this camera. Can also be accessed by holding down the `snapshots` menu icon. |
|
||||||
| `snapshots` | Shows a gallery of snapshots for this camera. |
|
| `snapshots` | Shows a gallery of snapshots for this camera. |
|
||||||
| `timeline` | Shows an event timeline. |
|
| `timeline` | Shows an event timeline. |
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ It is possible to pass the Advanced Camera Card one or more
|
|||||||
[actions](../configuration/actions/README.md) from the URL (e.g. select a particular
|
[actions](../configuration/actions/README.md) from the URL (e.g. select a particular
|
||||||
camera, open the live view in expanded mode, etc).
|
camera, open the live view in expanded mode, etc).
|
||||||
|
|
||||||
### When actions are executed
|
## When actions are executed
|
||||||
|
|
||||||
The Advanced Camera Card will execute these actions in the following circumstances:
|
The Advanced Camera Card will execute these actions in the following circumstances:
|
||||||
|
|
||||||
@@ -19,13 +19,13 @@ The Advanced Camera Card will execute these actions in the following circumstanc
|
|||||||
|
|
||||||
To send an action to _all_ Advanced Camera Cards on a dashboard:
|
To send an action to _all_ Advanced Camera Cards on a dashboard:
|
||||||
|
|
||||||
```
|
```text
|
||||||
[PATH_TO_YOUR_HA_DASHBOARD]?advanced-camera-card-action.[ACTION]=[VALUE]
|
[PATH_TO_YOUR_HA_DASHBOARD]?advanced-camera-card-action.[ACTION]=[VALUE]
|
||||||
```
|
```
|
||||||
|
|
||||||
To send an action to a specific named Advanced Camera Card:
|
To send an action to a specific named Advanced Camera Card:
|
||||||
|
|
||||||
```
|
```text
|
||||||
[PATH_TO_YOUR_HA_DASHBOARD]?advanced-camera-card-action.[CARD_ID].[ACTION]=[VALUE]
|
[PATH_TO_YOUR_HA_DASHBOARD]?advanced-camera-card-action.[CARD_ID].[ACTION]=[VALUE]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -58,12 +58,17 @@ Only a subset of all [actions](../configuration/actions/README.md) are supported
|
|||||||
| `clip` | :white_check_mark: | |
|
| `clip` | :white_check_mark: | |
|
||||||
| `clips` | :white_check_mark: | |
|
| `clips` | :white_check_mark: | |
|
||||||
| `default` | :white_check_mark: | |
|
| `default` | :white_check_mark: | |
|
||||||
|
| `diagnostics` | :white_check_mark: | |
|
||||||
| `download` | :heavy_multiplication_x: | Latest media information is not available on initial render. |
|
| `download` | :heavy_multiplication_x: | Latest media information is not available on initial render. |
|
||||||
| `expand` | :white_check_mark: | |
|
| `expand` | :white_check_mark: | |
|
||||||
|
| `folder` | :white_check_mark: | |
|
||||||
|
| `folders` | :white_check_mark: | |
|
||||||
| `fullscreen` | :heavy_multiplication_x: | Javascript does not support activating fullscreen without direct human interaction. Use `expand` as an alternative. |
|
| `fullscreen` | :heavy_multiplication_x: | Javascript does not support activating fullscreen without direct human interaction. Use `expand` as an alternative. |
|
||||||
|
| `gallery` | :white_check_mark: | |
|
||||||
| `image` | :white_check_mark: | |
|
| `image` | :white_check_mark: | |
|
||||||
| `live_substream_select` | :white_check_mark: | |
|
| `live_substream_select` | :white_check_mark: | |
|
||||||
| `live` | :white_check_mark: | |
|
| `live` | :white_check_mark: | |
|
||||||
|
| `media` | :white_check_mark: | |
|
||||||
| `media_player` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/advanced-camera-card/issues) if you need this. |
|
| `media_player` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/advanced-camera-card/issues) if you need this. |
|
||||||
| `menu_toggle` | :white_check_mark: | |
|
| `menu_toggle` | :white_check_mark: | |
|
||||||
| `microphone_connect`, `microphone_disconnect`, `microphone_mute`, `microphone_unmute` | :heavy_multiplication_x: | |
|
| `microphone_connect`, `microphone_disconnect`, `microphone_mute`, `microphone_unmute` | :heavy_multiplication_x: | |
|
||||||
@@ -72,6 +77,8 @@ Only a subset of all [actions](../configuration/actions/README.md) are supported
|
|||||||
| `ptz` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/advanced-camera-card/issues) if you need this. |
|
| `ptz` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/advanced-camera-card/issues) if you need this. |
|
||||||
| `recording` | :white_check_mark: | |
|
| `recording` | :white_check_mark: | |
|
||||||
| `recordings` | :white_check_mark: | |
|
| `recordings` | :white_check_mark: | |
|
||||||
|
| `review` | :white_check_mark: | |
|
||||||
|
| `reviews` | :white_check_mark: | |
|
||||||
| `screenshot` | :heavy_multiplication_x: | Latest media information is not available on initial render. |
|
| `screenshot` | :heavy_multiplication_x: | Latest media information is not available on initial render. |
|
||||||
| `ptz_controls` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/advanced-camera-card/issues) if you need this. |
|
| `ptz_controls` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/advanced-camera-card/issues) if you need this. |
|
||||||
| `snapshot` | :white_check_mark: | |
|
| `snapshot` | :white_check_mark: | |
|
||||||
|
|||||||
@@ -91,8 +91,10 @@ export class ActionFactory {
|
|||||||
case 'clips':
|
case 'clips':
|
||||||
case 'folder':
|
case 'folder':
|
||||||
case 'folders':
|
case 'folders':
|
||||||
|
case 'gallery':
|
||||||
case 'image':
|
case 'image':
|
||||||
case 'live':
|
case 'live':
|
||||||
|
case 'media':
|
||||||
case 'recording':
|
case 'recording':
|
||||||
case 'recordings':
|
case 'recordings':
|
||||||
case 'review':
|
case 'review':
|
||||||
|
|||||||
@@ -131,10 +131,16 @@ export class QueryStringManager {
|
|||||||
case 'clip':
|
case 'clip':
|
||||||
case 'clips':
|
case 'clips':
|
||||||
case 'diagnostics':
|
case 'diagnostics':
|
||||||
|
case 'folder':
|
||||||
|
case 'folders':
|
||||||
|
case 'gallery':
|
||||||
case 'image':
|
case 'image':
|
||||||
case 'live':
|
case 'live':
|
||||||
|
case 'media':
|
||||||
case 'recording':
|
case 'recording':
|
||||||
case 'recordings':
|
case 'recordings':
|
||||||
|
case 'review':
|
||||||
|
case 'reviews':
|
||||||
case 'snapshot':
|
case 'snapshot':
|
||||||
case 'snapshots':
|
case 'snapshots':
|
||||||
case 'timeline':
|
case 'timeline':
|
||||||
@@ -159,10 +165,16 @@ export class QueryStringManager {
|
|||||||
case 'clip':
|
case 'clip':
|
||||||
case 'clips':
|
case 'clips':
|
||||||
case 'diagnostics':
|
case 'diagnostics':
|
||||||
|
case 'folder':
|
||||||
|
case 'folders':
|
||||||
|
case 'gallery':
|
||||||
case 'image':
|
case 'image':
|
||||||
case 'live':
|
case 'live':
|
||||||
|
case 'media':
|
||||||
case 'recording':
|
case 'recording':
|
||||||
case 'recordings':
|
case 'recordings':
|
||||||
|
case 'review':
|
||||||
|
case 'reviews':
|
||||||
case 'snapshot':
|
case 'snapshot':
|
||||||
case 'snapshots':
|
case 'snapshots':
|
||||||
case 'timeline':
|
case 'timeline':
|
||||||
|
|||||||
@@ -105,23 +105,30 @@ export class ViewQueryExecutor {
|
|||||||
|
|
||||||
const cameraForQuery = view.isGrid() ? undefined : view.camera;
|
const cameraForQuery = view.isGrid() ? undefined : view.camera;
|
||||||
|
|
||||||
|
const getDefaultQueryModifiers = async () => {
|
||||||
|
const query = builder.buildDefaultCameraQuery(cameraForQuery, {
|
||||||
|
limit: this._getLimit(),
|
||||||
|
});
|
||||||
|
return await executeQuery(query);
|
||||||
|
};
|
||||||
|
|
||||||
switch (view.view) {
|
switch (view.view) {
|
||||||
case 'live':
|
case 'live':
|
||||||
if (config.live.controls.thumbnails.mode !== 'none') {
|
if (config.live.controls.thumbnails.mode !== 'none') {
|
||||||
const defaultQuery = builder.buildDefaultCameraQuery(cameraForQuery);
|
viewModifiers.push(...(await getDefaultQueryModifiers()));
|
||||||
if (defaultQuery) {
|
|
||||||
viewModifiers.push(...(await executeQuery(defaultQuery)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'timeline':
|
case 'timeline':
|
||||||
// Timeline view always queries all cameras with media capabilities.
|
// Timeline view always queries all cameras with media capabilities.
|
||||||
viewModifiers.push(...(await executeQuery(builder.buildDefaultCameraQuery())));
|
viewModifiers.push(...(await executeQuery(builder.buildDefaultCameraQuery())));
|
||||||
break;
|
break;
|
||||||
|
case 'gallery':
|
||||||
case 'media':
|
case 'media':
|
||||||
// If the user is looking at media in the `media` view and then
|
// If the user is looking at media in the `media` view and then changes
|
||||||
// changes camera (via the menu) it should default to showing clips
|
// camera (via the menu) it should default to the default camera media
|
||||||
// for the new camera.
|
// type.
|
||||||
|
viewModifiers.push(...(await getDefaultQueryModifiers()));
|
||||||
|
break;
|
||||||
case 'clip':
|
case 'clip':
|
||||||
case 'clips':
|
case 'clips':
|
||||||
viewModifiers.push(
|
viewModifiers.push(
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
AdvancedCameraCardView,
|
AdvancedCameraCardView,
|
||||||
VIEWS_USER_SPECIFIED,
|
VIEWS_USER_SPECIFIED,
|
||||||
} from '../config/schema/common/const';
|
} from '../config/schema/common/const';
|
||||||
import { MenuItemBase } from '../config/schema/elements/custom/menu/base';
|
|
||||||
import { MenuItem } from '../config/schema/elements/custom/menu/types';
|
import { MenuItem } from '../config/schema/elements/custom/menu/types';
|
||||||
import { AdvancedCameraCardConfig } from '../config/schema/types';
|
import { AdvancedCameraCardConfig } from '../config/schema/types';
|
||||||
import { getEntityTitle } from '../ha/get-entity-title';
|
import { getEntityTitle } from '../ha/get-entity-title';
|
||||||
@@ -82,6 +81,7 @@ export class MenuButtonController {
|
|||||||
this._getSnapshotsButton(config, cameraManager, foldersManager, options?.view),
|
this._getSnapshotsButton(config, cameraManager, foldersManager, options?.view),
|
||||||
this._getRecordingsButton(config, cameraManager, foldersManager, options?.view),
|
this._getRecordingsButton(config, cameraManager, foldersManager, options?.view),
|
||||||
this._getReviewsButton(config, cameraManager, foldersManager, options?.view),
|
this._getReviewsButton(config, cameraManager, foldersManager, options?.view),
|
||||||
|
this._getGalleryButton(config, cameraManager, foldersManager, options?.view),
|
||||||
this._getImageButton(config, cameraManager, foldersManager, options?.view),
|
this._getImageButton(config, cameraManager, foldersManager, options?.view),
|
||||||
this._getTimelineButton(config, cameraManager, foldersManager, options?.view),
|
this._getTimelineButton(config, cameraManager, foldersManager, options?.view),
|
||||||
this._getDownloadButton(config, cameraManager, options?.view),
|
this._getDownloadButton(config, cameraManager, options?.view),
|
||||||
@@ -252,45 +252,17 @@ export class MenuButtonController {
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if a media button (clips/snapshots) should be shown. These are
|
|
||||||
* hidden by default if reviews are supported.
|
|
||||||
*/
|
|
||||||
protected _shouldShowEventMediaButton(
|
|
||||||
viewName: 'clips' | 'snapshots',
|
|
||||||
buttonConfig: MenuItemBase,
|
|
||||||
cameraManager: CameraManager,
|
|
||||||
foldersManager: FoldersManager,
|
|
||||||
view?: View | null,
|
|
||||||
): boolean {
|
|
||||||
const supportsEventView =
|
|
||||||
view &&
|
|
||||||
isViewSupportedByCamera(viewName, cameraManager, foldersManager, view.camera);
|
|
||||||
const supportsReviewsView =
|
|
||||||
view &&
|
|
||||||
isViewSupportedByCamera('reviews', cameraManager, foldersManager, view.camera);
|
|
||||||
|
|
||||||
// Show if: explicitly enabled OR (supports view AND reviews not supported)
|
|
||||||
return !!supportsEventView && (buttonConfig.enabled || !supportsReviewsView);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected _getClipsButton(
|
protected _getClipsButton(
|
||||||
config: AdvancedCameraCardConfig,
|
config: AdvancedCameraCardConfig,
|
||||||
cameraManager: CameraManager,
|
cameraManager: CameraManager,
|
||||||
foldersManager: FoldersManager,
|
foldersManager: FoldersManager,
|
||||||
view?: View | null,
|
view?: View | null,
|
||||||
): MenuItem | null {
|
): MenuItem | null {
|
||||||
return this._shouldShowEventMediaButton(
|
return view &&
|
||||||
'clips',
|
isViewSupportedByCamera('clips', cameraManager, foldersManager, view.camera)
|
||||||
config.menu.buttons.clips,
|
|
||||||
cameraManager,
|
|
||||||
foldersManager,
|
|
||||||
view,
|
|
||||||
)
|
|
||||||
? {
|
? {
|
||||||
icon: 'mdi:filmstrip',
|
icon: 'mdi:filmstrip',
|
||||||
...config.menu.buttons.clips,
|
...config.menu.buttons.clips,
|
||||||
enabled: true,
|
|
||||||
type: 'custom:advanced-camera-card-menu-icon',
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
title: localize('config.view.views.clips'),
|
title: localize('config.view.views.clips'),
|
||||||
style: view?.is('clips') ? this._getEmphasizedStyle() : {},
|
style: view?.is('clips') ? this._getEmphasizedStyle() : {},
|
||||||
@@ -306,17 +278,11 @@ export class MenuButtonController {
|
|||||||
foldersManager: FoldersManager,
|
foldersManager: FoldersManager,
|
||||||
view?: View | null,
|
view?: View | null,
|
||||||
): MenuItem | null {
|
): MenuItem | null {
|
||||||
return this._shouldShowEventMediaButton(
|
return view &&
|
||||||
'snapshots',
|
isViewSupportedByCamera('snapshots', cameraManager, foldersManager, view.camera)
|
||||||
config.menu.buttons.snapshots,
|
|
||||||
cameraManager,
|
|
||||||
foldersManager,
|
|
||||||
view,
|
|
||||||
)
|
|
||||||
? {
|
? {
|
||||||
icon: 'mdi:camera',
|
icon: 'mdi:camera',
|
||||||
...config.menu.buttons.snapshots,
|
...config.menu.buttons.snapshots,
|
||||||
enabled: true,
|
|
||||||
type: 'custom:advanced-camera-card-menu-icon',
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
title: localize('config.view.views.snapshots'),
|
title: localize('config.view.views.snapshots'),
|
||||||
style: view?.is('snapshots') ? this._getEmphasizedStyle() : {},
|
style: view?.is('snapshots') ? this._getEmphasizedStyle() : {},
|
||||||
@@ -355,7 +321,7 @@ export class MenuButtonController {
|
|||||||
return view &&
|
return view &&
|
||||||
isViewSupportedByCamera('reviews', cameraManager, foldersManager, view.camera)
|
isViewSupportedByCamera('reviews', cameraManager, foldersManager, view.camera)
|
||||||
? {
|
? {
|
||||||
icon: 'mdi:play-box-multiple',
|
icon: 'mdi:play-box-edit-outline',
|
||||||
...config.menu.buttons.reviews,
|
...config.menu.buttons.reviews,
|
||||||
type: 'custom:advanced-camera-card-menu-icon',
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
title: localize('config.view.views.reviews'),
|
title: localize('config.view.views.reviews'),
|
||||||
@@ -366,6 +332,26 @@ export class MenuButtonController {
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected _getGalleryButton(
|
||||||
|
config: AdvancedCameraCardConfig,
|
||||||
|
cameraManager: CameraManager,
|
||||||
|
foldersManager: FoldersManager,
|
||||||
|
view?: View | null,
|
||||||
|
): MenuItem | null {
|
||||||
|
return view &&
|
||||||
|
isViewSupportedByCamera('gallery', cameraManager, foldersManager, view.camera)
|
||||||
|
? {
|
||||||
|
icon: 'mdi:play-box-multiple',
|
||||||
|
...config.menu.buttons.gallery,
|
||||||
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
|
title: localize('config.menu.buttons.gallery'),
|
||||||
|
style: view.is('gallery') ? this._getEmphasizedStyle() : {},
|
||||||
|
tap_action: createViewAction('gallery'),
|
||||||
|
hold_action: createViewAction('media'),
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
protected _getImageButton(
|
protected _getImageButton(
|
||||||
config: AdvancedCameraCardConfig,
|
config: AdvancedCameraCardConfig,
|
||||||
cameraManager: CameraManager,
|
cameraManager: CameraManager,
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ export const VIEWS_USER_SPECIFIED = [
|
|||||||
'clips',
|
'clips',
|
||||||
'folder',
|
'folder',
|
||||||
'folders',
|
'folders',
|
||||||
|
'gallery',
|
||||||
|
'media',
|
||||||
'snapshot',
|
'snapshot',
|
||||||
'snapshots',
|
'snapshots',
|
||||||
'recording',
|
'recording',
|
||||||
@@ -28,7 +30,4 @@ export const VIEWS_USER_SPECIFIED = [
|
|||||||
'timeline',
|
'timeline',
|
||||||
] as const;
|
] as const;
|
||||||
export type AdvancedCameraCardUserSpecifiedView = (typeof VIEWS_USER_SPECIFIED)[number];
|
export type AdvancedCameraCardUserSpecifiedView = (typeof VIEWS_USER_SPECIFIED)[number];
|
||||||
export type AdvancedCameraCardView =
|
export type AdvancedCameraCardView = AdvancedCameraCardUserSpecifiedView | 'diagnostics';
|
||||||
| AdvancedCameraCardUserSpecifiedView
|
|
||||||
| 'media'
|
|
||||||
| 'diagnostics';
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export const menuConfigDefault = {
|
|||||||
fullscreen: visibleButtonDefault,
|
fullscreen: visibleButtonDefault,
|
||||||
image: hiddenButtonDefault,
|
image: hiddenButtonDefault,
|
||||||
info: visibleButtonDefault,
|
info: visibleButtonDefault,
|
||||||
|
gallery: visibleButtonDefault,
|
||||||
live: visibleButtonDefault,
|
live: visibleButtonDefault,
|
||||||
media_player: visibleButtonDefault,
|
media_player: visibleButtonDefault,
|
||||||
microphone: {
|
microphone: {
|
||||||
@@ -49,7 +50,7 @@ export const menuConfigDefault = {
|
|||||||
play: hiddenButtonDefault,
|
play: hiddenButtonDefault,
|
||||||
ptz_controls: hiddenButtonDefault,
|
ptz_controls: hiddenButtonDefault,
|
||||||
recordings: hiddenButtonDefault,
|
recordings: hiddenButtonDefault,
|
||||||
reviews: visibleButtonDefault,
|
reviews: hiddenButtonDefault,
|
||||||
set_review: visibleButtonDefault,
|
set_review: visibleButtonDefault,
|
||||||
screenshot: hiddenButtonDefault,
|
screenshot: hiddenButtonDefault,
|
||||||
snapshots: hiddenButtonDefault,
|
snapshots: hiddenButtonDefault,
|
||||||
@@ -91,6 +92,7 @@ export const menuConfigSchema = z
|
|||||||
fullscreen: visibleButtonSchema.default(menuConfigDefault.buttons.fullscreen),
|
fullscreen: visibleButtonSchema.default(menuConfigDefault.buttons.fullscreen),
|
||||||
image: hiddenButtonSchema.default(menuConfigDefault.buttons.image),
|
image: hiddenButtonSchema.default(menuConfigDefault.buttons.image),
|
||||||
info: visibleButtonSchema.default(menuConfigDefault.buttons.info),
|
info: visibleButtonSchema.default(menuConfigDefault.buttons.info),
|
||||||
|
gallery: visibleButtonSchema.default(menuConfigDefault.buttons.gallery),
|
||||||
live: visibleButtonSchema.default(menuConfigDefault.buttons.live),
|
live: visibleButtonSchema.default(menuConfigDefault.buttons.live),
|
||||||
media_player: visibleButtonSchema.default(
|
media_player: visibleButtonSchema.default(
|
||||||
menuConfigDefault.buttons.media_player,
|
menuConfigDefault.buttons.media_player,
|
||||||
@@ -106,7 +108,7 @@ export const menuConfigSchema = z
|
|||||||
play: hiddenButtonSchema.default(menuConfigDefault.buttons.play),
|
play: hiddenButtonSchema.default(menuConfigDefault.buttons.play),
|
||||||
ptz_controls: hiddenButtonSchema.default(menuConfigDefault.buttons.ptz_controls),
|
ptz_controls: hiddenButtonSchema.default(menuConfigDefault.buttons.ptz_controls),
|
||||||
recordings: hiddenButtonSchema.default(menuConfigDefault.buttons.recordings),
|
recordings: hiddenButtonSchema.default(menuConfigDefault.buttons.recordings),
|
||||||
reviews: visibleButtonSchema.default(menuConfigDefault.buttons.reviews),
|
reviews: hiddenButtonSchema.default(menuConfigDefault.buttons.reviews),
|
||||||
set_review: visibleButtonSchema.default(menuConfigDefault.buttons.set_review),
|
set_review: visibleButtonSchema.default(menuConfigDefault.buttons.set_review),
|
||||||
screenshot: hiddenButtonSchema.default(menuConfigDefault.buttons.screenshot),
|
screenshot: hiddenButtonSchema.default(menuConfigDefault.buttons.screenshot),
|
||||||
snapshots: hiddenButtonSchema.default(menuConfigDefault.buttons.snapshots),
|
snapshots: hiddenButtonSchema.default(menuConfigDefault.buttons.snapshots),
|
||||||
|
|||||||
+4
-1
@@ -368,7 +368,7 @@ const options: EditorOptions = {
|
|||||||
secondary: localize('editor.folders'),
|
secondary: localize('editor.folders'),
|
||||||
},
|
},
|
||||||
media_gallery: {
|
media_gallery: {
|
||||||
icon: 'grid',
|
icon: 'play-box-multiple',
|
||||||
name: localize('editor.media_gallery'),
|
name: localize('editor.media_gallery'),
|
||||||
secondary: localize('editor.media_gallery_secondary'),
|
secondary: localize('editor.media_gallery_secondary'),
|
||||||
},
|
},
|
||||||
@@ -432,8 +432,10 @@ export class AdvancedCameraCardEditor extends LitElement implements LovelaceCard
|
|||||||
{ value: 'clips', label: localize('config.view.views.clips') },
|
{ value: 'clips', label: localize('config.view.views.clips') },
|
||||||
{ value: 'folder', label: localize('config.view.views.folder') },
|
{ value: 'folder', label: localize('config.view.views.folder') },
|
||||||
{ value: 'folders', label: localize('config.view.views.folders') },
|
{ value: 'folders', label: localize('config.view.views.folders') },
|
||||||
|
{ value: 'gallery', label: localize('config.view.views.gallery') },
|
||||||
{ value: 'image', label: localize('config.view.views.image') },
|
{ value: 'image', label: localize('config.view.views.image') },
|
||||||
{ value: 'live', label: localize('config.view.views.live') },
|
{ value: 'live', label: localize('config.view.views.live') },
|
||||||
|
{ value: 'media', label: localize('config.view.views.media') },
|
||||||
{ value: 'recording', label: localize('config.view.views.recording') },
|
{ value: 'recording', label: localize('config.view.views.recording') },
|
||||||
{ value: 'recordings', label: localize('config.view.views.recordings') },
|
{ value: 'recordings', label: localize('config.view.views.recordings') },
|
||||||
{ value: 'review', label: localize('config.view.views.review') },
|
{ value: 'review', label: localize('config.view.views.review') },
|
||||||
@@ -2927,6 +2929,7 @@ export class AdvancedCameraCardEditor extends LitElement implements LovelaceCard
|
|||||||
${this._renderMenuButton('expand') /* */}
|
${this._renderMenuButton('expand') /* */}
|
||||||
${this._renderMenuButton('folders')}
|
${this._renderMenuButton('folders')}
|
||||||
${this._renderMenuButton('fullscreen')}
|
${this._renderMenuButton('fullscreen')}
|
||||||
|
${this._renderMenuButton('gallery')}
|
||||||
${this._renderMenuButton('image') /* */}
|
${this._renderMenuButton('image') /* */}
|
||||||
${this._renderMenuButton('info') /* */}
|
${this._renderMenuButton('info') /* */}
|
||||||
${this._renderMenuButton('live')}
|
${this._renderMenuButton('live')}
|
||||||
|
|||||||
@@ -459,11 +459,13 @@
|
|||||||
"expand": "Expand",
|
"expand": "Expand",
|
||||||
"folders": "Folders",
|
"folders": "Folders",
|
||||||
"fullscreen": "Fullscreen",
|
"fullscreen": "Fullscreen",
|
||||||
|
"gallery": "Gallery",
|
||||||
"icon": "Icon",
|
"icon": "Icon",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"iris": "Iris / Default View / Unhide menu",
|
"iris": "Iris / Default View / Unhide menu",
|
||||||
"live": "Live",
|
"live": "Live",
|
||||||
|
"media": "Media",
|
||||||
"media_player": "Send to media player",
|
"media_player": "Send to media player",
|
||||||
"microphone": "Microphone",
|
"microphone": "Microphone",
|
||||||
"mute": "Mute / Unmute",
|
"mute": "Mute / Unmute",
|
||||||
@@ -631,8 +633,10 @@
|
|||||||
"current": "Current view",
|
"current": "Current view",
|
||||||
"folder": "Folder media",
|
"folder": "Folder media",
|
||||||
"folders": "Folders gallery",
|
"folders": "Folders gallery",
|
||||||
|
"gallery": "Default media gallery",
|
||||||
"image": "Static image",
|
"image": "Static image",
|
||||||
"live": "Live view",
|
"live": "Live view",
|
||||||
|
"media": "Most recent default media item",
|
||||||
"recording": "Most recent recording",
|
"recording": "Most recent recording",
|
||||||
"recordings": "Recordings gallery",
|
"recordings": "Recordings gallery",
|
||||||
"review": "Most recent media to review",
|
"review": "Most recent media to review",
|
||||||
|
|||||||
@@ -538,5 +538,4 @@
|
|||||||
--advanced-camera-card-overlay-message-scrollbar-color: rgba(0, 0, 0, 0.5);
|
--advanced-camera-card-overlay-message-scrollbar-color: rgba(0, 0, 0, 0.5);
|
||||||
--advanced-camera-card-overlay-message-close-color: #000000;
|
--advanced-camera-card-overlay-message-close-color: #000000;
|
||||||
--app-header-text-color: white;
|
--app-header-text-color: white;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ export const getCameraIDsForViewName = (
|
|||||||
switch (viewName) {
|
switch (viewName) {
|
||||||
case 'diagnostics':
|
case 'diagnostics':
|
||||||
case 'image':
|
case 'image':
|
||||||
case 'media':
|
|
||||||
return cameraManager.getStore().getCameraIDs();
|
return cameraManager.getStore().getCameraIDs();
|
||||||
|
|
||||||
case 'folder':
|
case 'folder':
|
||||||
@@ -51,11 +50,13 @@ export const getCameraIDsForViewName = (
|
|||||||
? cameraManager.getStore().getAllDependentCameras(cameraID, capability, options)
|
? cameraManager.getStore().getAllDependentCameras(cameraID, capability, options)
|
||||||
: cameraManager.getStore().getCameraIDsWithCapability(capability, options);
|
: cameraManager.getStore().getCameraIDsWithCapability(capability, options);
|
||||||
|
|
||||||
|
case 'gallery':
|
||||||
|
case 'media':
|
||||||
case 'timeline':
|
case 'timeline':
|
||||||
return folder
|
return folder
|
||||||
? cameraManager.getStore().getCameraIDs()
|
? cameraManager.getStore().getCameraIDs()
|
||||||
: cameraManager.getStore().getCameraIDsWithCapability({
|
: cameraManager.getStore().getCameraIDsWithCapability({
|
||||||
anyCapabilities: ['clips', 'snapshots', 'recordings'],
|
anyCapabilities: ['clips', 'snapshots', 'recordings', 'reviews'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+8
-3
@@ -127,9 +127,14 @@ export class View {
|
|||||||
* Determine if a view is a gallery.
|
* Determine if a view is a gallery.
|
||||||
*/
|
*/
|
||||||
public isGalleryView(): boolean {
|
public isGalleryView(): boolean {
|
||||||
return ['clips', 'folders', 'snapshots', 'recordings', 'reviews'].includes(
|
return [
|
||||||
this.view,
|
'clips',
|
||||||
);
|
'folders',
|
||||||
|
'gallery',
|
||||||
|
'snapshots',
|
||||||
|
'recordings',
|
||||||
|
'reviews',
|
||||||
|
].includes(this.view);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -568,48 +568,54 @@ describe('ViewQueryExecutor', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with a media view', () => {
|
describe('with a media or gallery view', () => {
|
||||||
it('should set query and queryResults for events', async () => {
|
it.each(['media' as const, 'gallery' as const])(
|
||||||
const api = createPopulatedAPI();
|
'should set query and queryResults for events with %s view',
|
||||||
const cameraManager = api.getCameraManager();
|
async (viewName) => {
|
||||||
if (cameraManager) {
|
const api = createPopulatedAPI();
|
||||||
vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue(
|
const cameraManager = api.getCameraManager();
|
||||||
new Capabilities({ clips: true }),
|
if (cameraManager) {
|
||||||
);
|
vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue(
|
||||||
}
|
new Capabilities({ clips: true }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const viewQueryExecutor = new ViewQueryExecutor(api);
|
const viewQueryExecutor = new ViewQueryExecutor(api);
|
||||||
const view = new View({
|
const view = new View({
|
||||||
view: 'media',
|
view: viewName,
|
||||||
camera: 'camera.office',
|
camera: 'camera.office',
|
||||||
});
|
});
|
||||||
|
|
||||||
const modifiers = await viewQueryExecutor.getNewQueryModifiers(view);
|
const modifiers = await viewQueryExecutor.getNewQueryModifiers(view);
|
||||||
applyViewModifiers(view, modifiers);
|
applyViewModifiers(view, modifiers);
|
||||||
|
|
||||||
expect(view.query).toBeInstanceOf(UnifiedQuery);
|
expect(view.query).toBeInstanceOf(UnifiedQuery);
|
||||||
const queries = view.query?.getMediaQueries({ type: QueryType.Event });
|
const queries = view.query?.getMediaQueries({ type: QueryType.Event });
|
||||||
expect(queries?.length).toBeGreaterThan(0);
|
expect(queries?.length).toBeGreaterThan(0);
|
||||||
expect(queries?.[0].cameraIDs.has('camera.office')).toBe(true);
|
expect(queries?.[0].cameraIDs.has('camera.office')).toBe(true);
|
||||||
expect(view.queryResults).toBeDefined();
|
expect(view.queryResults).toBeDefined();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
it('should query all cameras in media view grid mode', async () => {
|
it.each(['media' as const, 'gallery' as const])(
|
||||||
const api = createPopulatedAPI();
|
'should query all cameras in %s view grid mode',
|
||||||
const viewQueryExecutor = new ViewQueryExecutor(api);
|
async (viewName) => {
|
||||||
const view = createView({
|
const api = createPopulatedAPI();
|
||||||
view: 'media',
|
const viewQueryExecutor = new ViewQueryExecutor(api);
|
||||||
camera: 'camera.office',
|
const view = createView({
|
||||||
displayMode: 'grid',
|
view: viewName,
|
||||||
});
|
camera: 'camera.office',
|
||||||
|
displayMode: 'grid',
|
||||||
|
});
|
||||||
|
|
||||||
const modifiers = await viewQueryExecutor.getNewQueryModifiers(view);
|
const modifiers = await viewQueryExecutor.getNewQueryModifiers(view);
|
||||||
applyViewModifiers(view, modifiers);
|
applyViewModifiers(view, modifiers);
|
||||||
|
|
||||||
expect(view.query).toBeInstanceOf(UnifiedQuery);
|
expect(view.query).toBeInstanceOf(UnifiedQuery);
|
||||||
const allCameraIDs = view.query?.getAllCameraIDs();
|
const allCameraIDs = view.query?.getAllCameraIDs();
|
||||||
expect(allCameraIDs?.size).toBeGreaterThan(0);
|
expect(allCameraIDs?.size).toBeGreaterThan(0);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with an events-based view', () => {
|
describe('with an events-based view', () => {
|
||||||
|
|||||||
@@ -561,9 +561,7 @@ describe('MenuButtonController', () => {
|
|||||||
describe('should have clips menu button', () => {
|
describe('should have clips menu button', () => {
|
||||||
it('when in clips view', () => {
|
it('when in clips view', () => {
|
||||||
const viewManager = mock<ViewManager>();
|
const viewManager = mock<ViewManager>();
|
||||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
vi.mocked(isViewSupportedByCamera).mockReturnValue(true);
|
||||||
(view) => view !== 'reviews',
|
|
||||||
);
|
|
||||||
const buttons = calculateButtons(controller, {
|
const buttons = calculateButtons(controller, {
|
||||||
view: createView({ view: 'clips' }),
|
view: createView({ view: 'clips' }),
|
||||||
viewManager: viewManager,
|
viewManager: viewManager,
|
||||||
@@ -571,7 +569,7 @@ describe('MenuButtonController', () => {
|
|||||||
|
|
||||||
expect(buttons).toContainEqual({
|
expect(buttons).toContainEqual({
|
||||||
icon: 'mdi:filmstrip',
|
icon: 'mdi:filmstrip',
|
||||||
enabled: true,
|
enabled: false,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
type: 'custom:advanced-camera-card-menu-icon',
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
title: 'Clips gallery',
|
title: 'Clips gallery',
|
||||||
@@ -583,16 +581,14 @@ describe('MenuButtonController', () => {
|
|||||||
|
|
||||||
it('when not in clips view', () => {
|
it('when not in clips view', () => {
|
||||||
const viewManager = mock<ViewManager>();
|
const viewManager = mock<ViewManager>();
|
||||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
vi.mocked(isViewSupportedByCamera).mockReturnValue(true);
|
||||||
(view) => view !== 'reviews',
|
|
||||||
);
|
|
||||||
const buttons = calculateButtons(controller, {
|
const buttons = calculateButtons(controller, {
|
||||||
viewManager: viewManager,
|
viewManager: viewManager,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(buttons).toContainEqual({
|
expect(buttons).toContainEqual({
|
||||||
icon: 'mdi:filmstrip',
|
icon: 'mdi:filmstrip',
|
||||||
enabled: true,
|
enabled: false,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
type: 'custom:advanced-camera-card-menu-icon',
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
title: 'Clips gallery',
|
title: 'Clips gallery',
|
||||||
@@ -613,30 +609,6 @@ describe('MenuButtonController', () => {
|
|||||||
expect.arrayContaining([expect.objectContaining({ title: 'Clips gallery' })]),
|
expect.arrayContaining([expect.objectContaining({ title: 'Clips gallery' })]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be hidden when reviews are supported', () => {
|
|
||||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
|
||||||
(view) => view === 'clips' || view === 'reviews',
|
|
||||||
);
|
|
||||||
const buttons = calculateButtons(controller);
|
|
||||||
|
|
||||||
expect(buttons).not.toEqual(
|
|
||||||
expect.arrayContaining([expect.objectContaining({ title: 'Clips gallery' })]),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be shown when reviews are supported but button is explicitly enabled', () => {
|
|
||||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
|
||||||
(view) => view === 'clips' || view === 'reviews',
|
|
||||||
);
|
|
||||||
const buttons = calculateButtons(controller, {
|
|
||||||
config: createConfig({ menu: { buttons: { clips: { enabled: true } } } }),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(buttons).toContainEqual(
|
|
||||||
expect.objectContaining({ title: 'Clips gallery', enabled: true }),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should have snapshots menu button', () => {
|
describe('should have snapshots menu button', () => {
|
||||||
@@ -652,7 +624,7 @@ describe('MenuButtonController', () => {
|
|||||||
|
|
||||||
expect(buttons).toContainEqual({
|
expect(buttons).toContainEqual({
|
||||||
icon: 'mdi:camera',
|
icon: 'mdi:camera',
|
||||||
enabled: true,
|
enabled: false,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
type: 'custom:advanced-camera-card-menu-icon',
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
title: 'Snapshots gallery',
|
title: 'Snapshots gallery',
|
||||||
@@ -670,16 +642,14 @@ describe('MenuButtonController', () => {
|
|||||||
|
|
||||||
it('when not in snapshots view', () => {
|
it('when not in snapshots view', () => {
|
||||||
const viewManager = mock<ViewManager>();
|
const viewManager = mock<ViewManager>();
|
||||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
vi.mocked(isViewSupportedByCamera).mockReturnValue(true);
|
||||||
(view) => view !== 'reviews',
|
|
||||||
);
|
|
||||||
const buttons = calculateButtons(controller, {
|
const buttons = calculateButtons(controller, {
|
||||||
viewManager: viewManager,
|
viewManager: viewManager,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(buttons).toContainEqual({
|
expect(buttons).toContainEqual({
|
||||||
icon: 'mdi:camera',
|
icon: 'mdi:camera',
|
||||||
enabled: true,
|
enabled: false,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
type: 'custom:advanced-camera-card-menu-icon',
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
title: 'Snapshots gallery',
|
title: 'Snapshots gallery',
|
||||||
@@ -708,32 +678,6 @@ describe('MenuButtonController', () => {
|
|||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be hidden when reviews are supported', () => {
|
|
||||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
|
||||||
(view) => view === 'snapshots' || view === 'reviews',
|
|
||||||
);
|
|
||||||
const buttons = calculateButtons(controller);
|
|
||||||
|
|
||||||
expect(buttons).not.toEqual(
|
|
||||||
expect.arrayContaining([
|
|
||||||
expect.objectContaining({ title: 'Snapshots gallery' }),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be shown when reviews are supported but button is explicitly enabled', () => {
|
|
||||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
|
||||||
(view) => view === 'snapshots' || view === 'reviews',
|
|
||||||
);
|
|
||||||
const buttons = calculateButtons(controller, {
|
|
||||||
config: createConfig({ menu: { buttons: { snapshots: { enabled: true } } } }),
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(buttons).toContainEqual(
|
|
||||||
expect.objectContaining({ title: 'Snapshots gallery', enabled: true }),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should have reviews menu button', () => {
|
describe('should have reviews menu button', () => {
|
||||||
@@ -746,8 +690,8 @@ describe('MenuButtonController', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(buttons).toContainEqual({
|
expect(buttons).toContainEqual({
|
||||||
icon: 'mdi:play-box-multiple',
|
icon: 'mdi:play-box-edit-outline',
|
||||||
enabled: true,
|
enabled: false,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
type: 'custom:advanced-camera-card-menu-icon',
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
title: 'Reviews gallery',
|
title: 'Reviews gallery',
|
||||||
@@ -771,8 +715,8 @@ describe('MenuButtonController', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(buttons).toContainEqual({
|
expect(buttons).toContainEqual({
|
||||||
icon: 'mdi:play-box-multiple',
|
icon: 'mdi:play-box-edit-outline',
|
||||||
enabled: true,
|
enabled: false,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
type: 'custom:advanced-camera-card-menu-icon',
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
title: 'Reviews gallery',
|
title: 'Reviews gallery',
|
||||||
@@ -801,6 +745,71 @@ describe('MenuButtonController', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('should have gallery menu button', () => {
|
||||||
|
it('when in gallery view', () => {
|
||||||
|
const viewManager = mock<ViewManager>();
|
||||||
|
vi.mocked(isViewSupportedByCamera).mockReturnValue(true);
|
||||||
|
const buttons = calculateButtons(controller, {
|
||||||
|
view: createView({ view: 'gallery' }),
|
||||||
|
viewManager: viewManager,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(buttons).toContainEqual({
|
||||||
|
icon: 'mdi:play-box-multiple',
|
||||||
|
enabled: true,
|
||||||
|
priority: 50,
|
||||||
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
|
title: 'Gallery',
|
||||||
|
style: { color: 'var(--advanced-camera-card-menu-button-active-color)' },
|
||||||
|
tap_action: {
|
||||||
|
action: 'fire-dom-event',
|
||||||
|
advanced_camera_card_action: 'gallery',
|
||||||
|
},
|
||||||
|
hold_action: {
|
||||||
|
action: 'fire-dom-event',
|
||||||
|
advanced_camera_card_action: 'media',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('when not in gallery view', () => {
|
||||||
|
const viewManager = mock<ViewManager>();
|
||||||
|
vi.mocked(isViewSupportedByCamera).mockReturnValue(true);
|
||||||
|
const buttons = calculateButtons(controller, {
|
||||||
|
viewManager: viewManager,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(buttons).toContainEqual({
|
||||||
|
icon: 'mdi:play-box-multiple',
|
||||||
|
enabled: true,
|
||||||
|
priority: 50,
|
||||||
|
type: 'custom:advanced-camera-card-menu-icon',
|
||||||
|
title: 'Gallery',
|
||||||
|
style: {},
|
||||||
|
tap_action: {
|
||||||
|
action: 'fire-dom-event',
|
||||||
|
advanced_camera_card_action: 'gallery',
|
||||||
|
},
|
||||||
|
hold_action: {
|
||||||
|
action: 'fire-dom-event',
|
||||||
|
advanced_camera_card_action: 'media',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('when not supported', () => {
|
||||||
|
const viewManager = mock<ViewManager>();
|
||||||
|
vi.mocked(isViewSupportedByCamera).mockReturnValue(false);
|
||||||
|
const buttons = calculateButtons(controller, {
|
||||||
|
viewManager: viewManager,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(buttons).not.toEqual(
|
||||||
|
expect.arrayContaining([expect.objectContaining({ title: 'Gallery' })]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('should have recordings menu button', () => {
|
describe('should have recordings menu button', () => {
|
||||||
it('when in recordings view', () => {
|
it('when in recordings view', () => {
|
||||||
const viewManager = mock<ViewManager>();
|
const viewManager = mock<ViewManager>();
|
||||||
|
|||||||
@@ -231,6 +231,10 @@ describe('config defaults', () => {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
},
|
},
|
||||||
|
gallery: {
|
||||||
|
enabled: true,
|
||||||
|
priority: 50,
|
||||||
|
},
|
||||||
image: {
|
image: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
@@ -277,7 +281,7 @@ describe('config defaults', () => {
|
|||||||
priority: 50,
|
priority: 50,
|
||||||
},
|
},
|
||||||
reviews: {
|
reviews: {
|
||||||
enabled: true,
|
enabled: false,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
},
|
},
|
||||||
set_review: {
|
set_review: {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
|
|
||||||
describe('getCameraIDsForViewName', () => {
|
describe('getCameraIDsForViewName', () => {
|
||||||
describe('views that are always supported', () => {
|
describe('views that are always supported', () => {
|
||||||
it.each([['diagnostics' as const], ['image' as const], ['media' as const]])(
|
it.each([['diagnostics' as const], ['image' as const]])(
|
||||||
'%s',
|
'%s',
|
||||||
(viewName: AdvancedCameraCardView) => {
|
(viewName: AdvancedCameraCardView) => {
|
||||||
const cameraManager = createCameraManager();
|
const cameraManager = createCameraManager();
|
||||||
@@ -51,6 +51,15 @@ describe('getCameraIDsForViewName', () => {
|
|||||||
['timeline' as const, 'clips' as const],
|
['timeline' as const, 'clips' as const],
|
||||||
['timeline' as const, 'recordings' as const],
|
['timeline' as const, 'recordings' as const],
|
||||||
['timeline' as const, 'snapshots' as const],
|
['timeline' as const, 'snapshots' as const],
|
||||||
|
['timeline' as const, 'reviews' as const],
|
||||||
|
['media' as const, 'clips' as const],
|
||||||
|
['media' as const, 'recordings' as const],
|
||||||
|
['media' as const, 'snapshots' as const],
|
||||||
|
['media' as const, 'reviews' as const],
|
||||||
|
['gallery' as const, 'clips' as const],
|
||||||
|
['gallery' as const, 'recordings' as const],
|
||||||
|
['gallery' as const, 'snapshots' as const],
|
||||||
|
['gallery' as const, 'reviews' as const],
|
||||||
])('%s', (viewName: AdvancedCameraCardView, capabilityKey: CapabilityKey) => {
|
])('%s', (viewName: AdvancedCameraCardView, capabilityKey: CapabilityKey) => {
|
||||||
const cameraManager = createCameraManager();
|
const cameraManager = createCameraManager();
|
||||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||||
@@ -111,67 +120,73 @@ describe('getCameraIDsForViewName', () => {
|
|||||||
|
|
||||||
describe('views that respect a folder', () => {
|
describe('views that respect a folder', () => {
|
||||||
describe('should return cameras when a folder is present', () => {
|
describe('should return cameras when a folder is present', () => {
|
||||||
it.each([['folder' as const], ['folders' as const], ['timeline' as const]])(
|
it.each([
|
||||||
'%s',
|
['folder' as const],
|
||||||
(viewName: AdvancedCameraCardView) => {
|
['folders' as const],
|
||||||
const cameraManager = createCameraManager();
|
['timeline' as const],
|
||||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
['media' as const],
|
||||||
createStore([
|
['gallery' as const],
|
||||||
{
|
])('%s', (viewName: AdvancedCameraCardView) => {
|
||||||
cameraID: 'camera-1',
|
const cameraManager = createCameraManager();
|
||||||
config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }),
|
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||||
},
|
createStore([
|
||||||
{
|
{
|
||||||
cameraID: 'camera-2',
|
cameraID: 'camera-1',
|
||||||
},
|
config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }),
|
||||||
]),
|
},
|
||||||
);
|
{
|
||||||
const foldersManager = mock<FoldersManager>();
|
cameraID: 'camera-2',
|
||||||
vi.mocked(foldersManager.getFolder).mockReturnValue(createFolder());
|
},
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
const foldersManager = mock<FoldersManager>();
|
||||||
|
vi.mocked(foldersManager.getFolder).mockReturnValue(createFolder());
|
||||||
|
|
||||||
expect(
|
expect(getCameraIDsForViewName(viewName, cameraManager, foldersManager)).toEqual(
|
||||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager),
|
new Set(['camera-1', 'camera-2']),
|
||||||
).toEqual(new Set(['camera-1', 'camera-2']));
|
);
|
||||||
expect(
|
expect(
|
||||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-1'),
|
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-1'),
|
||||||
).toEqual(new Set(['camera-1', 'camera-2']));
|
).toEqual(new Set(['camera-1', 'camera-2']));
|
||||||
expect(
|
expect(
|
||||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-2'),
|
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-2'),
|
||||||
).toEqual(new Set(['camera-1', 'camera-2']));
|
).toEqual(new Set(['camera-1', 'camera-2']));
|
||||||
},
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('should not return cameras when a folder is absent', () => {
|
describe('should not return cameras when a folder is absent', () => {
|
||||||
it.each([['folder' as const], ['folders' as const], ['timeline' as const]])(
|
it.each([
|
||||||
'%s',
|
['folder' as const],
|
||||||
(viewName: AdvancedCameraCardView) => {
|
['folders' as const],
|
||||||
const cameraManager = createCameraManager();
|
['timeline' as const],
|
||||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
['media' as const],
|
||||||
createStore([
|
['gallery' as const],
|
||||||
{
|
])('%s', (viewName: AdvancedCameraCardView) => {
|
||||||
cameraID: 'camera-1',
|
const cameraManager = createCameraManager();
|
||||||
config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }),
|
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||||
},
|
createStore([
|
||||||
{
|
{
|
||||||
cameraID: 'camera-2',
|
cameraID: 'camera-1',
|
||||||
},
|
config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }),
|
||||||
]),
|
},
|
||||||
);
|
{
|
||||||
const foldersManager = mock<FoldersManager>();
|
cameraID: 'camera-2',
|
||||||
vi.mocked(foldersManager.getFolder).mockReturnValue(null);
|
},
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
const foldersManager = mock<FoldersManager>();
|
||||||
|
vi.mocked(foldersManager.getFolder).mockReturnValue(null);
|
||||||
|
|
||||||
expect(
|
expect(getCameraIDsForViewName(viewName, cameraManager, foldersManager)).toEqual(
|
||||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager),
|
new Set(),
|
||||||
).toEqual(new Set());
|
);
|
||||||
expect(
|
expect(
|
||||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-1'),
|
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-1'),
|
||||||
).toEqual(new Set());
|
).toEqual(new Set());
|
||||||
expect(
|
expect(
|
||||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-2'),
|
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-2'),
|
||||||
).toEqual(new Set());
|
).toEqual(new Set());
|
||||||
},
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user