@vived/host 4.5.3 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Apps/Entities/AppEntity.js +29 -3
- package/dist/cjs/Apps/Entities/AppEntity.js.map +1 -1
- package/dist/cjs/Apps/PMs/AppPM.js +44 -3
- package/dist/cjs/Apps/PMs/AppPM.js.map +1 -1
- package/dist/cjs/Assets/Adapters/assetFileAdapter.js +45 -0
- package/dist/cjs/Assets/Adapters/assetFileAdapter.js.map +1 -0
- package/dist/cjs/Assets/Adapters/index.js +1 -0
- package/dist/cjs/Assets/Adapters/index.js.map +1 -1
- package/dist/cjs/Assets/Factories/setupAssetsForSandbox.js +1 -0
- package/dist/cjs/Assets/Factories/setupAssetsForSandbox.js.map +1 -1
- package/dist/cjs/Assets/Mocks/AssetFilePMMock.js +24 -0
- package/dist/cjs/Assets/Mocks/AssetFilePMMock.js.map +1 -0
- package/dist/cjs/Assets/Mocks/index.js +1 -0
- package/dist/cjs/Assets/Mocks/index.js.map +1 -1
- package/dist/cjs/Assets/PMs/AssetFilePM.js +134 -0
- package/dist/cjs/Assets/PMs/AssetFilePM.js.map +1 -0
- package/dist/cjs/Assets/PMs/index.js +1 -0
- package/dist/cjs/Assets/PMs/index.js.map +1 -1
- package/dist/cjs/StateMachine/Entities/HostEditingStateEntity.js +62 -0
- package/dist/cjs/StateMachine/Entities/HostEditingStateEntity.js.map +1 -1
- package/dist/cjs/StateMachine/Entities/HostStateEntity.js +91 -2
- package/dist/cjs/StateMachine/Entities/HostStateEntity.js.map +1 -1
- package/dist/cjs/StateMachine/Entities/HostStateMachine.js +127 -0
- package/dist/cjs/StateMachine/Entities/HostStateMachine.js.map +1 -1
- package/dist/cjs/StateMachine/Mocks/MockHostStateEntity.js +1 -0
- package/dist/cjs/StateMachine/Mocks/MockHostStateEntity.js.map +1 -1
- package/dist/cjs/StateMachine/PMs/HostStatePM.js +6 -2
- package/dist/cjs/StateMachine/PMs/HostStatePM.js.map +1 -1
- package/dist/cjs/StateMachine/UCs/DeleteStateUC.js +1 -1
- package/dist/cjs/StateMachine/UCs/DeleteStateUC.js.map +1 -1
- package/dist/cjs/StateMachine/UCs/DuplicateStateUC.js +1 -1
- package/dist/cjs/StateMachine/UCs/DuplicateStateUC.js.map +1 -1
- package/dist/cjs/StateMachine/UCs/SavePersistentStates.js.map +1 -1
- package/dist/esm/Apps/Entities/AppEntity.js +30 -4
- package/dist/esm/Apps/Entities/AppEntity.js.map +1 -1
- package/dist/esm/Apps/PMs/AppPM.js +44 -3
- package/dist/esm/Apps/PMs/AppPM.js.map +1 -1
- package/dist/esm/Assets/Adapters/assetFileAdapter.js +42 -0
- package/dist/esm/Assets/Adapters/assetFileAdapter.js.map +1 -0
- package/dist/esm/Assets/Adapters/index.js +1 -0
- package/dist/esm/Assets/Adapters/index.js.map +1 -1
- package/dist/esm/Assets/Factories/setupAssetsForSandbox.js +2 -1
- package/dist/esm/Assets/Factories/setupAssetsForSandbox.js.map +1 -1
- package/dist/esm/Assets/Mocks/AssetFilePMMock.js +20 -0
- package/dist/esm/Assets/Mocks/AssetFilePMMock.js.map +1 -0
- package/dist/esm/Assets/Mocks/index.js +1 -0
- package/dist/esm/Assets/Mocks/index.js.map +1 -1
- package/dist/esm/Assets/PMs/AssetFilePM.js +129 -0
- package/dist/esm/Assets/PMs/AssetFilePM.js.map +1 -0
- package/dist/esm/Assets/PMs/index.js +1 -0
- package/dist/esm/Assets/PMs/index.js.map +1 -1
- package/dist/esm/StateMachine/Entities/HostEditingStateEntity.js +62 -0
- package/dist/esm/StateMachine/Entities/HostEditingStateEntity.js.map +1 -1
- package/dist/esm/StateMachine/Entities/HostStateEntity.js +90 -1
- package/dist/esm/StateMachine/Entities/HostStateEntity.js.map +1 -1
- package/dist/esm/StateMachine/Entities/HostStateMachine.js +127 -0
- package/dist/esm/StateMachine/Entities/HostStateMachine.js.map +1 -1
- package/dist/esm/StateMachine/Mocks/MockHostStateEntity.js +2 -1
- package/dist/esm/StateMachine/Mocks/MockHostStateEntity.js.map +1 -1
- package/dist/esm/StateMachine/PMs/HostStatePM.js +7 -3
- package/dist/esm/StateMachine/PMs/HostStatePM.js.map +1 -1
- package/dist/esm/StateMachine/UCs/DeleteStateUC.js +1 -1
- package/dist/esm/StateMachine/UCs/DeleteStateUC.js.map +1 -1
- package/dist/esm/StateMachine/UCs/DuplicateStateUC.js +1 -1
- package/dist/esm/StateMachine/UCs/DuplicateStateUC.js.map +1 -1
- package/dist/esm/StateMachine/UCs/SavePersistentStates.js.map +1 -1
- package/dist/types/Apps/Entities/AppEntity.d.ts +1 -0
- package/dist/types/Apps/Entities/AppEntity.d.ts.map +1 -1
- package/dist/types/Apps/PMs/AppPM.d.ts +2 -0
- package/dist/types/Apps/PMs/AppPM.d.ts.map +1 -1
- package/dist/types/Assets/Adapters/assetFileAdapter.d.ts +8 -0
- package/dist/types/Assets/Adapters/assetFileAdapter.d.ts.map +1 -0
- package/dist/types/Assets/Adapters/index.d.ts +1 -0
- package/dist/types/Assets/Adapters/index.d.ts.map +1 -1
- package/dist/types/Assets/Factories/setupAssetsForSandbox.d.ts.map +1 -1
- package/dist/types/Assets/Mocks/AssetFilePMMock.d.ts +19 -0
- package/dist/types/Assets/Mocks/AssetFilePMMock.d.ts.map +1 -0
- package/dist/types/Assets/Mocks/index.d.ts +1 -0
- package/dist/types/Assets/Mocks/index.d.ts.map +1 -1
- package/dist/types/Assets/PMs/AssetFilePM.d.ts +51 -0
- package/dist/types/Assets/PMs/AssetFilePM.d.ts.map +1 -0
- package/dist/types/Assets/PMs/index.d.ts +1 -0
- package/dist/types/Assets/PMs/index.d.ts.map +1 -1
- package/dist/types/StateMachine/Entities/HostEditingStateEntity.d.ts +42 -0
- package/dist/types/StateMachine/Entities/HostEditingStateEntity.d.ts.map +1 -1
- package/dist/types/StateMachine/Entities/HostStateEntity.d.ts +72 -5
- package/dist/types/StateMachine/Entities/HostStateEntity.d.ts.map +1 -1
- package/dist/types/StateMachine/Entities/HostStateMachine.d.ts +77 -0
- package/dist/types/StateMachine/Entities/HostStateMachine.d.ts.map +1 -1
- package/dist/types/StateMachine/Mocks/MockHostStateEntity.d.ts +2 -1
- package/dist/types/StateMachine/Mocks/MockHostStateEntity.d.ts.map +1 -1
- package/dist/types/StateMachine/PMs/HostStatePM.d.ts +2 -0
- package/dist/types/StateMachine/PMs/HostStatePM.d.ts.map +1 -1
- package/dist/types/StateMachine/UCs/SavePersistentStates.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/Assets/Mocks/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC","sourcesContent":["export * from \"./AppAssetListPMMock\";\r\nexport * from \"./AssetPMMock\";\r\nexport * from \"./EditingAppAssetPMMock\";\r\nexport * from \"./MockArchiveAsset\";\r\nexport * from \"./MockDeleteAssetUC\";\r\nexport * from \"./MockDownloadAssetFileUC\";\r\nexport * from \"./MockEditAppAssetUC\";\r\nexport * from \"./MockGetAppAssetsUC\";\r\nexport * from \"./MockGetAssetBlobURLUC\";\r\nexport * from \"./MockGetAssetFileUC\";\r\nexport * from \"./MockGetAssetUC\";\r\nexport * from \"./MockNewAppAsset\";\r\nexport * from \"./MockNewAssetUC\";\r\nexport * from \"./MockPrefetchAssets\";\r\nexport * from \"./MockUpdateAssetFileUC\";\r\nexport * from \"./MockUpdateAppAssetMetaUC\";\r\nexport * from \"./ShowArchivedAppAssetPMMock\";\r\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/Assets/Mocks/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC","sourcesContent":["export * from \"./AppAssetListPMMock\";\r\nexport * from \"./AssetPMMock\";\r\nexport * from \"./AssetFilePMMock\";\r\nexport * from \"./EditingAppAssetPMMock\";\r\nexport * from \"./MockArchiveAsset\";\r\nexport * from \"./MockDeleteAssetUC\";\r\nexport * from \"./MockDownloadAssetFileUC\";\r\nexport * from \"./MockEditAppAssetUC\";\r\nexport * from \"./MockGetAppAssetsUC\";\r\nexport * from \"./MockGetAssetBlobURLUC\";\r\nexport * from \"./MockGetAssetFileUC\";\r\nexport * from \"./MockGetAssetUC\";\r\nexport * from \"./MockNewAppAsset\";\r\nexport * from \"./MockNewAssetUC\";\r\nexport * from \"./MockPrefetchAssets\";\r\nexport * from \"./MockUpdateAssetFileUC\";\r\nexport * from \"./MockUpdateAppAssetMetaUC\";\r\nexport * from \"./ShowArchivedAppAssetPMMock\";\r\n"]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// filepath: c:\Users\amosp\Documents\WebGL\vivedlearning_host\src\Assets\PMs\AssetFilePM.ts
|
|
2
|
+
import { AppObjectPM } from "@vived/core";
|
|
3
|
+
import { AssetEntity } from "../Entities/AssetEntity";
|
|
4
|
+
/**
|
|
5
|
+
* Default empty AssetFileVM for initialization
|
|
6
|
+
*/
|
|
7
|
+
export const defaultAssetFileVM = {
|
|
8
|
+
blobURL: undefined,
|
|
9
|
+
isFetchingFile: false,
|
|
10
|
+
fileHasBeenFetched: false,
|
|
11
|
+
fetchError: undefined
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Presentation Manager for Asset file status
|
|
15
|
+
*
|
|
16
|
+
* The AssetFilePM is responsible for:
|
|
17
|
+
* - Converting the file-related properties of AssetEntity into a view-friendly format (AssetFileVM)
|
|
18
|
+
* - Notifying the view when asset file status changes
|
|
19
|
+
* - Providing comparison utilities for view models
|
|
20
|
+
*
|
|
21
|
+
* Usage:
|
|
22
|
+
* 1. Retrieve an instance with `AssetFilePM.getByID(assetId, appObjects)`
|
|
23
|
+
* 2. Subscribe to view updates with `pm.addView(callback)`
|
|
24
|
+
* 3. Access current view data with `pm.lastVM`
|
|
25
|
+
*/
|
|
26
|
+
export class AssetFilePM extends AppObjectPM {
|
|
27
|
+
/**
|
|
28
|
+
* Retrieves an AssetFilePM instance for a specific asset by ID
|
|
29
|
+
*
|
|
30
|
+
* @param assetID - The unique identifier of the asset
|
|
31
|
+
* @param appObjects - The repository of app objects
|
|
32
|
+
* @returns The AssetFilePM instance or undefined if not found
|
|
33
|
+
*/
|
|
34
|
+
static getByID(assetID, appObjects) {
|
|
35
|
+
const appObject = appObjects.get(assetID);
|
|
36
|
+
if (!appObject) {
|
|
37
|
+
appObjects.submitWarning("AssetFilePM.getByID", "Unable to find app object by ID " + assetID);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const pm = appObject.getComponent(AssetFilePM.type);
|
|
41
|
+
if (!pm) {
|
|
42
|
+
appObjects.submitWarning("AssetFilePM.getByID", "App Object does not have a AssetFilePM");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
return pm;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
AssetFilePM.type = "AssetFilePM";
|
|
49
|
+
/**
|
|
50
|
+
* Creates a new AssetFilePM instance
|
|
51
|
+
*
|
|
52
|
+
* @param appObject - The app object to associate with this PM
|
|
53
|
+
* @returns A new AssetFilePM instance
|
|
54
|
+
*/
|
|
55
|
+
export function makeAssetFilePM(appObject) {
|
|
56
|
+
return new AssetFilePMImp(appObject);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Implementation of the AssetFilePM abstract class
|
|
60
|
+
* Handles the connection between AssetEntity file properties and view
|
|
61
|
+
*/
|
|
62
|
+
class AssetFilePMImp extends AssetFilePM {
|
|
63
|
+
get asset() {
|
|
64
|
+
return this.getCachedLocalComponent(AssetEntity.type);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Compares two AssetFileVM instances for equality
|
|
68
|
+
* Used to determine if the view needs to update
|
|
69
|
+
*
|
|
70
|
+
* @param a - First AssetFileVM to compare
|
|
71
|
+
* @param b - Second AssetFileVM to compare
|
|
72
|
+
* @returns True if view models are equal, false otherwise
|
|
73
|
+
*/
|
|
74
|
+
vmsAreEqual(a, b) {
|
|
75
|
+
if (a.blobURL !== b.blobURL)
|
|
76
|
+
return false;
|
|
77
|
+
if (a.isFetchingFile !== b.isFetchingFile)
|
|
78
|
+
return false;
|
|
79
|
+
if (a.fileHasBeenFetched !== b.fileHasBeenFetched)
|
|
80
|
+
return false;
|
|
81
|
+
// Handle errors comparison (both undefined, or same message)
|
|
82
|
+
if (a.fetchError !== b.fetchError) {
|
|
83
|
+
if (a.fetchError === undefined && b.fetchError !== undefined)
|
|
84
|
+
return false;
|
|
85
|
+
if (a.fetchError !== undefined && b.fetchError === undefined)
|
|
86
|
+
return false;
|
|
87
|
+
if (a.fetchError !== undefined &&
|
|
88
|
+
b.fetchError !== undefined &&
|
|
89
|
+
a.fetchError.message !== b.fetchError.message)
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Cleans up resources and removes observers when the PM is disposed
|
|
96
|
+
*/
|
|
97
|
+
dispose() {
|
|
98
|
+
if (this.asset) {
|
|
99
|
+
this.asset.removeChangeObserver(this.onAssetChange);
|
|
100
|
+
}
|
|
101
|
+
super.dispose();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Creates a new AssetFilePMImp instance
|
|
105
|
+
*
|
|
106
|
+
* @param appObject - The app object to associate with this PM
|
|
107
|
+
*/
|
|
108
|
+
constructor(appObject) {
|
|
109
|
+
super(appObject, AssetFilePM.type);
|
|
110
|
+
/**
|
|
111
|
+
* Observer callback that updates the view model when the entity changes
|
|
112
|
+
* Transforms entity data into view model format
|
|
113
|
+
*/
|
|
114
|
+
this.onAssetChange = () => {
|
|
115
|
+
if (!this.asset)
|
|
116
|
+
return;
|
|
117
|
+
const vm = {
|
|
118
|
+
blobURL: this.asset.blobURL,
|
|
119
|
+
isFetchingFile: this.asset.isFetchingFile,
|
|
120
|
+
fileHasBeenFetched: this.asset.fileHasBeenFetched,
|
|
121
|
+
fetchError: this.asset.fetchError
|
|
122
|
+
};
|
|
123
|
+
this.doUpdateView(vm);
|
|
124
|
+
};
|
|
125
|
+
this.asset?.addChangeObserver(this.onAssetChange);
|
|
126
|
+
this.onAssetChange();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=AssetFilePM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetFilePM.js","sourceRoot":"","sources":["../../../../src/Assets/PMs/AssetFilePM.ts"],"names":[],"mappings":"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","sourcesContent":["// filepath: c:\\Users\\amosp\\Documents\\WebGL\\vivedlearning_host\\src\\Assets\\PMs\\AssetFilePM.ts\r\nimport { AppObject, AppObjectPM, AppObjectRepo } from \"@vived/core\";\r\nimport { AssetEntity } from \"../Entities/AssetEntity\";\r\n\r\n/**\r\n * View Model for Asset file information\r\n * Represents the data needed by the view to display asset file status\r\n */\r\nexport interface AssetFileVM {\r\n /** URL to the asset's file blob for direct access */\r\n blobURL: string | undefined;\r\n /** Whether the asset file is currently being fetched */\r\n isFetchingFile: boolean;\r\n /** Whether the asset file has been successfully fetched */\r\n fileHasBeenFetched: boolean;\r\n /** Error that occurred during file fetching, if any */\r\n fetchError: Error | undefined;\r\n}\r\n\r\n/**\r\n * Default empty AssetFileVM for initialization\r\n */\r\nexport const defaultAssetFileVM: AssetFileVM = {\r\n blobURL: undefined,\r\n isFetchingFile: false,\r\n fileHasBeenFetched: false,\r\n fetchError: undefined\r\n};\r\n\r\n/**\r\n * Presentation Manager for Asset file status\r\n *\r\n * The AssetFilePM is responsible for:\r\n * - Converting the file-related properties of AssetEntity into a view-friendly format (AssetFileVM)\r\n * - Notifying the view when asset file status changes\r\n * - Providing comparison utilities for view models\r\n *\r\n * Usage:\r\n * 1. Retrieve an instance with `AssetFilePM.getByID(assetId, appObjects)`\r\n * 2. Subscribe to view updates with `pm.addView(callback)`\r\n * 3. Access current view data with `pm.lastVM`\r\n */\r\nexport abstract class AssetFilePM extends AppObjectPM<AssetFileVM> {\r\n static type = \"AssetFilePM\";\r\n\r\n /**\r\n * Retrieves an AssetFilePM instance for a specific asset by ID\r\n *\r\n * @param assetID - The unique identifier of the asset\r\n * @param appObjects - The repository of app objects\r\n * @returns The AssetFilePM instance or undefined if not found\r\n */\r\n static getByID(\r\n assetID: string,\r\n appObjects: AppObjectRepo\r\n ): AssetFilePM | undefined {\r\n const appObject = appObjects.get(assetID);\r\n if (!appObject) {\r\n appObjects.submitWarning(\r\n \"AssetFilePM.getByID\",\r\n \"Unable to find app object by ID \" + assetID\r\n );\r\n return;\r\n }\r\n\r\n const pm = appObject.getComponent<AssetFilePM>(AssetFilePM.type);\r\n if (!pm) {\r\n appObjects.submitWarning(\r\n \"AssetFilePM.getByID\",\r\n \"App Object does not have a AssetFilePM\"\r\n );\r\n return;\r\n }\r\n return pm;\r\n }\r\n}\r\n\r\n/**\r\n * Creates a new AssetFilePM instance\r\n *\r\n * @param appObject - The app object to associate with this PM\r\n * @returns A new AssetFilePM instance\r\n */\r\nexport function makeAssetFilePM(appObject: AppObject): AssetFilePM {\r\n return new AssetFilePMImp(appObject);\r\n}\r\n\r\n/**\r\n * Implementation of the AssetFilePM abstract class\r\n * Handles the connection between AssetEntity file properties and view\r\n */\r\nclass AssetFilePMImp extends AssetFilePM {\r\n private get asset() {\r\n\t\treturn this.getCachedLocalComponent<AssetEntity>(AssetEntity.type);\r\n\t}\r\n\r\n /**\r\n * Compares two AssetFileVM instances for equality\r\n * Used to determine if the view needs to update\r\n *\r\n * @param a - First AssetFileVM to compare\r\n * @param b - Second AssetFileVM to compare\r\n * @returns True if view models are equal, false otherwise\r\n */\r\n vmsAreEqual(a: AssetFileVM, b: AssetFileVM): boolean {\r\n if (a.blobURL !== b.blobURL) return false;\r\n if (a.isFetchingFile !== b.isFetchingFile) return false;\r\n if (a.fileHasBeenFetched !== b.fileHasBeenFetched) return false;\r\n\r\n // Handle errors comparison (both undefined, or same message)\r\n if (a.fetchError !== b.fetchError) {\r\n if (a.fetchError === undefined && b.fetchError !== undefined)\r\n return false;\r\n if (a.fetchError !== undefined && b.fetchError === undefined)\r\n return false;\r\n if (\r\n a.fetchError !== undefined &&\r\n b.fetchError !== undefined &&\r\n a.fetchError.message !== b.fetchError.message\r\n )\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Observer callback that updates the view model when the entity changes\r\n * Transforms entity data into view model format\r\n */\r\n private onAssetChange = () => {\r\n if (!this.asset) return;\r\n\r\n const vm: AssetFileVM = {\r\n blobURL: this.asset.blobURL,\r\n isFetchingFile: this.asset.isFetchingFile,\r\n fileHasBeenFetched: this.asset.fileHasBeenFetched,\r\n fetchError: this.asset.fetchError\r\n };\r\n\r\n this.doUpdateView(vm);\r\n };\r\n\r\n /**\r\n * Cleans up resources and removes observers when the PM is disposed\r\n */\r\n dispose(): void {\r\n if (this.asset) {\r\n this.asset.removeChangeObserver(this.onAssetChange);\r\n }\r\n super.dispose();\r\n }\r\n\r\n /**\r\n * Creates a new AssetFilePMImp instance\r\n *\r\n * @param appObject - The app object to associate with this PM\r\n */\r\n constructor(appObject: AppObject) {\r\n super(appObject, AssetFilePM.type);\r\n\r\n this.asset?.addChangeObserver(this.onAssetChange);\r\n this.onAssetChange();\r\n }\r\n}\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/Assets/PMs/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC","sourcesContent":["export * from \"./AppAssetListPM\";\r\nexport * from \"./AssetPM\";\r\nexport * from \"./EditingAppAssetPM\";\r\nexport * from \"./ShowArchivedAppAssetPM\"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/Assets/PMs/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC","sourcesContent":["export * from \"./AppAssetListPM\";\r\nexport * from \"./AssetPM\";\r\nexport * from \"./AssetFilePM\";\r\nexport * from \"./EditingAppAssetPM\";\r\nexport * from \"./ShowArchivedAppAssetPM\";\r\n"]}
|
|
@@ -1,15 +1,39 @@
|
|
|
1
1
|
import { MemoizedBoolean } from "@vived/core";
|
|
2
2
|
import { getSingletonComponent, AppObjectEntity } from "@vived/core";
|
|
3
3
|
import { HostStateMachine } from "./HostStateMachine";
|
|
4
|
+
/**
|
|
5
|
+
* HostEditingStateEntity handles the editing workflow for state entities.
|
|
6
|
+
*
|
|
7
|
+
* This singleton component manages the process of creating new states or editing
|
|
8
|
+
* existing states in the host state machine. It tracks changes made during editing,
|
|
9
|
+
* maintains the original state for cancellation/rollback, and provides validation.
|
|
10
|
+
*
|
|
11
|
+
* The component implements a standard editing pattern:
|
|
12
|
+
* 1. Start editing (startEditing) or create new (startNewState)
|
|
13
|
+
* 2. Make changes to the editingState directly
|
|
14
|
+
* 3. Complete with either finishEditing (commit) or cancelEditState (rollback)
|
|
15
|
+
*
|
|
16
|
+
* This entity is a critical part of the state authoring workflow and works closely
|
|
17
|
+
* with HostStateMachine and HostStateEntity.
|
|
18
|
+
*/
|
|
4
19
|
export class HostEditingStateEntity extends AppObjectEntity {
|
|
5
20
|
static get(appObjects) {
|
|
6
21
|
return getSingletonComponent(HostEditingStateEntity.type, appObjects);
|
|
7
22
|
}
|
|
8
23
|
}
|
|
9
24
|
HostEditingStateEntity.type = "HostEditingStateEntity";
|
|
25
|
+
/**
|
|
26
|
+
* Factory function for creating a HostEditingStateEntity instance
|
|
27
|
+
* @param appObject The AppObject to associate with this entity
|
|
28
|
+
* @returns A new HostEditingStateEntity instance
|
|
29
|
+
*/
|
|
10
30
|
export function makeHostEditingStateEntity(appObject) {
|
|
11
31
|
return new HostEditingStateEntityImp(appObject);
|
|
12
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Implementation of the HostEditingStateEntity abstract class
|
|
35
|
+
* Manages the state editing workflow and tracks changes
|
|
36
|
+
*/
|
|
13
37
|
class HostEditingStateEntityImp extends HostEditingStateEntity {
|
|
14
38
|
get editingState() {
|
|
15
39
|
return this._editingState;
|
|
@@ -29,6 +53,10 @@ class HostEditingStateEntityImp extends HostEditingStateEntity {
|
|
|
29
53
|
this._stateValidationMessage = val;
|
|
30
54
|
this.notifyOnChange();
|
|
31
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Reference to the HostStateMachine singleton
|
|
58
|
+
* Used for creating and managing states
|
|
59
|
+
*/
|
|
32
60
|
get hostStateMachine() {
|
|
33
61
|
return this.getCachedSingleton(HostStateMachine.type);
|
|
34
62
|
}
|
|
@@ -38,7 +66,16 @@ class HostEditingStateEntityImp extends HostEditingStateEntity {
|
|
|
38
66
|
constructor(appObject) {
|
|
39
67
|
super(appObject, HostEditingStateEntity.type);
|
|
40
68
|
this._isNewState = false;
|
|
69
|
+
/**
|
|
70
|
+
* Tracks whether changes have been made to the state being edited
|
|
71
|
+
* Uses a memoized value to efficiently notify observers only when value changes
|
|
72
|
+
*/
|
|
41
73
|
this.memoizedSomethingHasChanged = new MemoizedBoolean(false, this.notifyOnChange);
|
|
74
|
+
/**
|
|
75
|
+
* Compares the current state with the original state to detect changes
|
|
76
|
+
* Performs deep comparison of all relevant properties
|
|
77
|
+
* @returns true if changes were detected, false otherwise
|
|
78
|
+
*/
|
|
42
79
|
this.checkForChange = () => {
|
|
43
80
|
if (!this._editingState)
|
|
44
81
|
return false;
|
|
@@ -66,9 +103,17 @@ class HostEditingStateEntityImp extends HostEditingStateEntity {
|
|
|
66
103
|
return true;
|
|
67
104
|
return false;
|
|
68
105
|
};
|
|
106
|
+
/**
|
|
107
|
+
* Observer callback for state changes
|
|
108
|
+
* Updates the somethingHasChanged flag when the state being edited changes
|
|
109
|
+
*/
|
|
69
110
|
this.onStateEntityChange = () => {
|
|
70
111
|
this.memoizedSomethingHasChanged.val = this.checkForChange();
|
|
71
112
|
};
|
|
113
|
+
/**
|
|
114
|
+
* Creates a new state and begins editing it
|
|
115
|
+
* @returns The newly created state entity or undefined if creation failed
|
|
116
|
+
*/
|
|
72
117
|
this.startNewState = () => {
|
|
73
118
|
if (!this.hostStateMachine)
|
|
74
119
|
return;
|
|
@@ -79,12 +124,21 @@ class HostEditingStateEntityImp extends HostEditingStateEntity {
|
|
|
79
124
|
this.memoizedSomethingHasChanged.val = true;
|
|
80
125
|
return this._editingState;
|
|
81
126
|
};
|
|
127
|
+
/**
|
|
128
|
+
* Begins editing an existing state
|
|
129
|
+
* @param state The state entity to edit
|
|
130
|
+
*/
|
|
82
131
|
this.startEditing = (state) => {
|
|
83
132
|
this._editingState = state;
|
|
84
133
|
this.originalStateData = state.getDTO();
|
|
85
134
|
this._editingState.addChangeObserver(this.onStateEntityChange);
|
|
86
135
|
this.notifyOnChange();
|
|
87
136
|
};
|
|
137
|
+
/**
|
|
138
|
+
* Cancels editing and reverts changes
|
|
139
|
+
* For new states, removes them from the state machine
|
|
140
|
+
* For existing states, restores the original values
|
|
141
|
+
*/
|
|
88
142
|
this.cancelEditState = () => {
|
|
89
143
|
if (!this._editingState)
|
|
90
144
|
return;
|
|
@@ -96,9 +150,17 @@ class HostEditingStateEntityImp extends HostEditingStateEntity {
|
|
|
96
150
|
}
|
|
97
151
|
this.resetInternalState();
|
|
98
152
|
};
|
|
153
|
+
/**
|
|
154
|
+
* Completes editing, keeping all changes
|
|
155
|
+
* Simply cleans up the internal state without reverting changes
|
|
156
|
+
*/
|
|
99
157
|
this.finishEditing = () => {
|
|
100
158
|
this.resetInternalState();
|
|
101
159
|
};
|
|
160
|
+
/**
|
|
161
|
+
* Resets the internal state after editing is complete
|
|
162
|
+
* Cleans up observers and notifies clients of the change
|
|
163
|
+
*/
|
|
102
164
|
this.resetInternalState = () => {
|
|
103
165
|
if (!this._editingState)
|
|
104
166
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HostEditingStateEntity.js","sourceRoot":"","sources":["../../../../src/StateMachine/Entities/HostEditingStateEntity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,qBAAqB,EAErB,eAAe,EAEhB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,OAAgB,sBAAuB,SAAQ,eAAe;IAclE,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,qBAAqB,CAC1B,sBAAsB,CAAC,IAAI,EAC3B,UAAU,CACX,CAAC;IACJ,CAAC;;AAlBM,2BAAI,GAAG,wBAAwB,CAAC;AAqBzC,MAAM,UAAU,0BAA0B,CACxC,SAAoB;IAEpB,OAAO,IAAI,yBAAyB,CAAC,SAAS,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,yBAA0B,SAAQ,sBAAsB;IAI5D,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,aAAa,KAAK,SAAS,CAAC;IAC1C,CAAC;IAGD,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAGD,IAAI,sBAAsB;QACxB,OAAO,IAAI,CAAC,uBAAuB,CAAC;IACtC,CAAC;IACD,IAAI,sBAAsB,CAAC,GAAuB;QAChD,IAAI,IAAI,CAAC,uBAAuB,KAAK,GAAG;YAAE,OAAO;QAEjD,IAAI,CAAC,uBAAuB,GAAG,GAAG,CAAC;QACnC,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAED,IAAY,gBAAgB;QAC1B,OAAO,IAAI,CAAC,kBAAkB,CAAmB,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC;IAMD,IAAI,mBAAmB;QACrB,OAAO,IAAI,CAAC,2BAA2B,CAAC,GAAG,CAAC;IAC9C,CAAC;IAsFD,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAjHxC,gBAAW,GAAG,KAAK,CAAC;QAoBpB,gCAA2B,GAAG,IAAI,eAAe,CACvD,KAAK,EACL,IAAI,CAAC,cAAc,CACpB,CAAC;QAKM,mBAAc,GAAG,GAAG,EAAE;YAC5B,IAAI,CAAC,IAAI,CAAC,aAAa;gBAAE,OAAO,KAAK,CAAC;YACtC,IAAI,CAAC,IAAI,CAAC,iBAAiB;gBAAE,OAAO,IAAI,CAAC;YAEzC,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,IAAI,CAAC,iBAAiB,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAC;YAEzE,IAAI,IAAI,CAAC,aAAa,CAAC,gBAAgB,KAAK,IAAI,CAAC,iBAAiB,CAAC,QAAQ;gBACzE,OAAO,IAAI,CAAC;YAEd,IACE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,MAAM;gBAEzE,OAAO,IAAI,CAAC;YACd,IAAI,iBAAiB,GAAG,KAAK,CAAC;YAC9B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,cAAc,EAAE,CAAC,EAAE,EAAE;gBACtD,MAAM,eAAe,GAAG,IAAI,CAAC,iBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC1D,IAAI,eAAe,KAAK,cAAc,EAAE,CAAC;oBACvC,iBAAiB,GAAG,IAAI,CAAC;gBAC3B,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,iBAAiB,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;YACvE,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YACxE,IAAI,iBAAiB,KAAK,YAAY;gBAAE,OAAO,IAAI,CAAC;YAEpD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC;QAEM,wBAAmB,GAAG,GAAS,EAAE;YACvC,IAAI,CAAC,2BAA2B,CAAC,GAAG,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QAC/D,CAAC,CAAC;QAEF,kBAAa,GAAG,GAAgC,EAAE;YAChD,IAAI,CAAC,IAAI,CAAC,gBAAgB;gBAAE,OAAO;YAEnC,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC;YACnC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC;YAC5D,IAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAC/D,IAAI,CAAC,2BAA2B,CAAC,GAAG,GAAG,IAAI,CAAC;YAE5C,OAAO,IAAI,CAAC,aAAa,CAAC;QAC5B,CAAC,CAAC;QAEF,iBAAY,GAAG,CAAC,KAAsB,EAAQ,EAAE;YAC9C,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;YAE3B,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YACxC,IAAI,CAAC,aAAa,CAAC,iBAAiB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAE/D,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC,CAAC;QAEF,oBAAe,GAAG,GAAS,EAAE;YAC3B,IAAI,CAAC,IAAI,CAAC,aAAa;gBAAE,OAAO;YAEhC,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBAC3B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YACpD,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YAC5D,CAAC;YAED,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,CAAC,CAAC;QAEF,kBAAa,GAAG,GAAS,EAAE;YACzB,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,CAAC,CAAC;QAEM,uBAAkB,GAAG,GAAG,EAAE;YAChC,IAAI,CAAC,IAAI,CAAC,aAAa;gBAAE,OAAO;YAEhC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YACzB,IAAI,CAAC,aAAa,CAAC,oBAAoB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YAClE,IAAI,CAAC,uBAAuB,GAAG,SAAS,CAAC;YACzC,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;YAC/B,IAAI,CAAC,2BAA2B,CAAC,GAAG,GAAG,KAAK,CAAC;YAC7C,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC,CAAC;QAIA,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["import { MemoizedBoolean } from \"@vived/core\";\r\nimport {\r\n getSingletonComponent,\r\n AppObject,\r\n AppObjectEntity,\r\n AppObjectRepo\r\n} from \"@vived/core\";\r\nimport { HostStateEntity, StateDTO } from \"./HostStateEntity\";\r\nimport { HostStateMachine } from \"./HostStateMachine\";\r\n\r\nexport abstract class HostEditingStateEntity extends AppObjectEntity {\r\n static type = \"HostEditingStateEntity\";\r\n\r\n abstract get isEditing(): boolean;\r\n abstract get isNewState(): boolean;\r\n abstract get editingState(): HostStateEntity | undefined;\r\n abstract get somethingHasChanged(): boolean;\r\n abstract stateValidationMessage?: string;\r\n\r\n abstract startNewState(): HostStateEntity | undefined;\r\n abstract startEditing(state: HostStateEntity): void;\r\n abstract cancelEditState(): void;\r\n abstract finishEditing(): void;\r\n\r\n static get(appObjects: AppObjectRepo) {\r\n return getSingletonComponent<HostEditingStateEntity>(\r\n HostEditingStateEntity.type,\r\n appObjects\r\n );\r\n }\r\n}\r\n\r\nexport function makeHostEditingStateEntity(\r\n appObject: AppObject\r\n): HostEditingStateEntity {\r\n return new HostEditingStateEntityImp(appObject);\r\n}\r\n\r\nclass HostEditingStateEntityImp extends HostEditingStateEntity {\r\n private originalStateData?: StateDTO;\r\n \r\n private _editingState?: HostStateEntity;\r\n get editingState() {\r\n return this._editingState;\r\n }\r\n\r\n get isEditing(): boolean {\r\n return this._editingState !== undefined;\r\n }\r\n\r\n private _isNewState = false;\r\n get isNewState(): boolean {\r\n return this._isNewState;\r\n }\r\n\r\n private _stateValidationMessage?: string | undefined;\r\n get stateValidationMessage(): string | undefined {\r\n return this._stateValidationMessage;\r\n }\r\n set stateValidationMessage(val: string | undefined) {\r\n if (this._stateValidationMessage === val) return;\r\n\r\n this._stateValidationMessage = val;\r\n this.notifyOnChange();\r\n }\r\n\r\n private get hostStateMachine() {\r\n return this.getCachedSingleton<HostStateMachine>(HostStateMachine.type);\r\n }\r\n\r\n private memoizedSomethingHasChanged = new MemoizedBoolean(\r\n false,\r\n this.notifyOnChange\r\n );\r\n get somethingHasChanged(): boolean {\r\n return this.memoizedSomethingHasChanged.val;\r\n }\r\n\r\n private checkForChange = () => {\r\n if (!this._editingState) return false;\r\n if (!this.originalStateData) return true;\r\n\r\n if (this._editingState.name !== this.originalStateData.name) return true;\r\n\r\n if (this._editingState.expectedResponse !== this.originalStateData.response)\r\n return true;\r\n\r\n if (\r\n this._editingState.assets.length !== this.originalStateData.assets.length\r\n )\r\n return true;\r\n let assetsHaveChanged = false;\r\n this._editingState.assets.forEach((currentAssetID, i) => {\r\n const originalAssetId = this.originalStateData!.assets[i];\r\n if (originalAssetId !== currentAssetID) {\r\n assetsHaveChanged = true;\r\n }\r\n });\r\n\r\n if (assetsHaveChanged) {\r\n return true;\r\n }\r\n\r\n const currentDataString = JSON.stringify(this._editingState.stateData);\r\n const originalData = JSON.stringify(this.originalStateData?.data ?? \"\");\r\n if (currentDataString !== originalData) return true;\r\n\r\n return false;\r\n };\r\n\r\n private onStateEntityChange = (): void => {\r\n this.memoizedSomethingHasChanged.val = this.checkForChange();\r\n };\r\n\r\n startNewState = (): HostStateEntity | undefined => {\r\n if (!this.hostStateMachine) return;\r\n\r\n this.originalStateData = undefined;\r\n this._isNewState = true;\r\n this._editingState = this.hostStateMachine.createNewState();\r\n this._editingState.addChangeObserver(this.onStateEntityChange);\r\n this.memoizedSomethingHasChanged.val = true;\r\n\r\n return this._editingState;\r\n };\r\n\r\n startEditing = (state: HostStateEntity): void => {\r\n this._editingState = state;\r\n\r\n this.originalStateData = state.getDTO();\r\n this._editingState.addChangeObserver(this.onStateEntityChange);\r\n\r\n this.notifyOnChange();\r\n };\r\n\r\n cancelEditState = (): void => {\r\n if (!this._editingState) return;\r\n\r\n if (this.originalStateData) {\r\n this._editingState.setDTO(this.originalStateData);\r\n } else {\r\n this.hostStateMachine?.deleteState(this._editingState.id);\r\n }\r\n\r\n this.resetInternalState();\r\n };\r\n\r\n finishEditing = (): void => {\r\n this.resetInternalState();\r\n };\r\n\r\n private resetInternalState = () => {\r\n if (!this._editingState) return;\r\n\r\n this._isNewState = false;\r\n this._editingState.removeChangeObserver(this.onStateEntityChange);\r\n this._stateValidationMessage = undefined;\r\n this._editingState = undefined;\r\n this.memoizedSomethingHasChanged.val = false;\r\n this.notifyOnChange();\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, HostEditingStateEntity.type);\r\n this.appObjects.registerSingleton(this);\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"HostEditingStateEntity.js","sourceRoot":"","sources":["../../../../src/StateMachine/Entities/HostEditingStateEntity.ts"],"names":[],"mappings":"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","sourcesContent":["import { MemoizedBoolean } from \"@vived/core\";\r\nimport {\r\n getSingletonComponent,\r\n AppObject,\r\n AppObjectEntity,\r\n AppObjectRepo\r\n} from \"@vived/core\";\r\nimport { HostStateEntity, StateDTO } from \"./HostStateEntity\";\r\nimport { HostStateMachine } from \"./HostStateMachine\";\r\n\r\n/**\r\n * HostEditingStateEntity handles the editing workflow for state entities.\r\n *\r\n * This singleton component manages the process of creating new states or editing\r\n * existing states in the host state machine. It tracks changes made during editing,\r\n * maintains the original state for cancellation/rollback, and provides validation.\r\n *\r\n * The component implements a standard editing pattern:\r\n * 1. Start editing (startEditing) or create new (startNewState)\r\n * 2. Make changes to the editingState directly\r\n * 3. Complete with either finishEditing (commit) or cancelEditState (rollback)\r\n *\r\n * This entity is a critical part of the state authoring workflow and works closely\r\n * with HostStateMachine and HostStateEntity.\r\n */\r\nexport abstract class HostEditingStateEntity extends AppObjectEntity {\r\n static type = \"HostEditingStateEntity\";\r\n\r\n /** Whether currently in edit mode for a state */\r\n abstract get isEditing(): boolean;\r\n\r\n /** Whether editing a newly created state (true) or existing state (false) */\r\n abstract get isNewState(): boolean;\r\n\r\n /** The state entity currently being edited, if any */\r\n abstract get editingState(): HostStateEntity | undefined;\r\n\r\n /** Whether changes have been made since starting edit mode */\r\n abstract get somethingHasChanged(): boolean;\r\n\r\n /** Validation message if the current state is invalid, undefined if valid */\r\n abstract stateValidationMessage?: string;\r\n\r\n /**\r\n * Creates a new state entity and begins editing it\r\n * @returns The newly created state entity that's being edited\r\n */\r\n abstract startNewState(): HostStateEntity | undefined;\r\n\r\n /**\r\n * Begins editing an existing state entity\r\n * @param state The state entity to begin editing\r\n */\r\n abstract startEditing(state: HostStateEntity): void;\r\n\r\n /**\r\n * Cancels the current edit operation and reverts any changes\r\n * For new states, removes them from the state machine\r\n * For existing states, reverts to original values\r\n */\r\n abstract cancelEditState(): void;\r\n\r\n /**\r\n * Completes the current edit operation, keeping all changes\r\n * Performs no validation - validation should happen before calling this\r\n */\r\n abstract finishEditing(): void;\r\n\r\n static get(appObjects: AppObjectRepo) {\r\n return getSingletonComponent<HostEditingStateEntity>(\r\n HostEditingStateEntity.type,\r\n appObjects\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Factory function for creating a HostEditingStateEntity instance\r\n * @param appObject The AppObject to associate with this entity\r\n * @returns A new HostEditingStateEntity instance\r\n */\r\nexport function makeHostEditingStateEntity(\r\n appObject: AppObject\r\n): HostEditingStateEntity {\r\n return new HostEditingStateEntityImp(appObject);\r\n}\r\n\r\n/**\r\n * Implementation of the HostEditingStateEntity abstract class\r\n * Manages the state editing workflow and tracks changes\r\n */\r\nclass HostEditingStateEntityImp extends HostEditingStateEntity {\r\n /** Stores the original state data for reverting changes on cancel */\r\n private originalStateData?: StateDTO;\r\n\r\n private _editingState?: HostStateEntity;\r\n get editingState() {\r\n return this._editingState;\r\n }\r\n\r\n get isEditing(): boolean {\r\n return this._editingState !== undefined;\r\n }\r\n\r\n private _isNewState = false;\r\n get isNewState(): boolean {\r\n return this._isNewState;\r\n }\r\n\r\n private _stateValidationMessage?: string | undefined;\r\n get stateValidationMessage(): string | undefined {\r\n return this._stateValidationMessage;\r\n }\r\n set stateValidationMessage(val: string | undefined) {\r\n if (this._stateValidationMessage === val) return;\r\n\r\n this._stateValidationMessage = val;\r\n this.notifyOnChange();\r\n }\r\n\r\n /**\r\n * Reference to the HostStateMachine singleton\r\n * Used for creating and managing states\r\n */\r\n private get hostStateMachine() {\r\n return this.getCachedSingleton<HostStateMachine>(HostStateMachine.type);\r\n }\r\n\r\n /**\r\n * Tracks whether changes have been made to the state being edited\r\n * Uses a memoized value to efficiently notify observers only when value changes\r\n */\r\n private memoizedSomethingHasChanged = new MemoizedBoolean(\r\n false,\r\n this.notifyOnChange\r\n );\r\n get somethingHasChanged(): boolean {\r\n return this.memoizedSomethingHasChanged.val;\r\n }\r\n\r\n /**\r\n * Compares the current state with the original state to detect changes\r\n * Performs deep comparison of all relevant properties\r\n * @returns true if changes were detected, false otherwise\r\n */\r\n private checkForChange = () => {\r\n if (!this._editingState) return false;\r\n if (!this.originalStateData) return true;\r\n\r\n if (this._editingState.name !== this.originalStateData.name) return true;\r\n\r\n if (this._editingState.expectedResponse !== this.originalStateData.response)\r\n return true;\r\n\r\n if (\r\n this._editingState.assets.length !== this.originalStateData.assets.length\r\n )\r\n return true;\r\n let assetsHaveChanged = false;\r\n this._editingState.assets.forEach((currentAssetID, i) => {\r\n const originalAssetId = this.originalStateData!.assets[i];\r\n if (originalAssetId !== currentAssetID) {\r\n assetsHaveChanged = true;\r\n }\r\n });\r\n\r\n if (assetsHaveChanged) {\r\n return true;\r\n }\r\n\r\n const currentDataString = JSON.stringify(this._editingState.stateData);\r\n const originalData = JSON.stringify(this.originalStateData?.data ?? \"\");\r\n if (currentDataString !== originalData) return true;\r\n\r\n return false;\r\n };\r\n\r\n /**\r\n * Observer callback for state changes\r\n * Updates the somethingHasChanged flag when the state being edited changes\r\n */\r\n private onStateEntityChange = (): void => {\r\n this.memoizedSomethingHasChanged.val = this.checkForChange();\r\n };\r\n\r\n /**\r\n * Creates a new state and begins editing it\r\n * @returns The newly created state entity or undefined if creation failed\r\n */\r\n startNewState = (): HostStateEntity | undefined => {\r\n if (!this.hostStateMachine) return;\r\n\r\n this.originalStateData = undefined;\r\n this._isNewState = true;\r\n this._editingState = this.hostStateMachine.createNewState();\r\n this._editingState.addChangeObserver(this.onStateEntityChange);\r\n this.memoizedSomethingHasChanged.val = true;\r\n\r\n return this._editingState;\r\n };\r\n\r\n /**\r\n * Begins editing an existing state\r\n * @param state The state entity to edit\r\n */\r\n startEditing = (state: HostStateEntity): void => {\r\n this._editingState = state;\r\n\r\n this.originalStateData = state.getDTO();\r\n this._editingState.addChangeObserver(this.onStateEntityChange);\r\n\r\n this.notifyOnChange();\r\n };\r\n\r\n /**\r\n * Cancels editing and reverts changes\r\n * For new states, removes them from the state machine\r\n * For existing states, restores the original values\r\n */\r\n cancelEditState = (): void => {\r\n if (!this._editingState) return;\r\n\r\n if (this.originalStateData) {\r\n this._editingState.setDTO(this.originalStateData);\r\n } else {\r\n this.hostStateMachine?.deleteState(this._editingState.id);\r\n }\r\n\r\n this.resetInternalState();\r\n };\r\n\r\n /**\r\n * Completes editing, keeping all changes\r\n * Simply cleans up the internal state without reverting changes\r\n */\r\n finishEditing = (): void => {\r\n this.resetInternalState();\r\n };\r\n\r\n /**\r\n * Resets the internal state after editing is complete\r\n * Cleans up observers and notifies clients of the change\r\n */\r\n private resetInternalState = () => {\r\n if (!this._editingState) return;\r\n\r\n this._isNewState = false;\r\n this._editingState.removeChangeObserver(this.onStateEntityChange);\r\n this._stateValidationMessage = undefined;\r\n this._editingState = undefined;\r\n this.memoizedSomethingHasChanged.val = false;\r\n this.notifyOnChange();\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, HostEditingStateEntity.type);\r\n this.appObjects.registerSingleton(this);\r\n }\r\n}\r\n"]}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { MemoizedString } from "@vived/core";
|
|
2
2
|
import { AppObjectEntity } from "@vived/core";
|
|
3
|
+
/**
|
|
4
|
+
* Defines the types of challenge responses that can be expected in a state
|
|
5
|
+
* These represent different feedback mechanisms available to the user
|
|
6
|
+
*/
|
|
3
7
|
export var ChallengeResponse;
|
|
4
8
|
(function (ChallengeResponse) {
|
|
5
9
|
ChallengeResponse["NONE"] = "NONE";
|
|
@@ -7,19 +11,63 @@ export var ChallengeResponse;
|
|
|
7
11
|
ChallengeResponse["HIT"] = "HIT";
|
|
8
12
|
ChallengeResponse["MULTIHIT"] = "MULTIHIT";
|
|
9
13
|
ChallengeResponse["PROGRESS"] = "PROGRESS";
|
|
10
|
-
ChallengeResponse["QUALITY"] = "QUALITY";
|
|
14
|
+
ChallengeResponse["QUALITY"] = "QUALITY"; // Quality-rated response
|
|
11
15
|
})(ChallengeResponse || (ChallengeResponse = {}));
|
|
16
|
+
/**
|
|
17
|
+
* Defines the loading states for streaming assets in a state
|
|
18
|
+
*/
|
|
19
|
+
export var StreamState;
|
|
20
|
+
(function (StreamState) {
|
|
21
|
+
StreamState["INIT"] = "INIT";
|
|
22
|
+
StreamState["LOADING"] = "LOADING";
|
|
23
|
+
StreamState["READY"] = "READY";
|
|
24
|
+
StreamState["ERROR"] = "ERROR"; // Error occurred during loading
|
|
25
|
+
})(StreamState || (StreamState = {}));
|
|
26
|
+
/**
|
|
27
|
+
* HostStateEntity represents a single state within a state machine.
|
|
28
|
+
*
|
|
29
|
+
* Each state contains:
|
|
30
|
+
* - Metadata (name, ID)
|
|
31
|
+
* - References to assets needed by the state
|
|
32
|
+
* - Custom state data specific to the app implementation
|
|
33
|
+
* - Expected response type for challenge/interaction
|
|
34
|
+
*
|
|
35
|
+
* States are managed by the HostStateMachine and can be persisted/restored
|
|
36
|
+
* through the DTO pattern.
|
|
37
|
+
*
|
|
38
|
+
* This is a core component of the VIVED platform's state-based application model,
|
|
39
|
+
* allowing apps to define discrete states with specific content and behaviors.
|
|
40
|
+
*/
|
|
12
41
|
export class HostStateEntity extends AppObjectEntity {
|
|
42
|
+
/**
|
|
43
|
+
* Gets an existing HostStateEntity by ID
|
|
44
|
+
* @param id The unique identifier for the state
|
|
45
|
+
* @param appObjects The app object repository
|
|
46
|
+
* @returns The state entity if found, undefined otherwise
|
|
47
|
+
*/
|
|
13
48
|
static get(id, appObjects) {
|
|
14
49
|
const ao = appObjects.get(id);
|
|
15
50
|
return ao?.getComponent(HostStateEntity.type);
|
|
16
51
|
}
|
|
17
52
|
}
|
|
18
53
|
HostStateEntity.type = "HostStateEntity";
|
|
54
|
+
/**
|
|
55
|
+
* Factory function for creating a HostStateEntity instance
|
|
56
|
+
* @param appObject The AppObject to associate with this entity
|
|
57
|
+
* @returns A new HostStateEntity instance
|
|
58
|
+
*/
|
|
19
59
|
export function makeHostStateEntity(appObject) {
|
|
20
60
|
return new HostStateEntityImp(appObject);
|
|
21
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Implementation of the HostStateEntity abstract class
|
|
64
|
+
* Provides concrete implementation of state properties and methods
|
|
65
|
+
*/
|
|
22
66
|
class HostStateEntityImp extends HostStateEntity {
|
|
67
|
+
/**
|
|
68
|
+
* The unique identifier for this state
|
|
69
|
+
* Derived from the associated AppObject ID
|
|
70
|
+
*/
|
|
23
71
|
get id() {
|
|
24
72
|
return this.appObject.id;
|
|
25
73
|
}
|
|
@@ -32,6 +80,11 @@ class HostStateEntityImp extends HostStateEntity {
|
|
|
32
80
|
get stateData() {
|
|
33
81
|
return this._data;
|
|
34
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Updates the state data, optionally checking if it actually changed
|
|
85
|
+
* @param val New state data
|
|
86
|
+
* @param checkForChange If true, only notifies on actual changes
|
|
87
|
+
*/
|
|
35
88
|
setStateData(val, checkForChange) {
|
|
36
89
|
let notify = true;
|
|
37
90
|
if (checkForChange) {
|
|
@@ -77,6 +130,10 @@ class HostStateEntityImp extends HostStateEntity {
|
|
|
77
130
|
this._expectedResponse = val;
|
|
78
131
|
this.notifyOnChange();
|
|
79
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Serializes state to a data transfer object
|
|
135
|
+
* Used for persistence and state management
|
|
136
|
+
*/
|
|
80
137
|
getDTO() {
|
|
81
138
|
return {
|
|
82
139
|
id: this.id,
|
|
@@ -87,6 +144,11 @@ class HostStateEntityImp extends HostStateEntity {
|
|
|
87
144
|
appID: this.appID
|
|
88
145
|
};
|
|
89
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Applies state data from a DTO
|
|
149
|
+
* Used when restoring state or rolling back changes
|
|
150
|
+
* @param dto The data transfer object to apply
|
|
151
|
+
*/
|
|
90
152
|
setDTO(dto) {
|
|
91
153
|
if (dto.id !== this.id) {
|
|
92
154
|
this.warn("DTO id does not match my ID. Skipping");
|
|
@@ -109,12 +171,39 @@ class HostStateEntityImp extends HostStateEntity {
|
|
|
109
171
|
set appID(val) {
|
|
110
172
|
this.memoisedAppID.val = val;
|
|
111
173
|
}
|
|
174
|
+
get streamState() {
|
|
175
|
+
return this.memoizedStreamState.val;
|
|
176
|
+
}
|
|
177
|
+
set streamState(val) {
|
|
178
|
+
this.memoizedStreamState.val = val;
|
|
179
|
+
}
|
|
112
180
|
constructor(appObject) {
|
|
113
181
|
super(appObject, HostStateEntity.type);
|
|
182
|
+
/**
|
|
183
|
+
* Memoized name property with change notification
|
|
184
|
+
* Uses MemoizedString to efficiently track changes
|
|
185
|
+
*/
|
|
114
186
|
this.memoizedName = new MemoizedString("", this.notifyOnChange);
|
|
187
|
+
/**
|
|
188
|
+
* Custom state data object
|
|
189
|
+
* This is app-specific data that defines the state behavior
|
|
190
|
+
*/
|
|
115
191
|
this._data = {};
|
|
192
|
+
/**
|
|
193
|
+
* Array of asset IDs required by this state
|
|
194
|
+
* Assets are loaded before the state becomes active
|
|
195
|
+
*/
|
|
116
196
|
this._assets = [];
|
|
197
|
+
/**
|
|
198
|
+
* ID of the app this state belongs to
|
|
199
|
+
* States can only be used with their associated app
|
|
200
|
+
*/
|
|
117
201
|
this.memoisedAppID = new MemoizedString("", this.notifyOnChange);
|
|
202
|
+
/**
|
|
203
|
+
* Current loading state for streaming assets
|
|
204
|
+
* Used to track progress when loading assets for this state
|
|
205
|
+
*/
|
|
206
|
+
this.memoizedStreamState = new MemoizedString(StreamState.INIT, this.notifyOnChange);
|
|
118
207
|
}
|
|
119
208
|
}
|
|
120
209
|
//# sourceMappingURL=HostStateEntity.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HostStateEntity.js","sourceRoot":"","sources":["../../../../src/StateMachine/Entities/HostStateEntity.ts"],"names":[],"mappings":"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","sourcesContent":["import { MemoizedString } from \"@vived/core\";\r\nimport { AppObject, AppObjectEntity, AppObjectRepo } from \"@vived/core\";\r\n\r\nexport enum ChallengeResponse {\r\n NONE = \"NONE\",\r\n SCORE = \"SCORE\",\r\n HIT = \"HIT\",\r\n MULTIHIT = \"MULTIHIT\",\r\n PROGRESS = \"PROGRESS\",\r\n QUALITY = \"QUALITY\"\r\n}\r\n\r\nexport interface StateDTO {\r\n id: string;\r\n name: string;\r\n data: object;\r\n assets: string[];\r\n response: string | undefined;\r\n appID: string;\r\n}\r\n\r\nexport abstract class HostStateEntity extends AppObjectEntity {\r\n static type = \"HostStateEntity\";\r\n\r\n abstract get id(): string;\r\n\r\n abstract name: string;\r\n abstract assets: string[];\r\n abstract expectedResponse: ChallengeResponse | undefined;\r\n abstract appID: string;\r\n abstract getDTO(): StateDTO;\r\n abstract setDTO(dto: StateDTO): void;\r\n\r\n abstract get stateData(): object;\r\n abstract setStateData(val: object, checkForChange?: boolean): void;\r\n\r\n static get(id: string, appObjects: AppObjectRepo) {\r\n const ao = appObjects.get(id);\r\n return ao?.getComponent<HostStateEntity>(HostStateEntity.type);\r\n }\r\n}\r\n\r\nexport function makeHostStateEntity(appObject: AppObject): HostStateEntity {\r\n return new HostStateEntityImp(appObject);\r\n}\r\n\r\nclass HostStateEntityImp extends HostStateEntity {\r\n get id(): string {\r\n return this.appObject.id;\r\n }\r\n\r\n private memoizedName = new MemoizedString(\"\", this.notifyOnChange);\r\n get name(): string {\r\n return this.memoizedName.val;\r\n }\r\n set name(val: string) {\r\n this.memoizedName.val = val;\r\n }\r\n\r\n private _data = {};\r\n get stateData(): object {\r\n return this._data;\r\n }\r\n\r\n setStateData(val: object, checkForChange?: boolean): void {\r\n let notify = true;\r\n if (checkForChange) {\r\n const currentData = JSON.stringify(this._data);\r\n const newData = JSON.stringify(val);\r\n\r\n if (currentData === newData) {\r\n notify = false;\r\n }\r\n }\r\n\r\n this._data = val;\r\n if (notify) {\r\n this.notifyOnChange();\r\n }\r\n }\r\n\r\n private _assets: string[] = [];\r\n get assets() {\r\n return [...this._assets];\r\n }\r\n set assets(val: string[]) {\r\n if (val.length !== this._assets.length) {\r\n this._assets = val;\r\n this.notifyOnChange();\r\n return;\r\n }\r\n\r\n let somethingHasChanged = false;\r\n val.forEach((newAsset, i) => {\r\n const existingAsset = this._assets[i];\r\n if (existingAsset !== newAsset) {\r\n somethingHasChanged = true;\r\n }\r\n });\r\n\r\n if (!somethingHasChanged) {\r\n return;\r\n }\r\n\r\n this._assets = val;\r\n this.notifyOnChange();\r\n }\r\n\r\n private _expectedResponse: ChallengeResponse | undefined;\r\n get expectedResponse() {\r\n return this._expectedResponse;\r\n }\r\n set expectedResponse(val: ChallengeResponse | undefined) {\r\n if (val === this._expectedResponse) return;\r\n\r\n this._expectedResponse = val;\r\n this.notifyOnChange();\r\n }\r\n\r\n getDTO(): StateDTO {\r\n return {\r\n id: this.id,\r\n assets: [...this._assets],\r\n data: this._data,\r\n name: this.memoizedName.val,\r\n response: this._expectedResponse,\r\n appID: this.appID\r\n };\r\n }\r\n\r\n setDTO(dto: StateDTO): void {\r\n if (dto.id !== this.id) {\r\n this.warn(\"DTO id does not match my ID. Skipping\");\r\n return;\r\n }\r\n\r\n this.setStateData(dto.data, true);\r\n this.assets = [...dto.assets];\r\n this.memoizedName.val = dto.name;\r\n this.memoisedAppID.val = dto.appID;\r\n\r\n if ((Object as any).values(ChallengeResponse).includes(dto.response)) {\r\n this.expectedResponse = dto.response as ChallengeResponse;\r\n } else {\r\n this.expectedResponse = undefined;\r\n }\r\n }\r\n\r\n private memoisedAppID = new MemoizedString(\"\", this.notifyOnChange);\r\n get appID(): string {\r\n return this.memoisedAppID.val;\r\n }\r\n set appID(val: string) {\r\n this.memoisedAppID.val = val;\r\n }\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, HostStateEntity.type);\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"HostStateEntity.js","sourceRoot":"","sources":["../../../../src/StateMachine/Entities/HostStateEntity.ts"],"names":[],"mappings":"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","sourcesContent":["import { MemoizedString } from \"@vived/core\";\r\nimport { AppObject, AppObjectEntity, AppObjectRepo } from \"@vived/core\";\r\n\r\n/**\r\n * Defines the types of challenge responses that can be expected in a state\r\n * These represent different feedback mechanisms available to the user\r\n */\r\nexport enum ChallengeResponse {\r\n NONE = \"NONE\", // No specific response expected\r\n SCORE = \"SCORE\", // Numeric score-based response\r\n HIT = \"HIT\", // Binary hit/miss response\r\n MULTIHIT = \"MULTIHIT\", // Multiple hit targets response\r\n PROGRESS = \"PROGRESS\", // Continuous progress response\r\n QUALITY = \"QUALITY\" // Quality-rated response\r\n}\r\n\r\n/**\r\n * Defines the loading states for streaming assets in a state\r\n */\r\nexport enum StreamState {\r\n INIT = \"INIT\", // Initial state before loading\r\n LOADING = \"LOADING\", // Assets are currently loading\r\n READY = \"READY\", // Assets have loaded successfully\r\n ERROR = \"ERROR\" // Error occurred during loading\r\n}\r\n\r\n/**\r\n * Data Transfer Object for serializing/deserializing state data\r\n * Used for persistence, state management, and undo/redo operations\r\n */\r\nexport interface StateDTO {\r\n id: string; // Unique identifier for the state\r\n name: string; // Display name for the state\r\n data: object; // Custom state data - structure depends on app implementation\r\n assets: string[]; // Array of asset IDs referenced by this state\r\n response: string | undefined; // Expected challenge response type\r\n appID: string; // ID of the app this state belongs to\r\n}\r\n\r\n/**\r\n * HostStateEntity represents a single state within a state machine.\r\n *\r\n * Each state contains:\r\n * - Metadata (name, ID)\r\n * - References to assets needed by the state\r\n * - Custom state data specific to the app implementation\r\n * - Expected response type for challenge/interaction\r\n *\r\n * States are managed by the HostStateMachine and can be persisted/restored\r\n * through the DTO pattern.\r\n *\r\n * This is a core component of the VIVED platform's state-based application model,\r\n * allowing apps to define discrete states with specific content and behaviors.\r\n */\r\nexport abstract class HostStateEntity extends AppObjectEntity {\r\n static type = \"HostStateEntity\";\r\n\r\n /** Unique identifier for this state */\r\n abstract get id(): string;\r\n\r\n /** Human-readable name of the state */\r\n abstract name: string;\r\n\r\n /** List of asset IDs required by this state */\r\n abstract assets: string[];\r\n\r\n /** Type of response expected from user interactions in this state */\r\n abstract expectedResponse: ChallengeResponse | undefined;\r\n\r\n /** ID of the app this state belongs to */\r\n abstract appID: string;\r\n\r\n /** Current loading state for streaming assets */\r\n abstract streamState: StreamState;\r\n\r\n /**\r\n * Serializes the state to a plain object for persistence\r\n * @returns StateDTO containing all state data\r\n */\r\n abstract getDTO(): StateDTO;\r\n\r\n /**\r\n * Deserializes from a DTO and updates this state's properties\r\n * @param dto The state data transfer object to apply\r\n */\r\n abstract setDTO(dto: StateDTO): void;\r\n\r\n /**\r\n * Gets the custom state data object\r\n * Structure is specific to the app implementation\r\n */\r\n abstract get stateData(): object;\r\n\r\n /**\r\n * Updates the custom state data object\r\n * @param val New state data object\r\n * @param checkForChange If true, only notifies observers when actual changes occur\r\n */\r\n abstract setStateData(val: object, checkForChange?: boolean): void;\r\n\r\n /**\r\n * Gets an existing HostStateEntity by ID\r\n * @param id The unique identifier for the state\r\n * @param appObjects The app object repository\r\n * @returns The state entity if found, undefined otherwise\r\n */\r\n static get(id: string, appObjects: AppObjectRepo) {\r\n const ao = appObjects.get(id);\r\n return ao?.getComponent<HostStateEntity>(HostStateEntity.type);\r\n }\r\n}\r\n\r\n/**\r\n * Factory function for creating a HostStateEntity instance\r\n * @param appObject The AppObject to associate with this entity\r\n * @returns A new HostStateEntity instance\r\n */\r\nexport function makeHostStateEntity(appObject: AppObject): HostStateEntity {\r\n return new HostStateEntityImp(appObject);\r\n}\r\n\r\n/**\r\n * Implementation of the HostStateEntity abstract class\r\n * Provides concrete implementation of state properties and methods\r\n */\r\nclass HostStateEntityImp extends HostStateEntity {\r\n /**\r\n * The unique identifier for this state\r\n * Derived from the associated AppObject ID\r\n */\r\n get id(): string {\r\n return this.appObject.id;\r\n }\r\n\r\n /**\r\n * Memoized name property with change notification\r\n * Uses MemoizedString to efficiently track changes\r\n */\r\n private memoizedName = new MemoizedString(\"\", this.notifyOnChange);\r\n get name(): string {\r\n return this.memoizedName.val;\r\n }\r\n set name(val: string) {\r\n this.memoizedName.val = val;\r\n }\r\n\r\n /**\r\n * Custom state data object\r\n * This is app-specific data that defines the state behavior\r\n */\r\n private _data = {};\r\n get stateData(): object {\r\n return this._data;\r\n }\r\n\r\n /**\r\n * Updates the state data, optionally checking if it actually changed\r\n * @param val New state data\r\n * @param checkForChange If true, only notifies on actual changes\r\n */\r\n setStateData(val: object, checkForChange?: boolean): void {\r\n let notify = true;\r\n if (checkForChange) {\r\n const currentData = JSON.stringify(this._data);\r\n const newData = JSON.stringify(val);\r\n\r\n if (currentData === newData) {\r\n notify = false;\r\n }\r\n }\r\n\r\n this._data = val;\r\n if (notify) {\r\n this.notifyOnChange();\r\n }\r\n }\r\n\r\n /**\r\n * Array of asset IDs required by this state\r\n * Assets are loaded before the state becomes active\r\n */\r\n private _assets: string[] = [];\r\n get assets() {\r\n return [...this._assets];\r\n }\r\n set assets(val: string[]) {\r\n if (val.length !== this._assets.length) {\r\n this._assets = val;\r\n this.notifyOnChange();\r\n return;\r\n }\r\n\r\n let somethingHasChanged = false;\r\n val.forEach((newAsset, i) => {\r\n const existingAsset = this._assets[i];\r\n if (existingAsset !== newAsset) {\r\n somethingHasChanged = true;\r\n }\r\n });\r\n\r\n if (!somethingHasChanged) {\r\n return;\r\n }\r\n\r\n this._assets = val;\r\n this.notifyOnChange();\r\n }\r\n\r\n /**\r\n * Type of response expected from user interactions\r\n * Determines how challenge results are processed\r\n */\r\n private _expectedResponse: ChallengeResponse | undefined;\r\n get expectedResponse() {\r\n return this._expectedResponse;\r\n }\r\n set expectedResponse(val: ChallengeResponse | undefined) {\r\n if (val === this._expectedResponse) return;\r\n\r\n this._expectedResponse = val;\r\n this.notifyOnChange();\r\n }\r\n\r\n /**\r\n * Serializes state to a data transfer object\r\n * Used for persistence and state management\r\n */\r\n getDTO(): StateDTO {\r\n return {\r\n id: this.id,\r\n assets: [...this._assets],\r\n data: this._data,\r\n name: this.memoizedName.val,\r\n response: this._expectedResponse,\r\n appID: this.appID\r\n };\r\n }\r\n\r\n /**\r\n * Applies state data from a DTO\r\n * Used when restoring state or rolling back changes\r\n * @param dto The data transfer object to apply\r\n */\r\n setDTO(dto: StateDTO): void {\r\n if (dto.id !== this.id) {\r\n this.warn(\"DTO id does not match my ID. Skipping\");\r\n return;\r\n }\r\n\r\n this.setStateData(dto.data, true);\r\n this.assets = [...dto.assets];\r\n this.memoizedName.val = dto.name;\r\n this.memoisedAppID.val = dto.appID;\r\n\r\n if ((Object as any).values(ChallengeResponse).includes(dto.response)) {\r\n this.expectedResponse = dto.response as ChallengeResponse;\r\n } else {\r\n this.expectedResponse = undefined;\r\n }\r\n }\r\n\r\n /**\r\n * ID of the app this state belongs to\r\n * States can only be used with their associated app\r\n */\r\n private memoisedAppID = new MemoizedString(\"\", this.notifyOnChange);\r\n get appID(): string {\r\n return this.memoisedAppID.val;\r\n }\r\n set appID(val: string) {\r\n this.memoisedAppID.val = val;\r\n }\r\n\r\n /**\r\n * Current loading state for streaming assets\r\n * Used to track progress when loading assets for this state\r\n */\r\n private memoizedStreamState = new MemoizedString(\r\n StreamState.INIT,\r\n this.notifyOnChange\r\n );\r\n get streamState(): StreamState {\r\n return this.memoizedStreamState.val as StreamState;\r\n }\r\n set streamState(val: StreamState) {\r\n this.memoizedStreamState.val = val;\r\n }\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, HostStateEntity.type);\r\n }\r\n}\r\n"]}
|