refactor: Break apart monolithic configuration schema (#1977)
[skip ci]
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const aspectRatioSchema = z
|
||||
.number()
|
||||
.array()
|
||||
.length(2)
|
||||
.or(
|
||||
z
|
||||
.string()
|
||||
.regex(/^\s*\d+\.?\d*\s*[:/]\s*\d+\.?\d*\s*$/)
|
||||
.transform((input) => input.split(/[:\/]/).map((d) => Number(d))),
|
||||
);
|
||||
@@ -0,0 +1,35 @@
|
||||
export const cardIDRegex = /^[-\w]+$/;
|
||||
|
||||
export const MENU_PRIORITY_DEFAULT = 50;
|
||||
export const MENU_PRIORITY_MAX = 100;
|
||||
|
||||
export const STATUS_BAR_PRIORITY_DEFAULT = 50;
|
||||
export const STATUS_BAR_PRIORITY_MAX = 100;
|
||||
|
||||
export const BUTTON_SIZE_MIN = 20;
|
||||
|
||||
// The default view (may not be supported on all cameras).
|
||||
export const VIEW_DEFAULT = 'live' as const;
|
||||
|
||||
export const VIEWS_USER_SPECIFIED = [
|
||||
'diagnostics',
|
||||
'live',
|
||||
'clip',
|
||||
'clips',
|
||||
'snapshot',
|
||||
'snapshots',
|
||||
'recording',
|
||||
'recordings',
|
||||
'image',
|
||||
'timeline',
|
||||
] as const;
|
||||
export type AdvancedCameraCardUserSpecifiedView = (typeof VIEWS_USER_SPECIFIED)[number];
|
||||
|
||||
const VIEWS = [
|
||||
...VIEWS_USER_SPECIFIED,
|
||||
'diagnostics',
|
||||
|
||||
// Media: A generic piece of media (could be clip, snapshot, recording).
|
||||
'media',
|
||||
] as const;
|
||||
export type AdvancedCameraCardView = (typeof VIEWS)[number];
|
||||
@@ -0,0 +1,8 @@
|
||||
import { z } from 'zod';
|
||||
import { BUTTON_SIZE_MIN } from '../const';
|
||||
|
||||
export const nextPreviousControlConfigSchema = z.object({
|
||||
style: z.enum(['none', 'chevrons', 'icons', 'thumbnails']),
|
||||
size: z.number().min(BUTTON_SIZE_MIN),
|
||||
});
|
||||
export type NextPreviousControlConfig = z.infer<typeof nextPreviousControlConfigSchema>;
|
||||
@@ -0,0 +1,27 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ptzControlsDefaults = {
|
||||
orientation: 'horizontal' as const,
|
||||
mode: 'auto' as const,
|
||||
hide_pan_tilt: false,
|
||||
hide_zoom: false,
|
||||
hide_home: false,
|
||||
position: 'bottom-right' as const,
|
||||
};
|
||||
|
||||
export const ptzControlsConfigSchema = z.object({
|
||||
mode: z.enum(['off', 'auto', 'on']).default(ptzControlsDefaults.mode),
|
||||
position: z
|
||||
.enum(['top-left', 'top-right', 'bottom-left', 'bottom-right'])
|
||||
.default(ptzControlsDefaults.position),
|
||||
orientation: z
|
||||
.enum(['vertical', 'horizontal'])
|
||||
.default(ptzControlsDefaults.orientation),
|
||||
|
||||
hide_pan_tilt: z.boolean().default(ptzControlsDefaults.hide_pan_tilt),
|
||||
hide_zoom: z.boolean().default(ptzControlsDefaults.hide_zoom),
|
||||
hide_home: z.boolean().default(ptzControlsDefaults.hide_home),
|
||||
|
||||
style: z.object({}).passthrough().optional(),
|
||||
});
|
||||
export type PTZControlsConfig = z.infer<typeof ptzControlsConfigSchema>;
|
||||
@@ -0,0 +1,45 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
// The min/max width thumbnail.
|
||||
export const THUMBNAIL_WIDTH_MIN = 75;
|
||||
export const THUMBNAIL_WIDTH_MAX = 300;
|
||||
|
||||
const thumbnailControlsBaseDefaults = {
|
||||
size: 100,
|
||||
show_details: true,
|
||||
show_favorite_control: true,
|
||||
show_timeline_control: true,
|
||||
show_download_control: true,
|
||||
};
|
||||
|
||||
// Configuration for the actual rendered thumbnail.
|
||||
const thumbnailsControlBaseSchema = z.object({
|
||||
size: z
|
||||
.number()
|
||||
.min(THUMBNAIL_WIDTH_MIN)
|
||||
.max(THUMBNAIL_WIDTH_MAX)
|
||||
.default(thumbnailControlsBaseDefaults.size),
|
||||
show_details: z.boolean().default(thumbnailControlsBaseDefaults.show_details),
|
||||
show_favorite_control: z
|
||||
.boolean()
|
||||
.default(thumbnailControlsBaseDefaults.show_favorite_control),
|
||||
show_timeline_control: z
|
||||
.boolean()
|
||||
.default(thumbnailControlsBaseDefaults.show_timeline_control),
|
||||
show_download_control: z
|
||||
.boolean()
|
||||
.default(thumbnailControlsBaseDefaults.show_download_control),
|
||||
});
|
||||
export type ThumbnailsControlBaseConfig = z.infer<typeof thumbnailsControlBaseSchema>;
|
||||
|
||||
export const thumbnailControlsDefaults = {
|
||||
...thumbnailControlsBaseDefaults,
|
||||
mode: 'right' as const,
|
||||
};
|
||||
|
||||
export const thumbnailsControlSchema = thumbnailsControlBaseSchema.extend({
|
||||
mode: z
|
||||
.enum(['none', 'above', 'below', 'left', 'right'])
|
||||
.default(thumbnailControlsDefaults.mode),
|
||||
});
|
||||
export type ThumbnailsControlConfig = z.infer<typeof thumbnailsControlSchema>;
|
||||
@@ -0,0 +1,67 @@
|
||||
import { z } from 'zod';
|
||||
import { eventsMediaTypeSchema } from '../events-media';
|
||||
import { thumbnailControlsDefaults } from './thumbnails';
|
||||
|
||||
const timelineCoreConfigDefault = {
|
||||
clustering_threshold: 3,
|
||||
events_media_type: 'all' as const,
|
||||
window_seconds: 60 * 60,
|
||||
show_recordings: true,
|
||||
style: 'stack' as const,
|
||||
pan_mode: 'pan' as const,
|
||||
format: {
|
||||
'24h': true,
|
||||
},
|
||||
};
|
||||
|
||||
const timelinePanModeSchema = z.enum(['pan', 'seek', 'seek-in-media', 'seek-in-camera']);
|
||||
export type TimelinePanMode = z.infer<typeof timelinePanModeSchema>;
|
||||
|
||||
const timelineFormatSchema = z.object({
|
||||
'24h': z.boolean().optional().default(timelineCoreConfigDefault.format['24h']),
|
||||
});
|
||||
|
||||
export const timelineCoreConfigSchema = z.object({
|
||||
clustering_threshold: z
|
||||
.number()
|
||||
.optional()
|
||||
.default(timelineCoreConfigDefault.clustering_threshold),
|
||||
events_media_type: eventsMediaTypeSchema
|
||||
.optional()
|
||||
.default(timelineCoreConfigDefault.events_media_type),
|
||||
window_seconds: z
|
||||
.number()
|
||||
.min(1 * 60)
|
||||
.max(24 * 60 * 60)
|
||||
.optional()
|
||||
.default(timelineCoreConfigDefault.window_seconds),
|
||||
show_recordings: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(timelineCoreConfigDefault.show_recordings),
|
||||
style: z.enum(['stack', 'ribbon']).optional().default(timelineCoreConfigDefault.style),
|
||||
pan_mode: timelinePanModeSchema.optional().default(timelineCoreConfigDefault.pan_mode),
|
||||
format: timelineFormatSchema.optional().default(timelineCoreConfigDefault.format),
|
||||
});
|
||||
export type TimelineCoreConfig = z.infer<typeof timelineCoreConfigSchema>;
|
||||
|
||||
export const miniTimelineConfigDefault = {
|
||||
...timelineCoreConfigDefault,
|
||||
mode: 'none' as const,
|
||||
|
||||
// Mini-timeline defaults to ribbon style.
|
||||
style: 'ribbon' as const,
|
||||
};
|
||||
|
||||
export const miniTimelineConfigSchema = timelineCoreConfigSchema.extend({
|
||||
mode: z.enum(['none', 'above', 'below']).default(miniTimelineConfigDefault.mode),
|
||||
style: timelineCoreConfigSchema.shape.style.default(miniTimelineConfigDefault.style),
|
||||
});
|
||||
export type MiniTimelineControlConfig = z.infer<typeof miniTimelineConfigSchema>;
|
||||
|
||||
export const timelineConfigDefault = {
|
||||
...timelineCoreConfigDefault,
|
||||
controls: {
|
||||
thumbnails: thumbnailControlsDefaults,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const viewDisplayModeSchema = z.enum(['single', 'grid']);
|
||||
export type ViewDisplayMode = z.infer<typeof viewDisplayModeSchema>;
|
||||
|
||||
export const viewDisplaySchema = z
|
||||
.object({
|
||||
mode: viewDisplayModeSchema.optional(),
|
||||
grid_selected_width_factor: z.number().min(0).optional(),
|
||||
grid_max_columns: z.number().min(0).optional(),
|
||||
grid_columns: z.number().min(0).optional(),
|
||||
})
|
||||
.optional();
|
||||
export type ViewDisplayConfig = z.infer<typeof viewDisplaySchema>;
|
||||
@@ -0,0 +1,3 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const eventsMediaTypeSchema = z.enum(['all', 'clips', 'snapshots']);
|
||||
@@ -0,0 +1,20 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const imageConfigDefault = {
|
||||
mode: 'auto' as const,
|
||||
refresh_seconds: 1,
|
||||
zoomable: true,
|
||||
};
|
||||
|
||||
const IMAGE_MODES = ['auto', 'camera', 'entity', 'screensaver', 'url'] as const;
|
||||
export type ImageMode = (typeof IMAGE_MODES)[number];
|
||||
|
||||
export const imageBaseConfigSchema = z.object({
|
||||
mode: z.enum(IMAGE_MODES).default(imageConfigDefault.mode),
|
||||
|
||||
refresh_seconds: z.number().min(0).default(imageConfigDefault.refresh_seconds),
|
||||
|
||||
url: z.string().optional(),
|
||||
entity: z.string().optional(),
|
||||
entity_parameters: z.string().optional(),
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
export const MEDIA_ACTION_POSITIVE_CONDITIONS = ['selected', 'visible'] as const;
|
||||
export const MEDIA_ACTION_NEGATIVE_CONDITIONS = ['unselected', 'hidden'] as const;
|
||||
|
||||
export const MEDIA_MUTE_CONDITIONS = [
|
||||
...MEDIA_ACTION_NEGATIVE_CONDITIONS,
|
||||
'microphone',
|
||||
] as const;
|
||||
|
||||
export const MEDIA_UNMUTE_CONDITIONS = [
|
||||
...MEDIA_ACTION_POSITIVE_CONDITIONS,
|
||||
'microphone',
|
||||
] as const;
|
||||
|
||||
export type AutoPlayCondition = (typeof MEDIA_ACTION_POSITIVE_CONDITIONS)[number];
|
||||
export type AutoPauseCondition = (typeof MEDIA_ACTION_NEGATIVE_CONDITIONS)[number];
|
||||
export type AutoMuteCondition = (typeof MEDIA_MUTE_CONDITIONS)[number];
|
||||
export type AutoUnmuteCondition = (typeof MEDIA_UNMUTE_CONDITIONS)[number];
|
||||
|
||||
export type LazyUnloadCondition = (typeof MEDIA_ACTION_NEGATIVE_CONDITIONS)[number];
|
||||
@@ -0,0 +1,6 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const panSchema = z.object({
|
||||
x: z.number().min(0).max(100).optional(),
|
||||
y: z.number().min(0).max(100).optional(),
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
import { z } from 'zod';
|
||||
import { STATUS_BAR_PRIORITY_DEFAULT, STATUS_BAR_PRIORITY_MAX } from './const';
|
||||
|
||||
export const statusBarItemBaseSchema = z.object({
|
||||
enabled: z.boolean().default(true).optional(),
|
||||
priority: z
|
||||
.number()
|
||||
.min(0)
|
||||
.max(STATUS_BAR_PRIORITY_MAX)
|
||||
.default(STATUS_BAR_PRIORITY_DEFAULT)
|
||||
.optional(),
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const transitionEffectConfigSchema = z.enum(['none', 'slide']);
|
||||
export type TransitionEffect = z.infer<typeof transitionEffectConfigSchema>;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZOOM_MIN = 1;
|
||||
export const ZOOM_MAX = 10;
|
||||
|
||||
export const zoomSchema = z.number().min(ZOOM_MIN).max(ZOOM_MAX);
|
||||
Reference in New Issue
Block a user