refactor: Clone context when a view is cloned (#2493)
This commit is contained in:
committed by
dermotduffy
parent
3f0d2ef14d
commit
2acec49b29
@@ -1,4 +1,3 @@
|
|||||||
import { cloneDeep } from 'lodash-es';
|
|
||||||
import { createNotificationFromText } from '../../components-lib/notification/factory';
|
import { createNotificationFromText } from '../../components-lib/notification/factory';
|
||||||
import { ConditionStateChange } from '../../conditions/types';
|
import { ConditionStateChange } from '../../conditions/types';
|
||||||
import { localize } from '../../localize/localize';
|
import { localize } from '../../localize/localize';
|
||||||
@@ -88,12 +87,10 @@ export class CallManager {
|
|||||||
|
|
||||||
// Store the previous view so it can be restored later. A call superseding
|
// Store the previous view so it can be restored later. A call superseding
|
||||||
// another inherits the earlier call's previous view -- the user never left
|
// another inherits the earlier call's previous view -- the user never left
|
||||||
// the call. `queryResults` are dropped (re-fetched fresh on restore);
|
// the call. `queryResults` are dropped (re-fetched fresh on restore).
|
||||||
// `context` is deep-cloned so the call engaging its own substream below
|
|
||||||
// cannot mutate the snapshot.
|
|
||||||
const previousView = existingCall
|
const previousView = existingCall
|
||||||
? existingCall.previousView
|
? existingCall.previousView
|
||||||
: view.evolve({ queryResults: null, context: cloneDeep(view.context) });
|
: view.evolve({ queryResults: null });
|
||||||
|
|
||||||
const needsNavigation = !view.is('live') || view.camera !== parentID;
|
const needsNavigation = !view.is('live') || view.camera !== parentID;
|
||||||
|
|
||||||
|
|||||||
@@ -383,8 +383,10 @@ export class AdvancedCameraCardViewerCarousel extends LitElement {
|
|||||||
// on media load, since the media may or may not have been loaded at
|
// on media load, since the media may or may not have been loaded at
|
||||||
// this point).
|
// this point).
|
||||||
if (
|
if (
|
||||||
this.viewManagerEpoch?.manager.getView()?.context?.mediaViewer !==
|
this.viewManagerEpoch?.manager
|
||||||
this.viewManagerEpoch?.oldView?.context?.mediaViewer
|
.getView()
|
||||||
|
?.context?.mediaViewer?.seek?.getTime() !==
|
||||||
|
this.viewManagerEpoch?.oldView?.context?.mediaViewer?.seek?.getTime()
|
||||||
) {
|
) {
|
||||||
this._seekHandler();
|
this._seekHandler();
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
import { merge } from 'lodash-es';
|
import { cloneDeep, merge } from 'lodash-es';
|
||||||
import { ViewContext } from 'view';
|
import { ViewContext } from 'view';
|
||||||
import { AdvancedCameraCardView } from '../config/schema/common/const';
|
import { AdvancedCameraCardView } from '../config/schema/common/const';
|
||||||
import { ViewDisplayMode } from '../config/schema/common/display';
|
import { ViewDisplayMode } from '../config/schema/common/display';
|
||||||
@@ -95,7 +95,7 @@ export class View {
|
|||||||
camera: this.camera,
|
camera: this.camera,
|
||||||
query: this.query?.clone() ?? null,
|
query: this.query?.clone() ?? null,
|
||||||
queryResults: this.queryResults?.clone() ?? null,
|
queryResults: this.queryResults?.clone() ?? null,
|
||||||
context: this.context,
|
context: cloneDeep(this.context),
|
||||||
displayMode: this.displayMode,
|
displayMode: this.displayMode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ export class View {
|
|||||||
params.queryResults !== undefined
|
params.queryResults !== undefined
|
||||||
? params.queryResults
|
? params.queryResults
|
||||||
: this.queryResults?.clone() ?? null,
|
: this.queryResults?.clone() ?? null,
|
||||||
context: params.context !== undefined ? params.context : this.context,
|
context: params.context !== undefined ? params.context : cloneDeep(this.context),
|
||||||
displayMode:
|
displayMode:
|
||||||
params.displayMode !== undefined ? params.displayMode : this.displayMode,
|
params.displayMode !== undefined ? params.displayMode : this.displayMode,
|
||||||
});
|
});
|
||||||
|
|||||||
+20
-1
@@ -87,7 +87,10 @@ describe('View Basics', () => {
|
|||||||
|
|
||||||
expect(evolved.view).toBe(view.view);
|
expect(evolved.view).toBe(view.view);
|
||||||
expect(evolved.camera).toBe(view.camera);
|
expect(evolved.camera).toBe(view.camera);
|
||||||
expect(evolved.context).toBe(view.context);
|
|
||||||
|
// Context is deep-cloned if not set, so the evolved view owns it.
|
||||||
|
expect(evolved.context).not.toBe(view.context);
|
||||||
|
expect(evolved.context).toEqual(view.context);
|
||||||
|
|
||||||
// Query and QueryResults are cloned if not set.
|
// Query and QueryResults are cloned if not set.
|
||||||
expect(evolved.query).not.toBe(view.query);
|
expect(evolved.query).not.toBe(view.query);
|
||||||
@@ -96,6 +99,22 @@ describe('View Basics', () => {
|
|||||||
expect(evolved.queryResults).toEqual(view.queryResults);
|
expect(evolved.queryResults).toEqual(view.queryResults);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should isolate inherited context from mutation on clone and evolve', () => {
|
||||||
|
const view = createView({
|
||||||
|
view: 'live',
|
||||||
|
camera: 'camera-1',
|
||||||
|
context: { live: { overrides: new Map([['camera-1', 'sub-1']]) } },
|
||||||
|
});
|
||||||
|
|
||||||
|
const cloned = view.clone();
|
||||||
|
const evolved = view.evolve({});
|
||||||
|
|
||||||
|
cloned.context?.live?.overrides?.set('camera-1', 'mutated-clone');
|
||||||
|
evolved.context?.live?.overrides?.delete('camera-1');
|
||||||
|
|
||||||
|
expect(view.context?.live?.overrides?.get('camera-1')).toBe('sub-1');
|
||||||
|
});
|
||||||
|
|
||||||
it('should not clone query and queryResults with nothing set', () => {
|
it('should not clone query and queryResults with nothing set', () => {
|
||||||
const view = createView();
|
const view = createView();
|
||||||
const evolved = view.evolve({});
|
const evolved = view.evolve({});
|
||||||
|
|||||||
Reference in New Issue
Block a user