doover-js 0.4.4 → 0.4.6
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.
|
@@ -39,10 +39,270 @@ const helpers_1 = require("./helpers");
|
|
|
39
39
|
await (0, chai_1.expect)(provider.getMe()).to.eventually.deep.equal({ id: "u1" });
|
|
40
40
|
await (0, chai_1.expect)(provider.getAgents()).to.eventually.deep.equal({ agents: [] });
|
|
41
41
|
(0, chai_1.expect)(fetchMock.getCall(0).args[0]).to.equal("https://control.example.com/users/me");
|
|
42
|
-
(0, chai_1.expect)(fetchMock.getCall(1).args[0]).to.equal("https://control.example.com/agents");
|
|
42
|
+
(0, chai_1.expect)(fetchMock.getCall(1).args[0]).to.equal("https://control.example.com/agents/");
|
|
43
43
|
(0, chai_1.expect)((fetchMock.getCall(0).args[1]?.headers).get("X-Doover-Sharing")).to.equal("internal");
|
|
44
44
|
(0, chai_1.expect)((fetchMock.getCall(1).args[1]?.headers).get("X-Doover-Sharing")).to.equal(null);
|
|
45
45
|
});
|
|
46
|
+
(0, mocha_1.it)("getAgents forwards include-archived/include-organisations/include-users query keys", async () => {
|
|
47
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)({ agents: [], organisations: [], users: [] }));
|
|
48
|
+
const provider = new doover_data_provider_1.DooverDataProvider({
|
|
49
|
+
dataRestUrl: "https://api.example.com",
|
|
50
|
+
controlApiUrl: "https://control.example.com",
|
|
51
|
+
dataWssUrl: "wss://ws.example.com",
|
|
52
|
+
fetchImpl: fetchMock,
|
|
53
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
54
|
+
});
|
|
55
|
+
await provider.getAgents({
|
|
56
|
+
includeArchived: true,
|
|
57
|
+
includeOrganisations: true,
|
|
58
|
+
includeUsers: true,
|
|
59
|
+
});
|
|
60
|
+
const url = fetchMock.getCall(0).args[0];
|
|
61
|
+
(0, chai_1.expect)(url.startsWith("https://control.example.com/agents/?")).to.equal(true);
|
|
62
|
+
(0, chai_1.expect)(url).to.include("include-archived=true");
|
|
63
|
+
(0, chai_1.expect)(url).to.include("include-organisations=true");
|
|
64
|
+
(0, chai_1.expect)(url).to.include("include-users=true");
|
|
65
|
+
});
|
|
66
|
+
(0, mocha_1.it)("getAgents preserves raw organisations/users without merging by default", async () => {
|
|
67
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)({
|
|
68
|
+
agents: [
|
|
69
|
+
{
|
|
70
|
+
id: "a1",
|
|
71
|
+
name: "agent-1",
|
|
72
|
+
display_name: "Agent 1",
|
|
73
|
+
type: "device",
|
|
74
|
+
organisation: "Org 1",
|
|
75
|
+
group: "g",
|
|
76
|
+
archived: false,
|
|
77
|
+
fa_icon: "fa-solid fa-robot",
|
|
78
|
+
fixed_location: { latitude: 1, longitude: 2 },
|
|
79
|
+
extra_config: {},
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
organisations: [{ id: "o1", name: "Org 1" }],
|
|
83
|
+
users: [{ id: "u1", username: "alice" }],
|
|
84
|
+
}));
|
|
85
|
+
const provider = new doover_data_provider_1.DooverDataProvider({
|
|
86
|
+
dataRestUrl: "https://api.example.com",
|
|
87
|
+
controlApiUrl: "https://control.example.com",
|
|
88
|
+
dataWssUrl: "wss://ws.example.com",
|
|
89
|
+
fetchImpl: fetchMock,
|
|
90
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
91
|
+
});
|
|
92
|
+
const result = await provider.getAgents({
|
|
93
|
+
includeOrganisations: true,
|
|
94
|
+
includeUsers: true,
|
|
95
|
+
});
|
|
96
|
+
(0, chai_1.expect)(result.agents).to.have.lengthOf(1);
|
|
97
|
+
(0, chai_1.expect)(result.agents?.[0].id).to.equal("a1");
|
|
98
|
+
(0, chai_1.expect)(result.organisations).to.deep.equal([{ id: "o1", name: "Org 1" }]);
|
|
99
|
+
(0, chai_1.expect)(result.users).to.deep.equal([{ id: "u1", username: "alice" }]);
|
|
100
|
+
(0, chai_1.expect)(result.results).to.equal(undefined);
|
|
101
|
+
(0, chai_1.expect)(result.count).to.equal(undefined);
|
|
102
|
+
});
|
|
103
|
+
(0, mocha_1.it)("getAgents merges normalized organisations and users when mergeIncludedAsAgents is true", async () => {
|
|
104
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)({
|
|
105
|
+
agents: [
|
|
106
|
+
{
|
|
107
|
+
id: "a1",
|
|
108
|
+
name: "agent-1",
|
|
109
|
+
display_name: "Agent 1",
|
|
110
|
+
type: "device",
|
|
111
|
+
organisation: "Org 1",
|
|
112
|
+
group: "g",
|
|
113
|
+
archived: false,
|
|
114
|
+
fa_icon: "fa-solid fa-robot",
|
|
115
|
+
fixed_location: { latitude: 1, longitude: 2 },
|
|
116
|
+
extra_config: { foo: "bar" },
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
organisations: [
|
|
120
|
+
{
|
|
121
|
+
id: "o1",
|
|
122
|
+
name: "Org One",
|
|
123
|
+
archived: false,
|
|
124
|
+
root_group: { name: "root" },
|
|
125
|
+
extra_config: { level: "premium" },
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
users: [
|
|
129
|
+
{
|
|
130
|
+
id: "u1",
|
|
131
|
+
username: "alice",
|
|
132
|
+
email: "alice@example.com",
|
|
133
|
+
first_name: "Alice",
|
|
134
|
+
last_name: "Anderson",
|
|
135
|
+
custom_data: { theme: "dark" },
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
}));
|
|
139
|
+
const provider = new doover_data_provider_1.DooverDataProvider({
|
|
140
|
+
dataRestUrl: "https://api.example.com",
|
|
141
|
+
controlApiUrl: "https://control.example.com",
|
|
142
|
+
dataWssUrl: "wss://ws.example.com",
|
|
143
|
+
fetchImpl: fetchMock,
|
|
144
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
145
|
+
});
|
|
146
|
+
const result = await provider.getAgents({
|
|
147
|
+
includeOrganisations: true,
|
|
148
|
+
includeUsers: true,
|
|
149
|
+
mergeIncludedAsAgents: true,
|
|
150
|
+
});
|
|
151
|
+
(0, chai_1.expect)(result.agents).to.have.lengthOf(3);
|
|
152
|
+
(0, chai_1.expect)(result.results).to.equal(result.agents);
|
|
153
|
+
(0, chai_1.expect)(result.count).to.equal(3);
|
|
154
|
+
const [agent, organisation, user] = result.agents;
|
|
155
|
+
(0, chai_1.expect)(agent.id).to.equal("a1");
|
|
156
|
+
(0, chai_1.expect)(agent.type).to.equal("device");
|
|
157
|
+
(0, chai_1.expect)(organisation).to.deep.equal({
|
|
158
|
+
id: "o1",
|
|
159
|
+
organisation: "Org One",
|
|
160
|
+
name: "Org One",
|
|
161
|
+
display_name: "Org One",
|
|
162
|
+
archived: false,
|
|
163
|
+
group: "root",
|
|
164
|
+
fa_icon: "fa-solid fa-building",
|
|
165
|
+
type: "organisation",
|
|
166
|
+
fixed_location: { latitude: 0, longitude: 0 },
|
|
167
|
+
extra_config: { level: "premium" },
|
|
168
|
+
});
|
|
169
|
+
(0, chai_1.expect)(user).to.deep.equal({
|
|
170
|
+
id: "u1",
|
|
171
|
+
organisation: "",
|
|
172
|
+
name: "alice",
|
|
173
|
+
display_name: "Alice Anderson",
|
|
174
|
+
archived: false,
|
|
175
|
+
group: "",
|
|
176
|
+
fa_icon: "fa-solid fa-user",
|
|
177
|
+
type: "user",
|
|
178
|
+
fixed_location: { latitude: 0, longitude: 0 },
|
|
179
|
+
extra_config: { theme: "dark" },
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
(0, mocha_1.it)("getAgents merge respects includeOrganisations/includeUsers flags", async () => {
|
|
183
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)({
|
|
184
|
+
agents: [
|
|
185
|
+
{
|
|
186
|
+
id: "a1",
|
|
187
|
+
name: "a1",
|
|
188
|
+
display_name: "a1",
|
|
189
|
+
type: "device",
|
|
190
|
+
organisation: "o",
|
|
191
|
+
group: "g",
|
|
192
|
+
archived: false,
|
|
193
|
+
fa_icon: "fa-solid fa-robot",
|
|
194
|
+
fixed_location: { latitude: 0, longitude: 0 },
|
|
195
|
+
extra_config: {},
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
organisations: [{ id: "o1", name: "Org 1" }],
|
|
199
|
+
users: [{ id: "u1", username: "alice" }],
|
|
200
|
+
}));
|
|
201
|
+
const provider = new doover_data_provider_1.DooverDataProvider({
|
|
202
|
+
dataRestUrl: "https://api.example.com",
|
|
203
|
+
controlApiUrl: "https://control.example.com",
|
|
204
|
+
dataWssUrl: "wss://ws.example.com",
|
|
205
|
+
fetchImpl: fetchMock,
|
|
206
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
207
|
+
});
|
|
208
|
+
const result = await provider.getAgents({
|
|
209
|
+
includeOrganisations: false,
|
|
210
|
+
includeUsers: true,
|
|
211
|
+
mergeIncludedAsAgents: true,
|
|
212
|
+
});
|
|
213
|
+
(0, chai_1.expect)(result.agents).to.have.lengthOf(2);
|
|
214
|
+
(0, chai_1.expect)(result.agents?.map((entry) => entry.type)).to.deep.equal([
|
|
215
|
+
"device",
|
|
216
|
+
"user",
|
|
217
|
+
]);
|
|
218
|
+
(0, chai_1.expect)(result.count).to.equal(2);
|
|
219
|
+
});
|
|
220
|
+
(0, mocha_1.it)("getAgents user display_name falls back through full name, username, email, id", async () => {
|
|
221
|
+
let payload = {};
|
|
222
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)(payload));
|
|
223
|
+
const provider = new doover_data_provider_1.DooverDataProvider({
|
|
224
|
+
dataRestUrl: "https://api.example.com",
|
|
225
|
+
controlApiUrl: "https://control.example.com",
|
|
226
|
+
dataWssUrl: "wss://ws.example.com",
|
|
227
|
+
fetchImpl: fetchMock,
|
|
228
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
229
|
+
});
|
|
230
|
+
payload = {
|
|
231
|
+
agents: [],
|
|
232
|
+
users: [
|
|
233
|
+
{
|
|
234
|
+
id: "u-full",
|
|
235
|
+
username: "alice",
|
|
236
|
+
email: "alice@example.com",
|
|
237
|
+
first_name: "Alice",
|
|
238
|
+
last_name: "Anderson",
|
|
239
|
+
},
|
|
240
|
+
{ id: "u-username", username: "bob", email: "bob@example.com" },
|
|
241
|
+
{ id: "u-email", email: "carol@example.com" },
|
|
242
|
+
{ id: "u-id-only" },
|
|
243
|
+
],
|
|
244
|
+
};
|
|
245
|
+
const result = await provider.getAgents({
|
|
246
|
+
includeUsers: true,
|
|
247
|
+
mergeIncludedAsAgents: true,
|
|
248
|
+
});
|
|
249
|
+
const merged = result.agents ?? [];
|
|
250
|
+
(0, chai_1.expect)(merged.map((entry) => entry.display_name)).to.deep.equal([
|
|
251
|
+
"Alice Anderson",
|
|
252
|
+
"bob",
|
|
253
|
+
"carol@example.com",
|
|
254
|
+
"u-id-only",
|
|
255
|
+
]);
|
|
256
|
+
(0, chai_1.expect)(merged.map((entry) => entry.name)).to.deep.equal([
|
|
257
|
+
"alice",
|
|
258
|
+
"bob",
|
|
259
|
+
"carol@example.com",
|
|
260
|
+
"u-id-only",
|
|
261
|
+
]);
|
|
262
|
+
});
|
|
263
|
+
(0, mocha_1.it)("getAgents fills agent defaults when fa_icon, fixed_location, or extra_config are missing/null", async () => {
|
|
264
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)({
|
|
265
|
+
agents: [
|
|
266
|
+
{
|
|
267
|
+
id: "a1",
|
|
268
|
+
name: "a1",
|
|
269
|
+
display_name: "a1",
|
|
270
|
+
type: "device",
|
|
271
|
+
organisation: "o",
|
|
272
|
+
group: "g",
|
|
273
|
+
archived: false,
|
|
274
|
+
fa_icon: null,
|
|
275
|
+
fixed_location: null,
|
|
276
|
+
extra_config: null,
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
id: "a2",
|
|
280
|
+
name: "a2",
|
|
281
|
+
display_name: "a2",
|
|
282
|
+
type: "device",
|
|
283
|
+
organisation: "o",
|
|
284
|
+
group: "g",
|
|
285
|
+
archived: false,
|
|
286
|
+
// fa_icon, fixed_location, extra_config all missing
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
}));
|
|
290
|
+
const provider = new doover_data_provider_1.DooverDataProvider({
|
|
291
|
+
dataRestUrl: "https://api.example.com",
|
|
292
|
+
controlApiUrl: "https://control.example.com",
|
|
293
|
+
dataWssUrl: "wss://ws.example.com",
|
|
294
|
+
fetchImpl: fetchMock,
|
|
295
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
296
|
+
});
|
|
297
|
+
const result = await provider.getAgents();
|
|
298
|
+
const [withNulls, withMissing] = result.agents ?? [];
|
|
299
|
+
(0, chai_1.expect)(withNulls.fa_icon).to.equal("fa-solid fa-robot");
|
|
300
|
+
(0, chai_1.expect)(withNulls.fixed_location).to.deep.equal({ latitude: 0, longitude: 0 });
|
|
301
|
+
(0, chai_1.expect)(withNulls.extra_config).to.deep.equal({});
|
|
302
|
+
(0, chai_1.expect)(withMissing.fa_icon).to.equal("fa-solid fa-robot");
|
|
303
|
+
(0, chai_1.expect)(withMissing.fixed_location).to.deep.equal({ latitude: 0, longitude: 0 });
|
|
304
|
+
(0, chai_1.expect)(withMissing.extra_config).to.deep.equal({});
|
|
305
|
+
});
|
|
46
306
|
(0, mocha_1.it)("returns undefined for missing identifiers where expected", async () => {
|
|
47
307
|
const fetchMock = (0, helpers_1.createFetchMock)();
|
|
48
308
|
const provider = new doover_data_provider_1.DooverDataProvider({
|
package/dist/types/viewer.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export interface Agent {
|
|
|
12
12
|
archived: boolean;
|
|
13
13
|
group: string;
|
|
14
14
|
fa_icon: string;
|
|
15
|
-
type: "device" | "dashboard";
|
|
15
|
+
type: "device" | "dashboard" | "organisation" | "user";
|
|
16
16
|
fixed_location: {
|
|
17
17
|
latitude: number;
|
|
18
18
|
longitude: number;
|
|
@@ -26,6 +26,18 @@ export interface User {
|
|
|
26
26
|
name?: string;
|
|
27
27
|
[key: string]: unknown;
|
|
28
28
|
}
|
|
29
|
+
export interface GetAgentsOptions {
|
|
30
|
+
includeArchived?: boolean;
|
|
31
|
+
includeOrganisations?: boolean;
|
|
32
|
+
includeUsers?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* When `true`, normalized organisations and users are appended into the
|
|
35
|
+
* canonical `agents` list (and mirrored to `results` / `count`). Defaults
|
|
36
|
+
* to `false`, which preserves the legacy behaviour of returning only the
|
|
37
|
+
* raw `agents` array.
|
|
38
|
+
*/
|
|
39
|
+
mergeIncludedAsAgents?: boolean;
|
|
40
|
+
}
|
|
29
41
|
export interface AgentsResponse {
|
|
30
42
|
agents?: Agent[];
|
|
31
43
|
results?: Agent[];
|
|
@@ -42,7 +54,7 @@ export interface SubscriptionDetails {
|
|
|
42
54
|
}
|
|
43
55
|
export interface ChannelsDataProvider<TIdentifier extends ChannelIdentifier = ChannelIdentifier> {
|
|
44
56
|
getMe: () => Promise<User>;
|
|
45
|
-
getAgents: () => Promise<AgentsResponse>;
|
|
57
|
+
getAgents: (options?: GetAgentsOptions) => Promise<AgentsResponse>;
|
|
46
58
|
getChannels: (identifier: TIdentifier, options?: {
|
|
47
59
|
includeArchived?: boolean;
|
|
48
60
|
}) => Promise<Channel[] | undefined>;
|
|
@@ -7,7 +7,7 @@ import type { DooverAuth } from "../auth/doover-auth";
|
|
|
7
7
|
import { GatewayClient } from "../gateway/gateway-client";
|
|
8
8
|
import { RestClient, type DooverClientConfig } from "../http/rest-client";
|
|
9
9
|
import type { Aggregate, Channel, ConnectionDetails, JSONValue, MessageStructure, RpcRequest, RpcStatus } from "../types/common";
|
|
10
|
-
import type { Agent, AgentsResponse, ChannelIdentifier, ChannelsDataProvider, SubscriptionDetails, User } from "../types/viewer";
|
|
10
|
+
import type { Agent, AgentsResponse, ChannelIdentifier, ChannelsDataProvider, GetAgentsOptions, SubscriptionDetails, User } from "../types/viewer";
|
|
11
11
|
interface SubscriptionEntry {
|
|
12
12
|
messageCallback: (identifier: ChannelIdentifier, message: MessageStructure) => void;
|
|
13
13
|
aggregateCallback: (identifier: ChannelIdentifier, aggregate: Aggregate) => void;
|
|
@@ -30,7 +30,7 @@ export declare class DooverDataProvider implements ChannelsDataProvider<ChannelI
|
|
|
30
30
|
private readonly subscriptions;
|
|
31
31
|
constructor(config: DooverClientConfig, auth?: DooverAuth);
|
|
32
32
|
getMe(): Promise<User>;
|
|
33
|
-
getAgents(): Promise<AgentsResponse>;
|
|
33
|
+
getAgents(options?: GetAgentsOptions): Promise<AgentsResponse>;
|
|
34
34
|
getChannels(identifier: ChannelIdentifier, options?: {
|
|
35
35
|
includeArchived?: boolean;
|
|
36
36
|
}): Promise<Channel[] | undefined>;
|
|
@@ -82,6 +82,11 @@ export declare class DooverDataProvider implements ChannelsDataProvider<ChannelI
|
|
|
82
82
|
aggregatePath?: string;
|
|
83
83
|
};
|
|
84
84
|
getAgentInfo(agentId: string): Promise<Agent | undefined>;
|
|
85
|
+
private normalizeAgentEntry;
|
|
86
|
+
private normalizeOrganisationEntry;
|
|
87
|
+
private normalizeUserEntry;
|
|
88
|
+
private buildUserDisplayName;
|
|
89
|
+
private coerceExtraConfig;
|
|
85
90
|
private requireChannel;
|
|
86
91
|
private channelKey;
|
|
87
92
|
private toIdentifier;
|
|
@@ -18,6 +18,11 @@ function isRpcMessageData(data) {
|
|
|
18
18
|
"method" in data &&
|
|
19
19
|
"request" in data);
|
|
20
20
|
}
|
|
21
|
+
function isPlainObject(value) {
|
|
22
|
+
return (typeof value === "object" &&
|
|
23
|
+
value !== null &&
|
|
24
|
+
!Array.isArray(value));
|
|
25
|
+
}
|
|
21
26
|
class DooverDataProvider {
|
|
22
27
|
constructor(config, auth) {
|
|
23
28
|
this.config = config;
|
|
@@ -53,12 +58,52 @@ class DooverDataProvider {
|
|
|
53
58
|
getMe() {
|
|
54
59
|
return this.rest.get("/users/me", undefined, this.config.controlApiUrl);
|
|
55
60
|
}
|
|
56
|
-
getAgents() {
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
async getAgents(options) {
|
|
62
|
+
const query = {};
|
|
63
|
+
if (options?.includeArchived) {
|
|
64
|
+
query["include-archived"] = true;
|
|
65
|
+
}
|
|
66
|
+
if (options?.includeOrganisations) {
|
|
67
|
+
query["include-organisations"] = true;
|
|
68
|
+
}
|
|
69
|
+
if (options?.includeUsers) {
|
|
70
|
+
query["include-users"] = true;
|
|
71
|
+
}
|
|
72
|
+
const raw = await this.rest.request({
|
|
73
|
+
path: "/agents/",
|
|
59
74
|
baseUrl: this.config.controlApiUrl,
|
|
60
75
|
omitSharingHeader: true,
|
|
76
|
+
query: Object.keys(query).length > 0 ? query : undefined,
|
|
61
77
|
});
|
|
78
|
+
const rawAgents = Array.isArray(raw.agents) ? raw.agents : [];
|
|
79
|
+
const normalizedAgents = rawAgents.map((agent) => this.normalizeAgentEntry(agent));
|
|
80
|
+
if (!options?.mergeIncludedAsAgents) {
|
|
81
|
+
return {
|
|
82
|
+
...raw,
|
|
83
|
+
agents: normalizedAgents,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const merged = [...normalizedAgents];
|
|
87
|
+
if (options.includeOrganisations) {
|
|
88
|
+
const rawOrganisations = Array.isArray(raw.organisations)
|
|
89
|
+
? raw.organisations
|
|
90
|
+
: [];
|
|
91
|
+
for (const org of rawOrganisations) {
|
|
92
|
+
merged.push(this.normalizeOrganisationEntry(org));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (options.includeUsers) {
|
|
96
|
+
const rawUsers = Array.isArray(raw.users) ? raw.users : [];
|
|
97
|
+
for (const user of rawUsers) {
|
|
98
|
+
merged.push(this.normalizeUserEntry(user));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
...raw,
|
|
103
|
+
agents: merged,
|
|
104
|
+
results: merged,
|
|
105
|
+
count: merged.length,
|
|
106
|
+
};
|
|
62
107
|
}
|
|
63
108
|
async getChannels(identifier, options) {
|
|
64
109
|
if (!identifier.agentId) {
|
|
@@ -263,6 +308,106 @@ class DooverDataProvider {
|
|
|
263
308
|
extra_config: {},
|
|
264
309
|
});
|
|
265
310
|
}
|
|
311
|
+
normalizeAgentEntry(rawAgent) {
|
|
312
|
+
const source = isPlainObject(rawAgent)
|
|
313
|
+
? rawAgent
|
|
314
|
+
: {};
|
|
315
|
+
const fixedLocation = source.fixed_location;
|
|
316
|
+
const normalizedFixedLocation = isPlainObject(fixedLocation) &&
|
|
317
|
+
typeof fixedLocation.latitude === "number" &&
|
|
318
|
+
typeof fixedLocation.longitude === "number"
|
|
319
|
+
? {
|
|
320
|
+
latitude: fixedLocation.latitude,
|
|
321
|
+
longitude: fixedLocation.longitude,
|
|
322
|
+
}
|
|
323
|
+
: { latitude: 0, longitude: 0 };
|
|
324
|
+
const faIcon = typeof source.fa_icon === "string" && source.fa_icon.length > 0
|
|
325
|
+
? source.fa_icon
|
|
326
|
+
: "fa-solid fa-robot";
|
|
327
|
+
return {
|
|
328
|
+
...source,
|
|
329
|
+
id: typeof source.id === "string" ? source.id : String(source.id ?? ""),
|
|
330
|
+
organisation: typeof source.organisation === "string" ? source.organisation : "",
|
|
331
|
+
name: typeof source.name === "string" ? source.name : "",
|
|
332
|
+
display_name: typeof source.display_name === "string" ? source.display_name : "",
|
|
333
|
+
archived: typeof source.archived === "boolean" ? source.archived : false,
|
|
334
|
+
group: typeof source.group === "string" ? source.group : "",
|
|
335
|
+
fa_icon: faIcon,
|
|
336
|
+
type: source.type === "device" ||
|
|
337
|
+
source.type === "dashboard" ||
|
|
338
|
+
source.type === "organisation" ||
|
|
339
|
+
source.type === "user"
|
|
340
|
+
? source.type
|
|
341
|
+
: "device",
|
|
342
|
+
fixed_location: normalizedFixedLocation,
|
|
343
|
+
extra_config: this.coerceExtraConfig(source.extra_config),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
normalizeOrganisationEntry(rawOrganisation) {
|
|
347
|
+
const source = isPlainObject(rawOrganisation)
|
|
348
|
+
? rawOrganisation
|
|
349
|
+
: {};
|
|
350
|
+
const name = typeof source.name === "string" ? source.name : "";
|
|
351
|
+
const rootGroup = isPlainObject(source.root_group) ? source.root_group : null;
|
|
352
|
+
const groupName = rootGroup && typeof rootGroup.name === "string" ? rootGroup.name : "";
|
|
353
|
+
return {
|
|
354
|
+
id: typeof source.id === "string" ? source.id : String(source.id ?? ""),
|
|
355
|
+
organisation: name,
|
|
356
|
+
name,
|
|
357
|
+
display_name: name,
|
|
358
|
+
archived: typeof source.archived === "boolean" ? source.archived : false,
|
|
359
|
+
group: groupName,
|
|
360
|
+
fa_icon: "fa-solid fa-building",
|
|
361
|
+
type: "organisation",
|
|
362
|
+
fixed_location: { latitude: 0, longitude: 0 },
|
|
363
|
+
extra_config: this.coerceExtraConfig(source.extra_config),
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
normalizeUserEntry(rawUser) {
|
|
367
|
+
const source = isPlainObject(rawUser)
|
|
368
|
+
? rawUser
|
|
369
|
+
: {};
|
|
370
|
+
const id = typeof source.id === "string" ? source.id : String(source.id ?? "");
|
|
371
|
+
const username = typeof source.username === "string" ? source.username : "";
|
|
372
|
+
const email = typeof source.email === "string" ? source.email : "";
|
|
373
|
+
const name = username !== "" ? username : email !== "" ? email : id;
|
|
374
|
+
return {
|
|
375
|
+
id,
|
|
376
|
+
organisation: "",
|
|
377
|
+
name,
|
|
378
|
+
display_name: this.buildUserDisplayName(source),
|
|
379
|
+
archived: false,
|
|
380
|
+
group: "",
|
|
381
|
+
fa_icon: "fa-solid fa-user",
|
|
382
|
+
type: "user",
|
|
383
|
+
fixed_location: { latitude: 0, longitude: 0 },
|
|
384
|
+
extra_config: this.coerceExtraConfig(source.custom_data),
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
buildUserDisplayName(rawUser) {
|
|
388
|
+
const source = isPlainObject(rawUser)
|
|
389
|
+
? rawUser
|
|
390
|
+
: {};
|
|
391
|
+
const firstName = typeof source.first_name === "string" ? source.first_name.trim() : "";
|
|
392
|
+
const lastName = typeof source.last_name === "string" ? source.last_name.trim() : "";
|
|
393
|
+
const fullName = `${firstName} ${lastName}`.trim();
|
|
394
|
+
if (fullName !== "") {
|
|
395
|
+
return fullName;
|
|
396
|
+
}
|
|
397
|
+
if (typeof source.username === "string" && source.username !== "") {
|
|
398
|
+
return source.username;
|
|
399
|
+
}
|
|
400
|
+
if (typeof source.email === "string" && source.email !== "") {
|
|
401
|
+
return source.email;
|
|
402
|
+
}
|
|
403
|
+
if (typeof source.id === "string" && source.id !== "") {
|
|
404
|
+
return source.id;
|
|
405
|
+
}
|
|
406
|
+
return String(source.id ?? "");
|
|
407
|
+
}
|
|
408
|
+
coerceExtraConfig(value) {
|
|
409
|
+
return isPlainObject(value) ? value : {};
|
|
410
|
+
}
|
|
266
411
|
requireChannel(identifier) {
|
|
267
412
|
if (!identifier.agentId || !identifier.channelName) {
|
|
268
413
|
throw new errors_1.DooverValidationError("Identifier must contain agentId and channelName");
|