Add support for configuration profiles.

This commit is contained in:
Dermot Duffy
2024-03-28 21:41:48 -07:00
parent 0b9935dfe2
commit bde4e6cd38
25 changed files with 412 additions and 184 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
import { CurrentUser } from '@dermotduffy/custom-card-helpers';
import { HassEntities } from 'home-assistant-js-websocket';
import merge from 'lodash-es/merge';
import { copyConfig } from '../config-mgmt';
import { copyConfig } from '../config/management';
import {
FrigateCardCondition,
frigateConditionalSchema,
+3 -6
View File
@@ -1,5 +1,5 @@
import isEqual from 'lodash-es/isEqual';
import { isConfigUpgradeable } from '../config-mgmt';
import { isConfigUpgradeable } from '../config/management';
import {
CardWideConfig,
FrigateCardConfig,
@@ -7,7 +7,7 @@ import {
RawFrigateCardConfig
} from '../config/types';
import { localize } from '../localize/localize';
import { setLowPerformanceProfile } from '../performance.js';
import { setProfiles } from '../config/profiles';
import { getParseErrorPaths } from '../utils/zod.js';
import { getOverriddenConfig } from './conditions-manager';
import { InitializationAspect } from './initialization-manager';
@@ -70,10 +70,7 @@ export class ConfigManager {
: localize('error.invalid_configuration_no_hint')),
);
}
const config =
parseResult.data.performance.profile !== 'low'
? parseResult.data
: setLowPerformanceProfile(inputConfig, parseResult.data);
const config = setProfiles(inputConfig, parseResult.data, parseResult.data.profiles);
this._rawConfig = inputConfig;
if (isEqual(this._config, config)) {
+16 -5
View File
@@ -1,6 +1,5 @@
import { StyleInfo } from 'lit/directives/style-map';
import { FrigateCardConfig } from '../config/types';
import { setPerformanceCSSStyles } from '../performance';
import { aspectRatioToStyle, setOrRemoveAttribute } from '../utils/basic';
import { View } from '../view/view';
import { CardStyleAPI } from './types';
@@ -69,10 +68,22 @@ export class StyleManager {
}
public setPerformance(): void {
setPerformanceCSSStyles(
this._api.getCardElementManager().getElement(),
this._api.getConfigManager().getCardWideConfig()?.performance,
);
const STYLE_DISABLE_MAP = {
box_shadow: 'none',
border_radius: '0px',
};
const element = this._api.getCardElementManager().getElement();
const performance = this._api.getConfigManager().getCardWideConfig()?.performance;
const styles = performance?.style ?? {};
for (const configKey of Object.keys(styles)) {
const CSSKey = `--frigate-card-css-${configKey.replaceAll('_', '-')}`;
if (styles[configKey] === false) {
element.style.setProperty(CSSKey, STYLE_DISABLE_MAP[configKey]);
} else {
element.style.removeProperty(CSSKey);
}
}
}
protected _isAspectRatioEnforced(
+1 -5
View File
@@ -855,11 +855,7 @@ export class FrigateCardLiveProvider
) {
return 'webrtc-card';
} else if (this.cameraConfig?.camera_entity) {
if (this.cardWideConfig?.performance?.profile === 'low') {
return 'image';
} else {
return 'ha';
}
return 'ha';
} else if (this.cameraConfig?.frigate.camera_name) {
return 'jsmpeg';
}
@@ -7,7 +7,7 @@ import {
FrigateCardCondition,
RawFrigateCardConfig,
RawFrigateCardConfigArray,
} from './config/types';
} from './types';
import {
CONF_AUTOMATIONS,
CONF_CAMERAS,
@@ -22,14 +22,15 @@ import {
CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE,
CONF_MENU_BUTTONS_CAMERA_UI,
CONF_OVERRIDES,
CONF_PROFILES,
CONF_TIMELINE_EVENTS_MEDIA_TYPE,
CONF_VIEW_INTERACTION_SECONDS,
CONF_VIEW_TRIGGERS,
CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER,
CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER,
CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA,
} from './const';
import { arrayify } from './utils/basic';
} from '../const';
import { arrayify } from '../utils/basic';
// *************************************************************************
// General Config Management Functions
@@ -684,4 +685,8 @@ const UPGRADES = [
transform: (val) => (val === true ? { disable_except: 'substream' } : null),
}),
),
upgradeMoveToWithOverrides('performance.profile', CONF_PROFILES, {
// Delete the value if it's set to the default.
transform: (val) => (val === 'low' ? ['low-performance'] : null),
}),
];
+51
View File
@@ -0,0 +1,51 @@
import { getConfigValue, setConfigValue } from '../management.js';
import {
ProfileType,
RawFrigateCardConfig,
frigateCardConfigSchema,
} from '../types.js';
import { deepRemoveDefaults } from '../../utils/zod.js';
import { LOW_PERFORMANCE_PROFILE } from './low-performance.js';
import { SCRUBBING_PROFILE } from './scrubbing.js';
const PROFILES = {
'low-performance': LOW_PERFORMANCE_PROFILE,
'scrubbing': SCRUBBING_PROFILE,
};
/**
* Set a profile. Sets flags as defined in the relevant profile unless they are
* explicitly overriden in the configuration.
* @param inputConfig The raw unparsed input configuration.
* @param outputConfig The output config to write to.
* @returns A changed (in-place) parsed input configuration.
*/
export const setProfiles = <T extends RawFrigateCardConfig>(
inputConfig: RawFrigateCardConfig,
outputConfig: T,
profiles?: ProfileType[],
): T => {
const defaultLessParseResult = deepRemoveDefaults(frigateCardConfigSchema).safeParse(
inputConfig,
);
if (!defaultLessParseResult.success) {
return outputConfig;
}
const defaultLessConfig = defaultLessParseResult.data;
const setIfNotSpecified = (key: string, value: unknown) => {
if (getConfigValue(defaultLessConfig, key) === undefined) {
setConfigValue(outputConfig, key, value);
}
};
for (const profile of profiles ?? []) {
if (profile in PROFILES) {
Object.entries(PROFILES[profile]).forEach(([k, v]: [string, unknown]) =>
setIfNotSpecified(k, v),
);
}
}
return outputConfig;
};
@@ -1,11 +1,6 @@
import { getConfigValue, setConfigValue } from './config-mgmt.js';
import {
PerformanceConfig,
RawFrigateCardConfig,
frigateCardConfigSchema,
} from './config/types.js';
import {
CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS,
CONF_CAMERAS_GLOBAL_LIVE_PROVIDER,
CONF_CAMERAS_GLOBAL_TRIGGERS_OCCUPANCY,
CONF_LIVE_AUTO_MUTE,
CONF_LIVE_CONTROLS_THUMBNAILS_MODE,
@@ -51,13 +46,9 @@ import {
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL,
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL,
CONF_TIMELINE_SHOW_RECORDINGS,
} from './const.js';
import { deepRemoveDefaults } from './utils/zod.js';
} from '../../const.js';
// Caution: These values are applied after parsing (since we cannot know the
// performance profile until afterwards), so there is no validation on these
// defaults.
const LOW_PROFILE_DEFAULTS = {
export const LOW_PERFORMANCE_PROFILE = {
// Disable thumbnail carousels.
[CONF_LIVE_CONTROLS_THUMBNAILS_MODE]: 'none' as const,
[CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_MODE]: 'none' as const,
@@ -138,68 +129,9 @@ const LOW_PROFILE_DEFAULTS = {
[CONF_MEDIA_VIEWER_SNAPSHOT_CLICK_PLAYS_CLIP]: false,
[CONF_CAMERAS_GLOBAL_TRIGGERS_OCCUPANCY]: false,
[CONF_CAMERAS_GLOBAL_LIVE_PROVIDER]: 'image',
// Refresh the live camera image every 10 seconds (same as stock Home
// Assistant Picture Glance).
[CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS]: 10,
};
/**
* Set low performance profile mode. Sets flags as defined in
* LOW_PROFILE_DEFAULTS unless they are explicitly overriden in the
* configuration.
* @param inputConfig The raw unparsed input configuration.
* @param outputConfig The output config to write to.
* @returns A changed (in-place) parsed input configuration.
*/
export const setLowPerformanceProfile = <T extends RawFrigateCardConfig>(
inputConfig: RawFrigateCardConfig,
outputConfig: T,
): T => {
const setIfNotSpecified = (
defaultLessConfig: RawFrigateCardConfig,
outputConfig: T,
key: string,
value: unknown,
) => {
if (getConfigValue(defaultLessConfig, key) === undefined) {
setConfigValue(outputConfig, key, value);
}
};
const defaultLessParseResult = deepRemoveDefaults(frigateCardConfigSchema).safeParse(
inputConfig,
);
if (defaultLessParseResult.success) {
const defaultLessConfig = defaultLessParseResult.data;
Object.entries(LOW_PROFILE_DEFAULTS).forEach(([k, v]: [string, unknown]) =>
setIfNotSpecified(defaultLessConfig, outputConfig, k, v),
);
}
return outputConfig;
};
const STYLE_DISABLE_MAP = {
box_shadow: 'none',
border_radius: '0px',
};
/**
* Set card-wide CSS variables for performance.
* @param element The element to set the variables on.
* @param performance The performance configuration.
*/
export const setPerformanceCSSStyles = (
element: HTMLElement,
performance?: PerformanceConfig,
): void => {
const styles = performance?.style ?? {};
for (const configKey of Object.keys(styles)) {
const CSSKey = `--frigate-card-css-${configKey.replaceAll('_', '-')}`;
if (styles[configKey] === false) {
element.style.setProperty(CSSKey, STYLE_DISABLE_MAP[configKey]);
} else {
element.style.removeProperty(CSSKey);
}
}
};
+18
View File
@@ -0,0 +1,18 @@
import {
CONF_LIVE_CONTROLS_TIMELINE_MODE,
CONF_LIVE_CONTROLS_TIMELINE_PAN_MODE,
CONF_LIVE_CONTROLS_TIMELINE_STYLE,
CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE,
CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_PAN_MODE,
CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE,
} from '../../const.js';
export const SCRUBBING_PROFILE = {
[CONF_LIVE_CONTROLS_TIMELINE_MODE]: 'below' as const,
[CONF_LIVE_CONTROLS_TIMELINE_STYLE]: 'ribbon' as const,
[CONF_LIVE_CONTROLS_TIMELINE_PAN_MODE]: 'seek' as const,
[CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE]: 'below' as const,
[CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE]: 'ribbon' as const,
[CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_PAN_MODE]: 'seek' as const,
};
+9 -2
View File
@@ -1623,7 +1623,6 @@ export type Automations = z.infer<typeof automationsSchema>;
// *************************************************************************
const performanceConfigDefault = {
profile: 'high' as const,
features: {
animated_progress_indicator: true,
media_chunk_size: MEDIA_CHUNK_SIZE_DEFAULT,
@@ -1636,7 +1635,6 @@ const performanceConfigDefault = {
export const performanceConfigSchema = z
.object({
profile: z.enum(['low', 'high']).default(performanceConfigDefault.profile),
features: z
.object({
animated_progress_indicator: z
@@ -1679,6 +1677,13 @@ export interface CardWideConfig {
debug?: DebugConfig;
}
// *************************************************************************
// *** Profile Configuration ***
// *************************************************************************
const PROFILES = ['low-performance', 'scrubbing'] as const;
export type ProfileType = (typeof PROFILES)[number];
export const profilesSchema = z.enum(PROFILES).array().optional();
// *************************************************************************
// *** Card Configuration ***
// *************************************************************************
@@ -1705,6 +1710,8 @@ export const frigateCardConfigSchema = z.object({
debug: debugConfigSchema,
automations: automationsSchema,
profiles: profilesSchema,
// Configuration overrides.
overrides: overridesSchema,
+4
View File
@@ -72,6 +72,8 @@ export const CONF_CAMERAS_ARRAY_TRIGGERS_EVENTS =
const CONF_CAMERAS_GLOBAL = 'cameras_global' as const;
export const CONF_CAMERAS_GLOBAL_IMAGE = `${CONF_CAMERAS_GLOBAL}.image` as const;
export const CONF_CAMERAS_GLOBAL_LIVE_PROVIDER =
`${CONF_CAMERAS_GLOBAL}.live_provider` as const;
export const CONF_CAMERAS_GLOBAL_JSMPEG = `${CONF_CAMERAS_GLOBAL}.jsmpeg` as const;
export const CONF_CAMERAS_GLOBAL_WEBRTC_CARD =
`${CONF_CAMERAS_GLOBAL}.webrtc_card` as const;
@@ -313,6 +315,8 @@ export const CONF_PERFORMANCE_PROFILE = `${CONF_PERFORMANCE}.profile`;
export const CONF_PERFORMANCE_STYLE_BOX_SHADOW = `${CONF_PERFORMANCE}.style.box_shadow`;
export const CONF_PERFORMANCE_STYLE_BORDER_RADIUS = `${CONF_PERFORMANCE}.style.border_radius`;
export const CONF_PROFILES = 'profiles' as const;
// Taken from https://github.dev/home-assistant/frontend/blob/b5861869e39290fd2e15737e89571dfc543b3ad3/src/data/media-player.ts#L93
export const MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA = 131072;
+33 -26
View File
@@ -19,21 +19,24 @@ import {
isConfigUpgradeable,
setConfigValue,
upgradeConfig,
} from './config-mgmt.js';
} from './config/management.js';
import { setProfiles } from './config/profiles/index.js';
import {
BUTTON_SIZE_MIN,
FrigateCardConfig,
frigateCardConfigDefaults,
FRIGATE_MENU_PRIORITY_MAX,
profilesSchema,
RawFrigateCardConfig,
RawFrigateCardConfigArray,
THUMBNAIL_WIDTH_MAX,
THUMBNAIL_WIDTH_MIN,
} from './config/types.js';
import {
CONF_CAMERAS,
CONF_CAMERAS_ARRAY_CAMERA_ENTITY,
CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE_EXCEPT,
CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE,
CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE_EXCEPT,
CONF_CAMERAS_ARRAY_CAST_DASHBOARD_DASHBOARD_PATH,
CONF_CAMERAS_ARRAY_CAST_DASHBOARD_VIEW_PATH,
CONF_CAMERAS_ARRAY_CAST_METHOD,
@@ -67,9 +70,8 @@ import {
CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY,
CONF_CAMERAS_ARRAY_WEBRTC_CARD_ENTITY,
CONF_CAMERAS_ARRAY_WEBRTC_CARD_URL,
CONF_CAMERAS,
CONF_DIMENSIONS_ASPECT_RATIO_MODE,
CONF_DIMENSIONS_ASPECT_RATIO,
CONF_DIMENSIONS_ASPECT_RATIO_MODE,
CONF_DIMENSIONS_MAX_HEIGHT,
CONF_DIMENSIONS_MIN_HEIGHT,
CONF_IMAGE_MODE,
@@ -158,8 +160,8 @@ import {
CONF_MEDIA_VIEWER_TRANSITION_EFFECT,
CONF_MEDIA_VIEWER_ZOOMABLE,
CONF_MENU_ALIGNMENT,
CONF_MENU_BUTTON_SIZE,
CONF_MENU_BUTTONS,
CONF_MENU_BUTTON_SIZE,
CONF_MENU_POSITION,
CONF_MENU_STYLE,
CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR,
@@ -167,6 +169,7 @@ import {
CONF_PERFORMANCE_PROFILE,
CONF_PERFORMANCE_STYLE_BORDER_RADIUS,
CONF_PERFORMANCE_STYLE_BOX_SHADOW,
CONF_PROFILES,
CONF_TIMELINE_CLUSTERING_THRESHOLD,
CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE,
CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_DETAILS,
@@ -183,21 +186,20 @@ import {
CONF_VIEW_DEFAULT,
CONF_VIEW_INTERACTION_SECONDS,
CONF_VIEW_RESET_AFTER_INTERACTION,
CONF_VIEW_TRIGGERS,
CONF_VIEW_TRIGGERS_ACTIONS,
CONF_VIEW_TRIGGERS_ACTIONS_INTERACTION_MODE,
CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER,
CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER,
CONF_VIEW_TRIGGERS_ACTIONS,
CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA,
CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS,
CONF_VIEW_TRIGGERS_UNTRIGGER_SECONDS,
CONF_VIEW_TRIGGERS,
CONF_VIEW_UPDATE_CYCLE_CAMERA,
CONF_VIEW_UPDATE_FORCE,
CONF_VIEW_UPDATE_SECONDS,
MEDIA_CHUNK_SIZE_MAX,
} from './const.js';
import { localize } from './localize/localize.js';
import { setLowPerformanceProfile } from './performance.js';
import frigate_card_editor_style from './scss/editor.scss';
import { arrayMove, prettifyTitle } from './utils/basic.js';
import { getCameraID } from './utils/camera.js';
@@ -315,6 +317,11 @@ const options: EditorOptions = {
name: localize('editor.performance'),
secondary: localize('editor.performance_secondary'),
},
profiles: {
icon: 'folder-wrench-outline',
name: localize('editor.profiles'),
secondary: localize('editor.profiles_secondary'),
},
overrides: {
icon: 'file-replace',
name: localize('editor.overrides'),
@@ -589,10 +596,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
{ value: 'below', label: localize('config.common.controls.timeline.modes.below') },
];
protected _performanceProfiles: EditorSelectOption[] = [
protected _profiles: EditorSelectOption[] = [
{ value: '', label: '' },
{ value: 'low', label: localize('config.performance.profiles.low') },
{ value: 'high', label: localize('config.performance.profiles.high') },
{ value: 'low-performance', label: localize('config.profiles.low-performance') },
{ value: 'scrubbing', label: localize('config.profiles.scrubbing') },
];
protected _go2rtcModes: EditorSelectOption[] = [
@@ -788,25 +795,20 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
];
public setConfig(config: RawFrigateCardConfig): void {
// Note: This does not use Zod to parse the configuration, so it may be
// Note: This does not use Zod to parse the full configuration, so it may be
// partially or completely invalid. It's more useful to have a partially
// valid configuration here, to allow the user to fix the broken parts. As
// such, RawFrigateCardConfig is used as the type.
this._config = config;
this._configUpgradeable = isConfigUpgradeable(config);
let unvalidatedProfile: string | null = null;
try {
// this._config may not be a valid FrigateCardConfig as it has not been
// parsed. Attempt to pull out the performance profile.
unvalidatedProfile = (this._config as FrigateCardConfig).performance?.profile;
} catch (_) {}
const profiles = profilesSchema.safeParse(
(this._config as FrigateCardConfig).profiles,
);
if (unvalidatedProfile === 'high' || unvalidatedProfile === 'low') {
if (profiles.success) {
const defaults = copyConfig(frigateCardConfigDefaults);
if (unvalidatedProfile === 'low') {
setLowPerformanceProfile(this._config, defaults);
}
setProfiles(this._config, defaults, profiles.data);
this._defaults = defaults;
}
}
@@ -2130,6 +2132,15 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
</div>
`
: ''}
${this._renderOptionSetHeader('profiles')}
${this._expandedMenus[MENU_OPTIONS] === 'profiles'
? html` <div class="values">
${this._renderOptionSelector(CONF_PROFILES, this._profiles, {
multiple: true,
label: localize('config.profiles.editor_label'),
})}
</div>`
: ''}
${this._renderOptionSetHeader('view')}
${this._expandedMenus[MENU_OPTIONS] === 'view'
? html`
@@ -2556,10 +2567,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
${getConfigValue(this._config, CONF_PERFORMANCE_PROFILE) === 'low'
? this._renderInfo(localize('config.performance.warning'))
: html``}
${this._renderOptionSelector(
CONF_PERFORMANCE_PROFILE,
this._performanceProfiles,
)}
${this._putInSubmenu(
MENU_PERFORMANCE_FEATURES,
true,
+7 -5
View File
@@ -401,11 +401,6 @@
"editor_label": "Opcions de característiques",
"media_chunk_size": "Mida del fragment multimèdia"
},
"profile": "Perfil de rendiment",
"profiles": {
"high": "Alt rendiment",
"low": "Baix rendiment"
},
"style": {
"border_radius": "Corbes",
"box_shadow": "Ombres",
@@ -413,6 +408,11 @@
},
"warning": "Aquesta targeta està en mode de perfil baix, de manera que els valors predeterminats han canviat per optimitzar el rendiment"
},
"profiles": {
"editor_label": "",
"low-performance": "",
"scrubbing": ""
},
"view": {
"camera_select": "Visualitza les càmeres seleccionades recentment",
"dark_mode": "Mode fosc",
@@ -497,6 +497,8 @@
"overrides_secondary": "S'han detectat substitucions de configuració dinàmica",
"performance": "Rendiment",
"performance_secondary": "Opcions de rendiment de la targeta",
"profiles": "",
"profiles_secondary": "",
"timeline": "Cronologia",
"timeline_secondary": "Opcions de la cronologia d'esdeveniments",
"upgrade": "Upgrade",
+7 -5
View File
@@ -401,11 +401,6 @@
"editor_label": "Feature Options",
"media_chunk_size": "Media chunk size"
},
"profile": "Performance profile",
"profiles": {
"high": "High/full performance",
"low": "Low performance"
},
"style": {
"border_radius": "Curves",
"box_shadow": "Shadows",
@@ -413,6 +408,11 @@
},
"warning": "This card is in low profile mode so defaults have changed to optimize performance"
},
"profiles": {
"editor_label": "Configuration profiles",
"low-performance": "Low performance",
"scrubbing": "Video scrubbing"
},
"view": {
"camera_select": "View for newly selected cameras",
"dark_mode": "Dark mode",
@@ -497,6 +497,8 @@
"overrides_secondary": "Dynamic configuration overrides detected",
"performance": "Performance",
"performance_secondary": "Card performance options",
"profiles": "Configuration profiles",
"profiles_secondary": "Choose pre-configured sets of defaults",
"timeline": "Timeline",
"timeline_secondary": "Event timeline options",
"upgrade": "Upgrade",
+7 -5
View File
@@ -401,11 +401,6 @@
"editor_label": "Options de fonctionnalités",
"media_chunk_size": "Taille du morceau de média"
},
"profile": "Profil de performances",
"profiles": {
"high": "Performances élevées",
"low": "Performances faibles"
},
"style": {
"border_radius": "Courbes",
"box_shadow": "Ombres",
@@ -413,6 +408,11 @@
},
"warning": "Cette carte est en mode profil bas, les paramètres par défaut ont donc été modifiés pour optimiser les performances."
},
"profiles": {
"editor_label": "",
"low-performance": "",
"scrubbing": ""
},
"view": {
"camera_select": "Afficher les caméras nouvellement sélectionnées",
"dark_mode": "Mode sombre",
@@ -497,6 +497,8 @@
"overrides_secondary": "Remplacements de configuration dynamique détectés",
"performance": "Performance",
"performance_secondary": "Options de performances de la carte",
"profiles": "",
"profiles_secondary": "",
"timeline": "Chronologie",
"timeline_secondary": "Options de chronologie des événements",
"upgrade": "Mise à niveau",
+7 -5
View File
@@ -401,11 +401,6 @@
"editor_label": "Opzioni funzionalità",
"media_chunk_size": "Dimensione del blocco multimediale"
},
"profile": "Profilo delle prestazioni",
"profiles": {
"high": "Prestazioni alte",
"low": "Prestazioni basse"
},
"style": {
"border_radius": "Curve",
"box_shadow": "Ombre",
@@ -413,6 +408,11 @@
},
"warning": "Questa scheda è in modalità basso profilo, quindi le impostazioni predefinite sono state modificate per ottimizzare le prestazioni"
},
"profiles": {
"editor_label": "",
"low-performance": "",
"scrubbing": ""
},
"view": {
"camera_select": "Visualizza per le telecamere appena selezionate",
"dark_mode": "Tema scuro",
@@ -497,6 +497,8 @@
"overrides_secondary": "Rilevate sovrascritture della configurazione dinamica",
"performance": "",
"performance_secondary": "",
"profiles": "",
"profiles_secondary": "",
"timeline": "Timeline",
"timeline_secondary": "Opzioni della timeline degli eventi",
"upgrade": "Aggiornamento",
+7 -5
View File
@@ -401,11 +401,6 @@
"editor_label": "Opções de recursos",
"media_chunk_size": "Tamanho do bloco de mídia"
},
"profile": "Perfil de desempenho",
"profiles": {
"high": "Alto desempenho/completo",
"low": "Baixo desempenho"
},
"style": {
"border_radius": "Curvas",
"box_shadow": "Sombras",
@@ -413,6 +408,11 @@
},
"warning": "Este cartão está no modo de baixo desempenho, então os padrões foram alterados para otimizar o desempenho"
},
"profiles": {
"editor_label": "",
"low-performance": "",
"scrubbing": ""
},
"view": {
"camera_select": "Visualização de câmeras recém-selecionadas",
"dark_mode": "Modo escuro",
@@ -497,6 +497,8 @@
"overrides_secondary": "Substituições de configuração dinâmica detectadas",
"performance": "Desempenho",
"performance_secondary": "Opções de desempenho do cartão",
"profiles": "",
"profiles_secondary": "",
"timeline": "Linha do tempo",
"timeline_secondary": "Opções do evento da linha do tempo",
"upgrade": "Upgrade",
+7 -5
View File
@@ -401,11 +401,6 @@
"editor_label": "Editor de etiquetas",
"media_chunk_size": "Tamanho do ficheiro"
},
"profile": "Perfil",
"profiles": {
"high": "Alto",
"low": "Baixo"
},
"style": {
"border_radius": "Tamanho do bordo",
"box_shadow": "Caixa de Fundo",
@@ -413,6 +408,11 @@
},
"warning": "Avisos"
},
"profiles": {
"editor_label": "",
"low-performance": "",
"scrubbing": ""
},
"view": {
"camera_select": "Visualização de câmeras recém-selecionadas",
"dark_mode": "Modo escuro",
@@ -497,6 +497,8 @@
"overrides_secondary": "Substituições de configuração dinâmica detectadas",
"performance": "",
"performance_secondary": "",
"profiles": "",
"profiles_secondary": "",
"timeline": "Linha do tempo",
"timeline_secondary": "Opções do evento da linha do tempo",
"upgrade": "Actualização",