@fleetbase/ember-core 0.3.9 → 0.3.11
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/addon/exports/host-services.js +1 -0
- package/addon/exports/services.js +1 -0
- package/addon/library/subject-custom-fields.js +1 -1
- package/addon/services/app-cache.js +2 -1
- package/addon/services/crud.js +19 -0
- package/addon/services/current-user.js +27 -25
- package/addon/services/events.js +322 -0
- package/addon/services/legacy-universe.js +0 -1
- package/addon/services/resource-action.js +18 -0
- package/addon/services/universe/extension-manager.js +8 -7
- package/addon/services/universe/hook-service.js +9 -7
- package/addon/services/universe/registry-service.js +11 -16
- package/addon/services/universe.js +1 -1
- package/addon/utils/inject-engine-service.js +1 -1
- package/app/services/events.js +1 -0
- package/package.json +1 -1
- package/BOOT_SEQUENCE_REFACTOR_GUIDE.md +0 -294
- package/UNIVERSE_REFACTOR_MIGRATION_GUIDE.md +0 -318
- package/UNIVERSE_REFACTOR_README.md +0 -220
|
@@ -242,7 +242,7 @@ export default class SubjectCustomFields {
|
|
|
242
242
|
let existingMany = subject.hasMany?.('custom_field_values')?.value?.() ?? null;
|
|
243
243
|
|
|
244
244
|
// If asked or not loaded, fetch from API (scoped to subject)
|
|
245
|
-
if (reloadExisting || !existingMany) {
|
|
245
|
+
if ((reloadExisting || !existingMany) && subjectId) {
|
|
246
246
|
try {
|
|
247
247
|
existingMany = await this.store.query('custom-field-value', {
|
|
248
248
|
subject_uuid: subjectId,
|
|
@@ -13,7 +13,8 @@ export default class AppCacheService extends Service {
|
|
|
13
13
|
|
|
14
14
|
get cachePrefix() {
|
|
15
15
|
const userId = this.currentUser.id ?? 'anon';
|
|
16
|
-
|
|
16
|
+
const companyId = this.currentUser.companyId ?? 'no-org';
|
|
17
|
+
return `${userId}:${companyId}:`;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
@action setEmberData(key, value, except = []) {
|
package/addon/services/crud.js
CHANGED
|
@@ -17,6 +17,8 @@ export default class CrudService extends Service {
|
|
|
17
17
|
@service notifications;
|
|
18
18
|
@service store;
|
|
19
19
|
@service currentUser;
|
|
20
|
+
@service universe;
|
|
21
|
+
@service events;
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
24
|
* Generic deletion modal with options
|
|
@@ -43,6 +45,10 @@ export default class CrudService extends Service {
|
|
|
43
45
|
try {
|
|
44
46
|
const response = await model.destroyRecord();
|
|
45
47
|
this.notifications.success(successNotification);
|
|
48
|
+
|
|
49
|
+
// Track deletion event
|
|
50
|
+
this.events.trackResourceDeleted(model);
|
|
51
|
+
|
|
46
52
|
if (typeof options.onSuccess === 'function') {
|
|
47
53
|
options.onSuccess(model);
|
|
48
54
|
}
|
|
@@ -161,6 +167,10 @@ export default class CrudService extends Service {
|
|
|
161
167
|
);
|
|
162
168
|
|
|
163
169
|
this.notifications.success(response.message ?? successMessage);
|
|
170
|
+
|
|
171
|
+
// Track bulk action event
|
|
172
|
+
this.events.trackBulkAction(verb, selected);
|
|
173
|
+
|
|
164
174
|
if (typeof options.onSuccess === 'function') {
|
|
165
175
|
options.onSuccess(selected);
|
|
166
176
|
}
|
|
@@ -224,6 +234,9 @@ export default class CrudService extends Service {
|
|
|
224
234
|
}
|
|
225
235
|
)
|
|
226
236
|
.then(() => {
|
|
237
|
+
// Track export event
|
|
238
|
+
this.events.trackResourceExported(modelName, format, exportParams);
|
|
239
|
+
|
|
227
240
|
later(
|
|
228
241
|
this,
|
|
229
242
|
() => {
|
|
@@ -248,6 +261,7 @@ export default class CrudService extends Service {
|
|
|
248
261
|
* @param {Object} [options={}]
|
|
249
262
|
* @memberof CrudService
|
|
250
263
|
*/
|
|
264
|
+
|
|
251
265
|
@action import(modelName, options = {}) {
|
|
252
266
|
// always lowercase modelname
|
|
253
267
|
modelName = modelName.toLowerCase();
|
|
@@ -337,6 +351,11 @@ export default class CrudService extends Service {
|
|
|
337
351
|
|
|
338
352
|
try {
|
|
339
353
|
const response = await this.fetch.post(importEndpoint, { files }, fetchOptions);
|
|
354
|
+
|
|
355
|
+
// Track import event
|
|
356
|
+
const importCount = response?.imported?.length || response?.count || files.length;
|
|
357
|
+
this.events.trackResourceImported(modelName, importCount);
|
|
358
|
+
|
|
340
359
|
if (typeof options.onImportCompleted === 'function') {
|
|
341
360
|
options.onImportCompleted(response, files);
|
|
342
361
|
}
|
|
@@ -16,6 +16,7 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
16
16
|
@service theme;
|
|
17
17
|
@service notifications;
|
|
18
18
|
@service intl;
|
|
19
|
+
@service events;
|
|
19
20
|
|
|
20
21
|
@tracked user = { id: 'anon' };
|
|
21
22
|
@tracked userSnapshot = { id: 'anon' };
|
|
@@ -65,14 +66,9 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
65
66
|
async load() {
|
|
66
67
|
if (this.session.isAuthenticated) {
|
|
67
68
|
const user = await this.store.findRecord('user', 'me');
|
|
68
|
-
const snapshot = await this.getUserSnapshot(user);
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
this.
|
|
72
|
-
this.trigger('user.loaded', user);
|
|
73
|
-
|
|
74
|
-
// Set permissions
|
|
75
|
-
this.permissions = this.getUserPermissions(user);
|
|
70
|
+
// set user
|
|
71
|
+
this.setUser(user);
|
|
76
72
|
|
|
77
73
|
// Load preferences
|
|
78
74
|
await this.loadPreferences();
|
|
@@ -91,25 +87,9 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
91
87
|
|
|
92
88
|
try {
|
|
93
89
|
const user = await this.store.queryRecord('user', { me: true });
|
|
94
|
-
const snapshot = await this.getUserSnapshot(user);
|
|
95
|
-
|
|
96
|
-
// Set current user
|
|
97
|
-
this.set('user', user);
|
|
98
|
-
this.set('userSnapshot', snapshot);
|
|
99
|
-
this.trigger('user.loaded', user);
|
|
100
|
-
|
|
101
|
-
// Set permissions
|
|
102
|
-
this.permissions = this.getUserPermissions(user);
|
|
103
90
|
|
|
104
|
-
//
|
|
105
|
-
this.
|
|
106
|
-
|
|
107
|
-
// Set locale
|
|
108
|
-
if (user.locale) {
|
|
109
|
-
this.setLocale(user.locale);
|
|
110
|
-
} else {
|
|
111
|
-
await this.loadLocale();
|
|
112
|
-
}
|
|
91
|
+
// set user
|
|
92
|
+
this.setUser(user);
|
|
113
93
|
|
|
114
94
|
// Load user whois data
|
|
115
95
|
await this.loadWhois();
|
|
@@ -309,4 +289,26 @@ export default class CurrentUserService extends Service.extend(Evented) {
|
|
|
309
289
|
|
|
310
290
|
return defaultValue;
|
|
311
291
|
}
|
|
292
|
+
|
|
293
|
+
async setUser(user) {
|
|
294
|
+
const snapshot = await this.getUserSnapshot(user);
|
|
295
|
+
|
|
296
|
+
// Set current user
|
|
297
|
+
this.set('user', user);
|
|
298
|
+
this.set('userSnapshot', snapshot);
|
|
299
|
+
this.trigger('user.loaded', user);
|
|
300
|
+
|
|
301
|
+
// Set permissions
|
|
302
|
+
this.permissions = this.getUserPermissions(user);
|
|
303
|
+
|
|
304
|
+
// Set environment from user option
|
|
305
|
+
this.theme.setEnvironment();
|
|
306
|
+
|
|
307
|
+
// Set locale
|
|
308
|
+
if (user.locale) {
|
|
309
|
+
this.setLocale(user.locale);
|
|
310
|
+
} else {
|
|
311
|
+
await this.loadLocale();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
312
314
|
}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import Service, { inject as service } from '@ember/service';
|
|
2
|
+
import Evented from '@ember/object/evented';
|
|
3
|
+
import config from 'ember-get-config';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Events Service
|
|
7
|
+
*
|
|
8
|
+
* Provides a centralized event tracking system for Fleetbase.
|
|
9
|
+
* This service emits standardized events on both its own event bus and the universe service,
|
|
10
|
+
* allowing components, services, and engines to subscribe and react to application events.
|
|
11
|
+
*
|
|
12
|
+
* @class EventsService
|
|
13
|
+
* @extends Service
|
|
14
|
+
*/
|
|
15
|
+
export default class EventsService extends Service.extend(Evented) {
|
|
16
|
+
@service universe;
|
|
17
|
+
@service currentUser;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Tracks the creation of a resource
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} resource - The created resource/model
|
|
23
|
+
* @param {Object} [props={}] - Additional properties to include
|
|
24
|
+
*/
|
|
25
|
+
trackResourceCreated(resource, props = {}) {
|
|
26
|
+
const events = this.#getResourceEvents(resource, 'created');
|
|
27
|
+
const properties = this.#enrichProperties({
|
|
28
|
+
...this.#getSafeProperties(resource),
|
|
29
|
+
...props,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
events.forEach((eventName) => {
|
|
33
|
+
this.#trigger(eventName, resource, properties);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Tracks the update of a resource
|
|
39
|
+
*
|
|
40
|
+
* @param {Object} resource - The updated resource/model
|
|
41
|
+
* @param {Object} [props={}] - Additional properties to include
|
|
42
|
+
*/
|
|
43
|
+
trackResourceUpdated(resource, props = {}) {
|
|
44
|
+
const events = this.#getResourceEvents(resource, 'updated');
|
|
45
|
+
const properties = this.#enrichProperties({
|
|
46
|
+
...this.#getSafeProperties(resource),
|
|
47
|
+
...props,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
events.forEach((eventName) => {
|
|
51
|
+
this.#trigger(eventName, resource, properties);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Tracks the deletion of a resource
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} resource - The deleted resource/model
|
|
59
|
+
* @param {Object} [props={}] - Additional properties to include
|
|
60
|
+
*/
|
|
61
|
+
trackResourceDeleted(resource, props = {}) {
|
|
62
|
+
const events = this.#getResourceEvents(resource, 'deleted');
|
|
63
|
+
const properties = this.#enrichProperties({
|
|
64
|
+
...this.#getSafeProperties(resource),
|
|
65
|
+
...props,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
events.forEach((eventName) => {
|
|
69
|
+
this.#trigger(eventName, resource, properties);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Tracks a bulk import of resources
|
|
75
|
+
*
|
|
76
|
+
* @param {String} modelName - The name of the model being imported
|
|
77
|
+
* @param {Number} count - Number of resources imported
|
|
78
|
+
* @param {Object} [props={}] - Additional properties to include
|
|
79
|
+
*/
|
|
80
|
+
trackResourceImported(modelName, count, props = {}) {
|
|
81
|
+
const properties = this.#enrichProperties({
|
|
82
|
+
model_name: modelName,
|
|
83
|
+
count: count,
|
|
84
|
+
...props,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
this.#trigger('resource.imported', modelName, count, properties);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Tracks a resource export
|
|
92
|
+
*
|
|
93
|
+
* @param {String} modelName - The name of the model being exported
|
|
94
|
+
* @param {String} format - Export format (csv, xlsx, etc.)
|
|
95
|
+
* @param {Object} [params={}] - Export parameters/filters
|
|
96
|
+
* @param {Object} [props={}] - Additional properties to include
|
|
97
|
+
*/
|
|
98
|
+
trackResourceExported(modelName, format, params = {}, props = {}) {
|
|
99
|
+
const properties = this.#enrichProperties({
|
|
100
|
+
model_name: modelName,
|
|
101
|
+
export_format: format,
|
|
102
|
+
has_filters: !!(params && Object.keys(params).length > 0),
|
|
103
|
+
...props,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
this.#trigger('resource.exported', modelName, format, params, properties);
|
|
107
|
+
|
|
108
|
+
// Also trigger model-specific export event
|
|
109
|
+
const specificEvent = `${modelName}.exported`;
|
|
110
|
+
this.#trigger(specificEvent, modelName, format, params, properties);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Tracks a bulk action on multiple resources
|
|
115
|
+
*
|
|
116
|
+
* @param {String} verb - The action verb (delete, archive, etc.)
|
|
117
|
+
* @param {Array} resources - Array of selected resources
|
|
118
|
+
* @param {Object} [props={}] - Additional properties to include
|
|
119
|
+
*/
|
|
120
|
+
trackBulkAction(verb, resources, props = {}) {
|
|
121
|
+
const firstResource = resources && resources.length > 0 ? resources[0] : null;
|
|
122
|
+
const modelName = this.#getModelName(firstResource);
|
|
123
|
+
|
|
124
|
+
const properties = this.#enrichProperties({
|
|
125
|
+
action: verb,
|
|
126
|
+
count: resources?.length || 0,
|
|
127
|
+
model_name: modelName,
|
|
128
|
+
...props,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
this.#trigger('resource.bulk_action', verb, resources, firstResource, properties);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Tracks when the current user is loaded (session initialized)
|
|
136
|
+
*
|
|
137
|
+
* @param {Object} user - The user object
|
|
138
|
+
* @param {Object} organization - The organization object
|
|
139
|
+
* @param {Object} [props={}] - Additional properties to include
|
|
140
|
+
*/
|
|
141
|
+
trackUserLoaded(user, organization, props = {}) {
|
|
142
|
+
const properties = this.#enrichProperties({
|
|
143
|
+
user_id: user?.id,
|
|
144
|
+
organization_id: organization?.id,
|
|
145
|
+
organization_name: organization?.name,
|
|
146
|
+
...props,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
this.#trigger('user.loaded', user, organization, properties);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Tracks when a user session is terminated
|
|
154
|
+
*
|
|
155
|
+
* @param {Number} duration - Session duration in seconds
|
|
156
|
+
* @param {Object} [props={}] - Additional properties to include
|
|
157
|
+
*/
|
|
158
|
+
trackSessionTerminated(duration, props = {}) {
|
|
159
|
+
const properties = this.#enrichProperties({
|
|
160
|
+
session_duration: duration,
|
|
161
|
+
...props,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
this.#trigger('session.terminated', duration, properties);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Tracks a generic custom event
|
|
169
|
+
*
|
|
170
|
+
* @param {String} eventName - The event name (dot notation)
|
|
171
|
+
* @param {Object} [props={}] - Event properties
|
|
172
|
+
*/
|
|
173
|
+
trackEvent(eventName, props = {}) {
|
|
174
|
+
const properties = this.#enrichProperties(props);
|
|
175
|
+
this.#trigger(eventName, properties);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Checks if event tracking is enabled
|
|
180
|
+
*
|
|
181
|
+
* @returns {Boolean}
|
|
182
|
+
*/
|
|
183
|
+
isEnabled() {
|
|
184
|
+
const eventsConfig = config?.events || {};
|
|
185
|
+
return eventsConfig.enabled !== false; // Enabled by default
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// =========================================================================
|
|
189
|
+
// Private Methods (using # syntax)
|
|
190
|
+
// =========================================================================
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Triggers an event on both the events service and universe service
|
|
194
|
+
*
|
|
195
|
+
* This dual event system allows listeners to subscribe to events on either:
|
|
196
|
+
* - this.events.on('event.name', handler) - Local listeners
|
|
197
|
+
* - this.universe.on('event.name', handler) - Cross-engine listeners
|
|
198
|
+
*
|
|
199
|
+
* @private
|
|
200
|
+
* @param {String} eventName - The event name
|
|
201
|
+
* @param {...*} args - Arguments to pass to event listeners
|
|
202
|
+
*/
|
|
203
|
+
#trigger(eventName, ...args) {
|
|
204
|
+
if (!this.isEnabled()) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Debug logging if enabled
|
|
209
|
+
if (config?.events?.debug) {
|
|
210
|
+
console.log(`[Events] ${eventName}`, args);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Trigger on events service (local listeners)
|
|
214
|
+
this.trigger(eventName, ...args);
|
|
215
|
+
|
|
216
|
+
// Trigger on universe service (cross-engine listeners)
|
|
217
|
+
if (this.universe) {
|
|
218
|
+
this.universe.trigger(eventName, ...args);
|
|
219
|
+
} else {
|
|
220
|
+
console.warn('[Events] Universe service not available');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Generates both generic and specific event names for a resource action
|
|
226
|
+
*
|
|
227
|
+
* @private
|
|
228
|
+
* @param {Object} resource - The resource/model
|
|
229
|
+
* @param {String} action - The action (created, updated, deleted)
|
|
230
|
+
* @returns {Array<String>} Array of event names
|
|
231
|
+
*/
|
|
232
|
+
#getResourceEvents(resource, action) {
|
|
233
|
+
const modelName = this.#getModelName(resource);
|
|
234
|
+
return [`resource.${action}`, `${modelName}.${action}`];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Extracts safe, serializable properties from a resource
|
|
239
|
+
*
|
|
240
|
+
* @private
|
|
241
|
+
* @param {Object} resource - The resource/model
|
|
242
|
+
* @returns {Object} Safe properties object
|
|
243
|
+
*/
|
|
244
|
+
#getSafeProperties(resource) {
|
|
245
|
+
if (!resource) {
|
|
246
|
+
return {};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const props = {
|
|
250
|
+
id: resource.id,
|
|
251
|
+
model_name: this.#getModelName(resource),
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// Add common properties if available
|
|
255
|
+
const commonProps = ['name', 'status', 'type', 'slug', 'public_id'];
|
|
256
|
+
commonProps.forEach((prop) => {
|
|
257
|
+
if (resource[prop] !== undefined && resource[prop] !== null) {
|
|
258
|
+
props[prop] = resource[prop];
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
return props;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Enriches properties with user, organization, and timestamp context
|
|
267
|
+
*
|
|
268
|
+
* @private
|
|
269
|
+
* @param {Object} props - Base properties
|
|
270
|
+
* @returns {Object} Enriched properties
|
|
271
|
+
*/
|
|
272
|
+
#enrichProperties(props = {}) {
|
|
273
|
+
const eventsConfig = config?.events || {};
|
|
274
|
+
const enrichConfig = eventsConfig.enrich || {};
|
|
275
|
+
const enriched = { ...props };
|
|
276
|
+
|
|
277
|
+
// Add user context if enabled
|
|
278
|
+
if (enrichConfig.user !== false && this.currentUser?.user) {
|
|
279
|
+
enriched.user_id = this.currentUser.user.id;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Add organization context if enabled
|
|
283
|
+
if (enrichConfig.organization !== false && this.currentUser?.organization) {
|
|
284
|
+
enriched.organization_id = this.currentUser.organization.id;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Add timestamp if enabled
|
|
288
|
+
if (enrichConfig.timestamp !== false) {
|
|
289
|
+
enriched.timestamp = new Date().toISOString();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return enriched;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Safely extracts the model name from a resource
|
|
297
|
+
*
|
|
298
|
+
* @private
|
|
299
|
+
* @param {Object} resource - The resource/model
|
|
300
|
+
* @returns {String} Model name or 'unknown'
|
|
301
|
+
*/
|
|
302
|
+
#getModelName(resource) {
|
|
303
|
+
if (!resource) {
|
|
304
|
+
return 'unknown';
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Try multiple ways to get model name
|
|
308
|
+
if (resource.constructor?.modelName) {
|
|
309
|
+
return resource.constructor.modelName;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (resource._internalModel?.modelName) {
|
|
313
|
+
return resource._internalModel.modelName;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (resource.modelName) {
|
|
317
|
+
return resource.modelName;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return 'unknown';
|
|
321
|
+
}
|
|
322
|
+
}
|
|
@@ -29,6 +29,8 @@ export default class ResourceActionService extends Service {
|
|
|
29
29
|
@service abilities;
|
|
30
30
|
@service tableContext;
|
|
31
31
|
@service resourceContextPanel;
|
|
32
|
+
@service universe;
|
|
33
|
+
@service events;
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Getter for router, attempt to use hostRouter if from engine
|
|
@@ -299,6 +301,9 @@ export default class ResourceActionService extends Service {
|
|
|
299
301
|
})
|
|
300
302
|
);
|
|
301
303
|
|
|
304
|
+
// Track creation event
|
|
305
|
+
this.events.trackResourceCreated(record);
|
|
306
|
+
|
|
302
307
|
if (options.refresh) {
|
|
303
308
|
this.refresh();
|
|
304
309
|
}
|
|
@@ -329,6 +334,9 @@ export default class ResourceActionService extends Service {
|
|
|
329
334
|
})
|
|
330
335
|
);
|
|
331
336
|
|
|
337
|
+
// Track update event
|
|
338
|
+
this.events.trackResourceUpdated(record);
|
|
339
|
+
|
|
332
340
|
if (options.refresh) {
|
|
333
341
|
this.refresh();
|
|
334
342
|
}
|
|
@@ -362,6 +370,13 @@ export default class ResourceActionService extends Service {
|
|
|
362
370
|
})
|
|
363
371
|
);
|
|
364
372
|
|
|
373
|
+
// Track save event (create or update)
|
|
374
|
+
if (isNew) {
|
|
375
|
+
this.events.trackResourceCreated(record);
|
|
376
|
+
} else {
|
|
377
|
+
this.events.trackResourceUpdated(record);
|
|
378
|
+
}
|
|
379
|
+
|
|
365
380
|
if (options.refresh) {
|
|
366
381
|
this.refresh();
|
|
367
382
|
}
|
|
@@ -409,6 +424,9 @@ export default class ResourceActionService extends Service {
|
|
|
409
424
|
})
|
|
410
425
|
);
|
|
411
426
|
|
|
427
|
+
// Track deletion event
|
|
428
|
+
this.events.trackResourceDeleted(record);
|
|
429
|
+
|
|
412
430
|
if (options.refresh) {
|
|
413
431
|
this.refresh();
|
|
414
432
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Service from '@ember/service';
|
|
1
|
+
import Service, { inject as service } from '@ember/service';
|
|
2
2
|
import Evented from '@ember/object/evented';
|
|
3
3
|
import { tracked } from '@glimmer/tracking';
|
|
4
4
|
import { getOwner } from '@ember/application';
|
|
@@ -22,6 +22,7 @@ import ExtensionBootState from '../../contracts/extension-boot-state';
|
|
|
22
22
|
* @extends Service
|
|
23
23
|
*/
|
|
24
24
|
export default class ExtensionManagerService extends Service.extend(Evented) {
|
|
25
|
+
@service universe;
|
|
25
26
|
/**
|
|
26
27
|
* Reference to the root Ember Application Instance.
|
|
27
28
|
* Used for registering components/services to the application container
|
|
@@ -84,14 +85,14 @@ export default class ExtensionManagerService extends Service.extend(Evented) {
|
|
|
84
85
|
* @returns {Application}
|
|
85
86
|
*/
|
|
86
87
|
#getApplication() {
|
|
87
|
-
// First priority
|
|
88
|
-
if (this.applicationInstance) {
|
|
89
|
-
return this.applicationInstance;
|
|
88
|
+
// First priority use the universe application instance
|
|
89
|
+
if (this.universe.applicationInstance) {
|
|
90
|
+
return this.universe.applicationInstance;
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
// Second priority:
|
|
93
|
-
if (
|
|
94
|
-
return
|
|
93
|
+
// Second priority: use applicationInstance if set
|
|
94
|
+
if (this.applicationInstance) {
|
|
95
|
+
return this.applicationInstance;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
// Third priority: try to get application from owner
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Service from '@ember/service';
|
|
1
|
+
import Service, { inject as service } from '@ember/service';
|
|
2
2
|
import { tracked } from '@glimmer/tracking';
|
|
3
3
|
import { getOwner } from '@ember/application';
|
|
4
4
|
import Hook from '../../contracts/hook';
|
|
@@ -14,6 +14,8 @@ import HookRegistry from '../../contracts/hook-registry';
|
|
|
14
14
|
* @extends Service
|
|
15
15
|
*/
|
|
16
16
|
export default class HookService extends Service {
|
|
17
|
+
@service universe;
|
|
18
|
+
|
|
17
19
|
/**
|
|
18
20
|
* Reference to the root Ember Application Instance.
|
|
19
21
|
* Used for registering components/services to the application container
|
|
@@ -69,14 +71,14 @@ export default class HookService extends Service {
|
|
|
69
71
|
* @returns {Application}
|
|
70
72
|
*/
|
|
71
73
|
#getApplication() {
|
|
72
|
-
// First priority
|
|
73
|
-
if (this.applicationInstance) {
|
|
74
|
-
return this.applicationInstance;
|
|
74
|
+
// First priority use the universe application instance
|
|
75
|
+
if (this.universe.applicationInstance) {
|
|
76
|
+
return this.universe.applicationInstance;
|
|
75
77
|
}
|
|
76
78
|
|
|
77
|
-
// Second priority:
|
|
78
|
-
if (
|
|
79
|
-
return
|
|
79
|
+
// Second priority: use applicationInstance if set
|
|
80
|
+
if (this.applicationInstance) {
|
|
81
|
+
return this.applicationInstance;
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
// Third priority: try to get application from owner
|
|
@@ -82,21 +82,16 @@ export default class RegistryService extends Service {
|
|
|
82
82
|
let application = this.applicationInstance;
|
|
83
83
|
|
|
84
84
|
if (!application) {
|
|
85
|
-
// Second priority:
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
// Second priority: try to get from owner
|
|
86
|
+
const owner = getOwner(this);
|
|
87
|
+
if (owner && owner.application) {
|
|
88
|
+
application = owner.application;
|
|
88
89
|
} else {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
warn('[RegistryService] Could not find application instance for registry initialization', {
|
|
95
|
-
id: 'registry-service.no-application',
|
|
96
|
-
});
|
|
97
|
-
// Return a new instance as fallback (won't be shared)
|
|
98
|
-
return new UniverseRegistry();
|
|
99
|
-
}
|
|
90
|
+
warn('[RegistryService] Could not find application instance for registry initialization', {
|
|
91
|
+
id: 'registry-service.no-application',
|
|
92
|
+
});
|
|
93
|
+
// Return a new instance as fallback (won't be shared)
|
|
94
|
+
return new UniverseRegistry();
|
|
100
95
|
}
|
|
101
96
|
}
|
|
102
97
|
|
|
@@ -489,7 +484,7 @@ export default class RegistryService extends Service {
|
|
|
489
484
|
* );
|
|
490
485
|
*/
|
|
491
486
|
async registerHelper(helperName, helperClassOrTemplateHelper, options = {}) {
|
|
492
|
-
const owner = this.applicationInstance ||
|
|
487
|
+
const owner = this.applicationInstance || getOwner(this);
|
|
493
488
|
|
|
494
489
|
if (!owner) {
|
|
495
490
|
warn('No owner available for helper registration. Cannot register helper.', {
|
|
@@ -539,7 +534,7 @@ export default class RegistryService extends Service {
|
|
|
539
534
|
* @returns {Promise<Function|Class|null>} The loaded helper or null if failed
|
|
540
535
|
*/
|
|
541
536
|
async #loadHelperFromEngine(templateHelper) {
|
|
542
|
-
const owner = this.applicationInstance ||
|
|
537
|
+
const owner = this.applicationInstance || getOwner(this);
|
|
543
538
|
|
|
544
539
|
if (!owner) {
|
|
545
540
|
return null;
|