@fleetbase/ember-core 0.2.7 → 0.2.9
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/services/app-cache.js +6 -2
- package/addon/services/chat.js +263 -0
- package/addon/services/socket.js +23 -16
- package/addon/services/universe.js +14 -3
- package/addon/utils/download.js +4 -3
- package/app/services/chat.js +1 -0
- package/package.json +1 -1
|
@@ -38,8 +38,12 @@ export default class AppCacheService extends Service {
|
|
|
38
38
|
return this;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
@action get(key) {
|
|
42
|
-
|
|
41
|
+
@action get(key, defaultValue = null) {
|
|
42
|
+
const value = this.localCache.get(`${this.cachePrefix}${dasherize(key)}`);
|
|
43
|
+
if (value === undefined) {
|
|
44
|
+
return defaultValue;
|
|
45
|
+
}
|
|
46
|
+
return value;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
@action has(key) {
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import Service, { inject as service } from '@ember/service';
|
|
2
|
+
import Evented from '@ember/object/evented';
|
|
3
|
+
import { tracked } from '@glimmer/tracking';
|
|
4
|
+
import { isArray } from '@ember/array';
|
|
5
|
+
import { task } from 'ember-concurrency';
|
|
6
|
+
import { all } from 'rsvp';
|
|
7
|
+
|
|
8
|
+
export default class ChatService extends Service.extend(Evented) {
|
|
9
|
+
@service store;
|
|
10
|
+
@service currentUser;
|
|
11
|
+
@service appCache;
|
|
12
|
+
@tracked channels = [];
|
|
13
|
+
@tracked openChannels = [];
|
|
14
|
+
|
|
15
|
+
openChannel(chatChannelRecord) {
|
|
16
|
+
if (this.openChannels.includes(chatChannelRecord)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
this.openChannels.pushObject(chatChannelRecord);
|
|
20
|
+
this.rememberOpenedChannel(chatChannelRecord);
|
|
21
|
+
this.trigger('chat.opened', chatChannelRecord);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
closeChannel(chatChannelRecord) {
|
|
25
|
+
const index = this.openChannels.findIndex((_) => _.id === chatChannelRecord.id);
|
|
26
|
+
if (index >= 0) {
|
|
27
|
+
this.openChannels.removeAt(index);
|
|
28
|
+
this.trigger('chat.closed', chatChannelRecord);
|
|
29
|
+
}
|
|
30
|
+
this.forgetOpenedChannel(chatChannelRecord);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
rememberOpenedChannel(chatChannelRecord) {
|
|
34
|
+
let openedChats = this.appCache.get('open-chats', []);
|
|
35
|
+
if (isArray(openedChats) && !openedChats.includes(chatChannelRecord.id)) {
|
|
36
|
+
openedChats.pushObject(chatChannelRecord.id);
|
|
37
|
+
} else {
|
|
38
|
+
openedChats = [chatChannelRecord.id];
|
|
39
|
+
}
|
|
40
|
+
this.appCache.set('open-chats', openedChats);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
forgetOpenedChannel(chatChannelRecord) {
|
|
44
|
+
let openedChats = this.appCache.get('open-chats', []);
|
|
45
|
+
if (isArray(openedChats)) {
|
|
46
|
+
openedChats.removeObject(chatChannelRecord.id);
|
|
47
|
+
} else {
|
|
48
|
+
openedChats = [];
|
|
49
|
+
}
|
|
50
|
+
this.appCache.set('open-chats', openedChats);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
restoreOpenedChats() {
|
|
54
|
+
const openedChats = this.appCache.get('open-chats', []);
|
|
55
|
+
if (isArray(openedChats)) {
|
|
56
|
+
const findAll = openedChats.map((id) => this.store.findRecord('chat-channel', id));
|
|
57
|
+
return all(findAll).then((openedChatRecords) => {
|
|
58
|
+
if (isArray(openedChatRecords)) {
|
|
59
|
+
for (let i = 0; i < openedChatRecords.length; i++) {
|
|
60
|
+
const chatChannelRecord = openedChatRecords[i];
|
|
61
|
+
this.openChannel(chatChannelRecord);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return openedChatRecords;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getOpenChannels() {
|
|
72
|
+
return this.openChannels;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
createChatChannel(name) {
|
|
76
|
+
const chatChannelRecord = this.store.createRecord('chat-channel', { name });
|
|
77
|
+
return chatChannelRecord.save().finally(() => {
|
|
78
|
+
this.trigger('chat.created', chatChannelRecord);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
deleteChatChannel(chatChannelRecord) {
|
|
83
|
+
return chatChannelRecord.destroyRecord().finally(() => {
|
|
84
|
+
this.trigger('chat.deleted', chatChannelRecord);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
updateChatChannel(chatChannelRecord, props = {}) {
|
|
89
|
+
chatChannelRecord.setProperties(props);
|
|
90
|
+
return chatChannelRecord.save().finally(() => {
|
|
91
|
+
this.trigger('chat.updated', chatChannelRecord);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
addParticipant(chatChannelRecord, userRecord) {
|
|
96
|
+
const chatParticipant = this.store.createRecord('chat-participant', {
|
|
97
|
+
chat_channel_uuid: chatChannelRecord.id,
|
|
98
|
+
user_uuid: userRecord.id,
|
|
99
|
+
});
|
|
100
|
+
return chatParticipant.save().finally(() => {
|
|
101
|
+
this.trigger('chat.added_participant', chatParticipant, chatChannelRecord);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
removeParticipant(chatChannelRecord, chatParticipant) {
|
|
106
|
+
return chatParticipant.destroyRecord().finally(() => {
|
|
107
|
+
this.trigger('chat.removed_participant', chatParticipant, chatChannelRecord);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async sendMessage(chatChannelRecord, senderRecord, messageContent = '', attachments = []) {
|
|
112
|
+
const chatMessage = this.store.createRecord('chat-message', {
|
|
113
|
+
chat_channel_uuid: chatChannelRecord.id,
|
|
114
|
+
sender_uuid: senderRecord.id,
|
|
115
|
+
content: messageContent,
|
|
116
|
+
attachment_files: attachments,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return chatMessage
|
|
120
|
+
.save()
|
|
121
|
+
.then((chatMessageRecord) => {
|
|
122
|
+
if (chatChannelRecord.doesntExistsInFeed('message', chatMessageRecord)) {
|
|
123
|
+
chatChannelRecord.feed.pushObject({
|
|
124
|
+
type: 'message',
|
|
125
|
+
created_at: chatMessageRecord.created_at,
|
|
126
|
+
data: chatMessageRecord.serialize(),
|
|
127
|
+
record: chatMessageRecord,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return chatMessageRecord;
|
|
131
|
+
})
|
|
132
|
+
.finally(() => {
|
|
133
|
+
this.trigger('chat.feed_updated', chatMessage, chatChannelRecord);
|
|
134
|
+
this.trigger('chat.message_created', chatMessage, chatChannelRecord);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
deleteMessage(chatMessageRecord) {
|
|
139
|
+
return chatMessageRecord.destroyRecord().finally(() => {
|
|
140
|
+
this.trigger('chat.feed_updated', chatMessageRecord);
|
|
141
|
+
this.trigger('chat.message_deleted', chatMessageRecord);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
insertChatMessageFromSocket(chatChannelRecord, data) {
|
|
146
|
+
// normalize and create record
|
|
147
|
+
const normalized = this.store.normalize('chat-message', data);
|
|
148
|
+
const record = this.store.push(normalized);
|
|
149
|
+
|
|
150
|
+
// make sure it doesn't exist in feed already
|
|
151
|
+
if (chatChannelRecord.existsInFeed('message', record)) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// create feed item
|
|
156
|
+
const item = {
|
|
157
|
+
type: 'message',
|
|
158
|
+
created_at: record.created_at,
|
|
159
|
+
data,
|
|
160
|
+
record,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// add item to feed
|
|
164
|
+
chatChannelRecord.feed.pushObject(item);
|
|
165
|
+
|
|
166
|
+
// trigger event
|
|
167
|
+
this.trigger('chat.feed_updated', record, chatChannelRecord);
|
|
168
|
+
this.trigger('chat.message_created', record, chatChannelRecord);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
insertChatLogFromSocket(chatChannelRecord, data) {
|
|
172
|
+
// normalize and create record
|
|
173
|
+
const normalized = this.store.normalize('chat-log', data);
|
|
174
|
+
const record = this.store.push(normalized);
|
|
175
|
+
|
|
176
|
+
// make sure it doesn't exist in feed already
|
|
177
|
+
if (chatChannelRecord.existsInFeed('log', record)) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// create feed item
|
|
182
|
+
const item = {
|
|
183
|
+
type: 'log',
|
|
184
|
+
created_at: record.created_at,
|
|
185
|
+
data,
|
|
186
|
+
record,
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// add item to feed
|
|
190
|
+
chatChannelRecord.feed.pushObject(item);
|
|
191
|
+
|
|
192
|
+
// trigger event
|
|
193
|
+
this.trigger('chat.feed_updated', record, chatChannelRecord);
|
|
194
|
+
this.trigger('chat.log_created', record, chatChannelRecord);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
insertChatAttachmentFromSocket(chatChannelRecord, data) {
|
|
198
|
+
// normalize and create record
|
|
199
|
+
const normalized = this.store.normalize('chat-attachment', data);
|
|
200
|
+
const record = this.store.push(normalized);
|
|
201
|
+
|
|
202
|
+
// Find the chat message the record belongs to in the feed
|
|
203
|
+
const chatMessage = chatChannelRecord.feed.find((item) => {
|
|
204
|
+
return item.type === 'message' && item.record.id === record.chat_message_uuid;
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// If we have the chat message then we can insert it to attachments
|
|
208
|
+
// This should work because chat message will always be created before the chat attachment
|
|
209
|
+
if (chatMessage) {
|
|
210
|
+
// Make sure the attachment isn't already attached to the message
|
|
211
|
+
const isNotAttached = chatMessage.record.attachments.find((attachment) => attachment.id === record.id) === undefined;
|
|
212
|
+
if (isNotAttached) {
|
|
213
|
+
chatMessage.record.attachments.pushObject(record);
|
|
214
|
+
// trigger event
|
|
215
|
+
this.trigger('chat.feed_updated', record, chatChannelRecord);
|
|
216
|
+
this.trigger('chat.attachment_created', record, chatChannelRecord);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
insertChatReceiptFromSocket(chatChannelRecord, data) {
|
|
222
|
+
// normalize and create record
|
|
223
|
+
const normalized = this.store.normalize('chat-receipt', data);
|
|
224
|
+
const record = this.store.push(normalized);
|
|
225
|
+
|
|
226
|
+
// Find the chat message the record belongs to in the feed
|
|
227
|
+
const chatMessage = chatChannelRecord.feed.find((item) => {
|
|
228
|
+
return item.type === 'message' && item.record.id === record.chat_message_uuid;
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// If we have the chat message then we can insert it to receipts
|
|
232
|
+
// This should work because chat message will always be created before the chat receipt
|
|
233
|
+
if (chatMessage) {
|
|
234
|
+
// Make sure the receipt isn't already attached to the message
|
|
235
|
+
const isNotAttached = chatMessage.record.receipts.find((receipt) => receipt.id === record.id) === undefined;
|
|
236
|
+
if (isNotAttached) {
|
|
237
|
+
chatMessage.record.receipts.pushObject(record);
|
|
238
|
+
// trigger event
|
|
239
|
+
this.trigger('chat.receipt_created', record, chatChannelRecord);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
@task *loadMessages(chatChannelRecord) {
|
|
245
|
+
const messages = yield this.store.query('chat-message', { chat_channel_uuid: chatChannelRecord.id });
|
|
246
|
+
chatChannelRecord.set('messages', messages);
|
|
247
|
+
return messages;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
@task *loadChannels(options = {}) {
|
|
251
|
+
const params = options.params || {};
|
|
252
|
+
const channels = yield this.store.query('chat-channel', params);
|
|
253
|
+
if (isArray(channels)) {
|
|
254
|
+
this.channels = channels;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (typeof options.withChannels === 'function') {
|
|
258
|
+
options.withChannels(channels);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return channels;
|
|
262
|
+
}
|
|
263
|
+
}
|
package/addon/services/socket.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Service from '@ember/service';
|
|
2
2
|
import { tracked } from '@glimmer/tracking';
|
|
3
3
|
import { isBlank } from '@ember/utils';
|
|
4
|
+
import { later } from '@ember/runloop';
|
|
4
5
|
import toBoolean from '../utils/to-boolean';
|
|
5
6
|
import config from 'ember-get-config';
|
|
6
7
|
|
|
@@ -29,22 +30,28 @@ export default class SocketService extends Service {
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
async listen(channelId, callback) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
later(
|
|
34
|
+
this,
|
|
35
|
+
async () => {
|
|
36
|
+
const channel = this.socket.subscribe(channelId);
|
|
37
|
+
|
|
38
|
+
// Track channel
|
|
39
|
+
this.channels.pushObject(channel);
|
|
40
|
+
|
|
41
|
+
// Listen to channel for events
|
|
42
|
+
await channel.listener('subscribe').once();
|
|
43
|
+
|
|
44
|
+
// Listen for channel subscription
|
|
45
|
+
(async () => {
|
|
46
|
+
for await (let output of channel) {
|
|
47
|
+
if (typeof callback === 'function') {
|
|
48
|
+
callback(output);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
})();
|
|
52
|
+
},
|
|
53
|
+
300
|
|
54
|
+
);
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
closeChannels() {
|
|
@@ -592,10 +592,15 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
592
592
|
|
|
593
593
|
// register to registry
|
|
594
594
|
const internalRegistryName = this.createInternalRegistryName(registryName);
|
|
595
|
-
if (
|
|
596
|
-
this[internalRegistryName].renderableComponents
|
|
595
|
+
if (!isBlank(this[internalRegistryName])) {
|
|
596
|
+
if (isArray(this[internalRegistryName].renderableComponents)) {
|
|
597
|
+
this[internalRegistryName].renderableComponents.pushObject(component);
|
|
598
|
+
} else {
|
|
599
|
+
this[internalRegistryName].renderableComponents = [component];
|
|
600
|
+
}
|
|
597
601
|
} else {
|
|
598
|
-
this
|
|
602
|
+
this.createRegistry(registryName);
|
|
603
|
+
return this.registerRenderableComponent(...arguments);
|
|
599
604
|
}
|
|
600
605
|
}
|
|
601
606
|
|
|
@@ -988,7 +993,10 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
988
993
|
const index = this._getOption(options, 'index', 0);
|
|
989
994
|
const onClick = this._getOption(options, 'onClick', null);
|
|
990
995
|
const section = this._getOption(options, 'section', null);
|
|
996
|
+
const iconComponent = this._getOption(options, 'iconComponent', null);
|
|
997
|
+
const iconComponentOptions = this._getOption(options, 'iconComponentOptions', {});
|
|
991
998
|
const iconSize = this._getOption(options, 'iconSize', null);
|
|
999
|
+
const iconPrefix = this._getOption(options, 'iconPrefix', null);
|
|
992
1000
|
const iconClass = this._getOption(options, 'iconClass', null);
|
|
993
1001
|
const itemClass = this._getOption(options, 'class', null);
|
|
994
1002
|
const inlineClass = this._getOption(options, 'inlineClass', null);
|
|
@@ -1019,7 +1027,10 @@ export default class UniverseService extends Service.extend(Evented) {
|
|
|
1019
1027
|
index,
|
|
1020
1028
|
section,
|
|
1021
1029
|
onClick,
|
|
1030
|
+
iconComponent,
|
|
1031
|
+
iconComponentOptions,
|
|
1022
1032
|
iconSize,
|
|
1033
|
+
iconPrefix,
|
|
1023
1034
|
iconClass,
|
|
1024
1035
|
class: itemClass,
|
|
1025
1036
|
inlineClass,
|
package/addon/utils/download.js
CHANGED
|
@@ -91,10 +91,11 @@ export default function download(data, strFileName, strMimeType) {
|
|
|
91
91
|
anchor.className = 'download-js-link';
|
|
92
92
|
anchor.innerHTML = 'downloading...';
|
|
93
93
|
anchor.style.display = 'none';
|
|
94
|
-
|
|
94
|
+
function handleClick(e) {
|
|
95
95
|
e.stopPropagation();
|
|
96
|
-
|
|
97
|
-
}
|
|
96
|
+
anchor.removeEventListener('click', handleClick);
|
|
97
|
+
}
|
|
98
|
+
anchor.addEventListener('click', handleClick);
|
|
98
99
|
document.body.appendChild(anchor);
|
|
99
100
|
later(
|
|
100
101
|
this,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/ember-core/services/chat';
|
package/package.json
CHANGED