@onehat/data 1.22.37 → 1.22.39
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/package.json +1 -1
- package/src/Integration/Browser/Repository/LocalStorage.js +194 -3
- package/src/Integration/Browser/Repository/SecureLocalStorage.js +3 -1
- package/src/Integration/Browser/Repository/SecureSessionStorage.js +4 -2
- package/src/Integration/Browser/Repository/SessionStorage.js +147 -4
- package/src/Integration/Browser/Repository/crossTabConstants.js +5 -0
- package/src/OneHatData.js +4 -0
- package/src/Repository/OneBuild.js +1 -1
- /package/.github/{copilot-instructions.md → copilot-instructions.md.bak.20260307094057} +0 -0
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import OfflineRepository from '@onehat/data/src/Repository/Offline.js';
|
|
4
4
|
import store from 'store2'; // see: https://github.com/nbubna/store#readme
|
|
5
5
|
import _ from 'lodash';
|
|
6
|
+
import { CROSS_TAB_CHANNEL_NAME, CROSS_TAB_MESSAGE_TYPE, CROSS_TAB_EVENT_NAME } from './crossTabConstants.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Repository representing a browser's LocalStorage implementation
|
|
@@ -17,9 +18,183 @@ class LocalStorageRepository extends OfflineRepository {
|
|
|
17
18
|
|
|
18
19
|
this._store = store.namespace(this.schema.name);
|
|
19
20
|
|
|
21
|
+
// crossTabSync defaults
|
|
22
|
+
this._crossTabSyncEnabled = config.crossTabSync === true;
|
|
23
|
+
this._crossTabChannelName = config.crossTabChannelName || CROSS_TAB_CHANNEL_NAME;
|
|
24
|
+
this._crossTabChannel = null;
|
|
25
|
+
this._onCrossTabStorageEvent = null;
|
|
26
|
+
this._onCrossTabMessageEvent = null;
|
|
27
|
+
|
|
28
|
+
this.registerEvent(CROSS_TAB_EVENT_NAME);
|
|
29
|
+
|
|
20
30
|
if (this._store.isFake()) {
|
|
21
31
|
throw new Error('store2 error: persistent storage not established.');
|
|
22
32
|
}
|
|
33
|
+
|
|
34
|
+
this._setupCrossTabSync();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* _setupCrossTabSync
|
|
39
|
+
*
|
|
40
|
+
* Initialises cross-tab change notification.
|
|
41
|
+
* Prefers BroadcastChannel (direct messaging, all modern browsers) and falls back to
|
|
42
|
+
* the native window 'storage' event, which browsers fire in every *other* tab whenever
|
|
43
|
+
* localStorage is mutated.
|
|
44
|
+
*/
|
|
45
|
+
_setupCrossTabSync() {
|
|
46
|
+
if (!this._crossTabSyncEnabled || typeof window === 'undefined') {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (typeof BroadcastChannel !== 'undefined') {
|
|
51
|
+
this._crossTabChannel = new BroadcastChannel(this._crossTabChannelName);
|
|
52
|
+
this._onCrossTabMessageEvent = this._handleBroadcastMessage.bind(this);
|
|
53
|
+
this._crossTabChannel.addEventListener('message', this._onCrossTabMessageEvent);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (_.isFunction(window.addEventListener)) {
|
|
58
|
+
this._onCrossTabStorageEvent = this._handleStorageEvent.bind(this);
|
|
59
|
+
window.addEventListener('storage', this._onCrossTabStorageEvent);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* _teardownCrossTabSync
|
|
65
|
+
*
|
|
66
|
+
* Removes all cross-tab listeners and closes the BroadcastChannel.
|
|
67
|
+
* Called from destroy() to prevent memory leaks and stale event handlers after
|
|
68
|
+
* the repository is no longer in use.
|
|
69
|
+
*/
|
|
70
|
+
_teardownCrossTabSync() {
|
|
71
|
+
if (typeof window !== 'undefined' && _.isFunction(window.removeEventListener) && this._onCrossTabStorageEvent) {
|
|
72
|
+
window.removeEventListener('storage', this._onCrossTabStorageEvent);
|
|
73
|
+
this._onCrossTabStorageEvent = null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (this._crossTabChannel) {
|
|
77
|
+
if (this._onCrossTabMessageEvent) {
|
|
78
|
+
this._crossTabChannel.removeEventListener('message', this._onCrossTabMessageEvent);
|
|
79
|
+
this._onCrossTabMessageEvent = null;
|
|
80
|
+
}
|
|
81
|
+
this._crossTabChannel.close();
|
|
82
|
+
this._crossTabChannel = null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* _getNamespacedKey
|
|
88
|
+
*
|
|
89
|
+
*
|
|
90
|
+
* Returns the fully-qualified storage key that store2 uses for a given entry name.
|
|
91
|
+
* store2 namespaces keys with a prefix derived from the schema name, so the raw
|
|
92
|
+
* key and the actual localStorage key differ. Broadcasting the namespaced key lets
|
|
93
|
+
* recipients correlate messages with what they see in raw storage APIs.
|
|
94
|
+
*/
|
|
95
|
+
_getNamespacedKey(name) {
|
|
96
|
+
if (!this._store || !_.isFunction(this._store._in)) {
|
|
97
|
+
return name;
|
|
98
|
+
}
|
|
99
|
+
return this._store._in(name);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* _emitCrossTabStorageChange
|
|
104
|
+
*
|
|
105
|
+
* Emits the crossTabStorageChange event on this repository instance.
|
|
106
|
+
* Attaches standard repository identity fields so listeners always know which
|
|
107
|
+
* repository triggered the change, regardless of how many are registered.
|
|
108
|
+
*/
|
|
109
|
+
_emitCrossTabStorageChange(data = {}) {
|
|
110
|
+
this.emit(CROSS_TAB_EVENT_NAME, {
|
|
111
|
+
repositoryId: this.id,
|
|
112
|
+
repositoryName: this.name,
|
|
113
|
+
repositoryType: this.type,
|
|
114
|
+
...data,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* _handleBroadcastMessage
|
|
120
|
+
*
|
|
121
|
+
* Handles an incoming BroadcastChannel message from another tab.
|
|
122
|
+
* Filters out messages that are not storage-change notifications, messages
|
|
123
|
+
* originating from this same repository instance (echo prevention), and messages
|
|
124
|
+
* intended for a different repository, then re-emits the change locally.
|
|
125
|
+
*/
|
|
126
|
+
_handleBroadcastMessage(event) {
|
|
127
|
+
const data = event?.data;
|
|
128
|
+
if (!data || data.type !== CROSS_TAB_MESSAGE_TYPE) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (data.repositoryId === this.id) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (data.repositoryName !== this.name) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
this._emitCrossTabStorageChange({
|
|
139
|
+
source: 'broadcast',
|
|
140
|
+
operation: data.operation,
|
|
141
|
+
key: data.key,
|
|
142
|
+
namespacedKey: data.namespacedKey,
|
|
143
|
+
timestamp: data.timestamp,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* _handleStorageEvent
|
|
149
|
+
*
|
|
150
|
+
* Handles the native window 'storage' event, which fires in every tab *except*
|
|
151
|
+
* the one that made the change. Used as a fallback when BroadcastChannel is
|
|
152
|
+
* unavailable. Filters to keys belonging to this repository's store2 namespace,
|
|
153
|
+
* then derives the operation from whether the new value is null (delete) or not.
|
|
154
|
+
*/
|
|
155
|
+
_handleStorageEvent(event) {
|
|
156
|
+
if (!event || !event.key) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const namespace = this._store?._ns;
|
|
160
|
+
if (!namespace || !event.key.startsWith(namespace)) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const key = event.key.replace(namespace, '');
|
|
165
|
+
if (!key) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this._emitCrossTabStorageChange({
|
|
170
|
+
source: 'storage',
|
|
171
|
+
operation: _.isNil(event.newValue) ? 'delete' : 'set',
|
|
172
|
+
key,
|
|
173
|
+
namespacedKey: event.key,
|
|
174
|
+
timestamp: Date.now(),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Posts a structured message to the BroadcastChannel so other tabs can react
|
|
180
|
+
* to a storage mutation made in this tab. Only called when BroadcastChannel is
|
|
181
|
+
* available; the storage-event fallback path does not require an explicit broadcast
|
|
182
|
+
* because the browser fires the 'storage' event automatically.
|
|
183
|
+
*/
|
|
184
|
+
_broadcastStorageChange(name, operation) {
|
|
185
|
+
if (!this._crossTabSyncEnabled || !this._crossTabChannel) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
this._crossTabChannel.postMessage({
|
|
190
|
+
type: CROSS_TAB_MESSAGE_TYPE,
|
|
191
|
+
repositoryId: this.id,
|
|
192
|
+
repositoryName: this.name,
|
|
193
|
+
operation,
|
|
194
|
+
key: name || null,
|
|
195
|
+
namespacedKey: _.isNil(name) ? null : this._getNamespacedKey(name),
|
|
196
|
+
timestamp: Date.now(),
|
|
197
|
+
});
|
|
23
198
|
}
|
|
24
199
|
|
|
25
200
|
_storageGetValue(name){
|
|
@@ -62,7 +237,9 @@ class LocalStorageRepository extends OfflineRepository {
|
|
|
62
237
|
value = JSON.stringify(value);
|
|
63
238
|
}
|
|
64
239
|
|
|
65
|
-
|
|
240
|
+
const result = this._store(name, value);
|
|
241
|
+
this._broadcastStorageChange(name, 'set');
|
|
242
|
+
return result;
|
|
66
243
|
|
|
67
244
|
} catch (error) {
|
|
68
245
|
if (this.debugMode) {
|
|
@@ -82,7 +259,9 @@ class LocalStorageRepository extends OfflineRepository {
|
|
|
82
259
|
console.log(this.name, 'LocalStorage.delete', name);
|
|
83
260
|
}
|
|
84
261
|
|
|
85
|
-
|
|
262
|
+
const result = this._store.remove(name);
|
|
263
|
+
this._broadcastStorageChange(name, 'delete');
|
|
264
|
+
return result;
|
|
86
265
|
|
|
87
266
|
} catch (error) {
|
|
88
267
|
if (this.debugMode) {
|
|
@@ -93,7 +272,19 @@ class LocalStorageRepository extends OfflineRepository {
|
|
|
93
272
|
}
|
|
94
273
|
|
|
95
274
|
clearAll() {
|
|
96
|
-
|
|
275
|
+
const result = this._store.clearAll();
|
|
276
|
+
this._broadcastStorageChange(null, 'clearAll');
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Cleans up cross-tab sync resources before delegating to the parent destroy.
|
|
282
|
+
* Ensures the BroadcastChannel is closed and event listeners are removed so the
|
|
283
|
+
* repository does not continue to react to storage events after disposal.
|
|
284
|
+
*/
|
|
285
|
+
destroy() {
|
|
286
|
+
this._teardownCrossTabSync();
|
|
287
|
+
super.destroy();
|
|
97
288
|
}
|
|
98
289
|
|
|
99
290
|
};
|
|
@@ -69,7 +69,9 @@ class SecureLocalStorageRepository extends LocalStorageRepository {
|
|
|
69
69
|
|
|
70
70
|
value = AES.encrypt(value, this.passphrase).toString(); // MOD
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
const result = this._store(name, value);
|
|
73
|
+
this._broadcastStorageChange(name, 'set');
|
|
74
|
+
return result;
|
|
73
75
|
|
|
74
76
|
} catch (error) {
|
|
75
77
|
if (this.debugMode) {
|
|
@@ -47,8 +47,10 @@ class SecureSessionStorageRepository extends SessionStorageRepository {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
value = AES.encrypt(value, this.passphrase).toString(); // MOD
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
|
|
51
|
+
const result = this._store.session(name, value);
|
|
52
|
+
this._broadcastStorageChange(name, 'set');
|
|
53
|
+
return result;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
};
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import OfflineRepository from '@onehat/data/src/Repository/Offline.js';
|
|
4
4
|
import store from 'store2'; // see: https://github.com/nbubna/store#readme
|
|
5
5
|
import _ from 'lodash';
|
|
6
|
+
import { CROSS_TAB_CHANNEL_NAME, CROSS_TAB_MESSAGE_TYPE, CROSS_TAB_EVENT_NAME } from './crossTabConstants.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Repository representing a browser's SessionStorage implementation
|
|
@@ -18,10 +19,136 @@ class SessionStorageRepository extends OfflineRepository {
|
|
|
18
19
|
_.merge(this, config);
|
|
19
20
|
|
|
20
21
|
this._store = store.namespace(this.schema.name);
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
// crossTabSync defaults
|
|
24
|
+
this._crossTabSyncEnabled = config.crossTabSync === true;
|
|
25
|
+
this._crossTabChannelName = config.crossTabChannelName || CROSS_TAB_CHANNEL_NAME;
|
|
26
|
+
this._crossTabChannel = null;
|
|
27
|
+
this._onCrossTabMessageEvent = null;
|
|
28
|
+
|
|
29
|
+
this.registerEvent(CROSS_TAB_EVENT_NAME);
|
|
30
|
+
|
|
22
31
|
if (this._store.isFake()) {
|
|
23
32
|
throw new Error('store2 error: persistent storage not established.');
|
|
24
33
|
}
|
|
34
|
+
|
|
35
|
+
this._setupCrossTabSync();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* _setupCrossTabSync
|
|
40
|
+
*
|
|
41
|
+
* Initialises cross-tab change notification via BroadcastChannel.
|
|
42
|
+
* Unlike LocalStorage, there is no window 'storage' event fallback here because
|
|
43
|
+
* browsers never fire that event for sessionStorage mutations. If BroadcastChannel
|
|
44
|
+
* is unavailable, cross-tab sync simply does nothing.
|
|
45
|
+
*/
|
|
46
|
+
_setupCrossTabSync() {
|
|
47
|
+
if (!this._crossTabSyncEnabled || typeof window === 'undefined') {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (typeof BroadcastChannel === 'undefined') {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
this._crossTabChannel = new BroadcastChannel(this._crossTabChannelName);
|
|
54
|
+
this._onCrossTabMessageEvent = this._handleBroadcastMessage.bind(this);
|
|
55
|
+
this._crossTabChannel.addEventListener('message', this._onCrossTabMessageEvent);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* _teardownCrossTabSync
|
|
60
|
+
*
|
|
61
|
+
* Removes the BroadcastChannel message listener and closes the channel.
|
|
62
|
+
* Called from destroy() to prevent memory leaks and stale handlers.
|
|
63
|
+
*/
|
|
64
|
+
_teardownCrossTabSync() {
|
|
65
|
+
if (this._crossTabChannel) {
|
|
66
|
+
if (this._onCrossTabMessageEvent) {
|
|
67
|
+
this._crossTabChannel.removeEventListener('message', this._onCrossTabMessageEvent);
|
|
68
|
+
this._onCrossTabMessageEvent = null;
|
|
69
|
+
}
|
|
70
|
+
this._crossTabChannel.close();
|
|
71
|
+
this._crossTabChannel = null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* _getNamespacedKey
|
|
77
|
+
*
|
|
78
|
+
* Returns the fully-qualified storage key that store2 uses for a given entry name.
|
|
79
|
+
* store2 namespaces keys with a prefix derived from the schema name, so the raw
|
|
80
|
+
* key and the actual sessionStorage key differ. Broadcasting the namespaced key lets
|
|
81
|
+
* recipients correlate messages with what they see in raw storage APIs.
|
|
82
|
+
*/
|
|
83
|
+
_getNamespacedKey(name) {
|
|
84
|
+
if (!this._store || !_.isFunction(this._store._in)) {
|
|
85
|
+
return name;
|
|
86
|
+
}
|
|
87
|
+
return this._store._in(name);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* _emitCrossTabStorageChange
|
|
92
|
+
*
|
|
93
|
+
* Emits the crossTabStorageChange event on this repository instance.
|
|
94
|
+
* Attaches standard repository identity fields so listeners always know which
|
|
95
|
+
* repository triggered the change, regardless of how many are registered.
|
|
96
|
+
*/
|
|
97
|
+
_emitCrossTabStorageChange(data = {}) {
|
|
98
|
+
this.emit(CROSS_TAB_EVENT_NAME, {
|
|
99
|
+
repositoryId: this.id,
|
|
100
|
+
repositoryName: this.name,
|
|
101
|
+
repositoryType: this.type,
|
|
102
|
+
...data,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* _handleBroadcastMessage
|
|
108
|
+
*
|
|
109
|
+
* Handles an incoming BroadcastChannel message from another tab.
|
|
110
|
+
* Filters out non-storage-change messages, echoes from this same instance,
|
|
111
|
+
* and messages for unrelated repositories, then re-emits the change locally.
|
|
112
|
+
*/
|
|
113
|
+
_handleBroadcastMessage(event) {
|
|
114
|
+
const data = event?.data;
|
|
115
|
+
if (!data || data.type !== CROSS_TAB_MESSAGE_TYPE) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (data.repositoryId === this.id) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (data.repositoryName !== this.name) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this._emitCrossTabStorageChange({
|
|
125
|
+
source: 'broadcast',
|
|
126
|
+
operation: data.operation,
|
|
127
|
+
key: data.key,
|
|
128
|
+
namespacedKey: data.namespacedKey,
|
|
129
|
+
timestamp: data.timestamp,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* _broadcastStorageChange
|
|
135
|
+
*
|
|
136
|
+
* Posts a structured message to the BroadcastChannel so other tabs can react
|
|
137
|
+
* to a sessionStorage mutation made in this tab.
|
|
138
|
+
*/
|
|
139
|
+
_broadcastStorageChange(name, operation) {
|
|
140
|
+
if (!this._crossTabSyncEnabled || !this._crossTabChannel) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
this._crossTabChannel.postMessage({
|
|
144
|
+
type: CROSS_TAB_MESSAGE_TYPE,
|
|
145
|
+
repositoryId: this.id,
|
|
146
|
+
repositoryName: this.name,
|
|
147
|
+
operation,
|
|
148
|
+
key: name || null,
|
|
149
|
+
namespacedKey: _.isNil(name) ? null : this._getNamespacedKey(name),
|
|
150
|
+
timestamp: Date.now(),
|
|
151
|
+
});
|
|
25
152
|
}
|
|
26
153
|
|
|
27
154
|
_storageGetValue(name) {
|
|
@@ -40,15 +167,31 @@ class SessionStorageRepository extends OfflineRepository {
|
|
|
40
167
|
if (!_.isString(value)) {
|
|
41
168
|
value = JSON.stringify(value);
|
|
42
169
|
}
|
|
43
|
-
|
|
170
|
+
const result = this._store.session(name, value);
|
|
171
|
+
this._broadcastStorageChange(name, 'set');
|
|
172
|
+
return result;
|
|
44
173
|
}
|
|
45
174
|
|
|
46
175
|
_storageDeleteValue(name) {
|
|
47
|
-
|
|
176
|
+
const result = this._store.session.remove(name);
|
|
177
|
+
this._broadcastStorageChange(name, 'delete');
|
|
178
|
+
return result;
|
|
48
179
|
}
|
|
49
180
|
|
|
50
181
|
clearAll() {
|
|
51
|
-
|
|
182
|
+
const result = this._store.session.clearAll();
|
|
183
|
+
this._broadcastStorageChange(null, 'clearAll');
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Cleans up cross-tab sync resources before delegating to the parent destroy.
|
|
189
|
+
* Ensures the BroadcastChannel is closed and event listeners are removed so the
|
|
190
|
+
* repository does not continue to react to storage events after disposal.
|
|
191
|
+
*/
|
|
192
|
+
destroy() {
|
|
193
|
+
this._teardownCrossTabSync();
|
|
194
|
+
super.destroy();
|
|
52
195
|
}
|
|
53
196
|
|
|
54
197
|
};
|
package/src/OneHatData.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
v4 as uuid,
|
|
17
17
|
} from 'uuid';
|
|
18
18
|
import _ from 'lodash';
|
|
19
|
+
import { CROSS_TAB_EVENT_NAME } from './Integration/Browser/Repository/crossTabConstants.js';
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* OneHatData represents a collection of Repositories.
|
|
@@ -258,6 +259,9 @@ export class OneHatData extends EventEmitter {
|
|
|
258
259
|
if (repository.isRegisteredEvent('logout')) { // OneBuild repository emits this
|
|
259
260
|
this.relayEventsFrom(repository, ['logout']);
|
|
260
261
|
}
|
|
262
|
+
if (repository.isRegisteredEvent(CROSS_TAB_EVENT_NAME)) {
|
|
263
|
+
this.relayEventsFrom(repository, [CROSS_TAB_EVENT_NAME]);
|
|
264
|
+
}
|
|
261
265
|
|
|
262
266
|
this.emit('createRepository', repository);
|
|
263
267
|
return repository;
|
|
@@ -175,7 +175,7 @@ class OneBuildRepository extends AjaxRepository {
|
|
|
175
175
|
*/
|
|
176
176
|
_getReloadEntityParams(entity) {
|
|
177
177
|
const params = { conditions: {}, };
|
|
178
|
-
params.conditions[entity.
|
|
178
|
+
params.conditions[entity.getModel() + '.id'] = entity.id;
|
|
179
179
|
return params;
|
|
180
180
|
}
|
|
181
181
|
|
|
File without changes
|