@evoke-platform/context 1.0.0-dev.99 → 1.0.1-dev.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/README.md +103 -64
- package/dist/api/apiServices.js +3 -2
- package/dist/api/paramsSerializer.d.ts +2 -0
- package/dist/api/paramsSerializer.js +16 -0
- package/dist/app/AppProvider.d.ts +10 -1
- package/dist/app/AppProvider.js +53 -6
- package/dist/authentication/AuthenticationContextProvider.js +4 -1
- package/dist/notification/NotificationProvider.js +1 -1
- package/dist/objects/objects.d.ts +40 -13
- package/dist/signalr/SignalRConnectionProvider.js +40 -129
- package/package.json +11 -6
package/README.md
CHANGED
|
@@ -17,7 +17,8 @@ available and no further installation is necessary.
|
|
|
17
17
|
|
|
18
18
|
- [Working With Objects](#working-with-objects)
|
|
19
19
|
- [REST API Calls](#rest-api-calls)
|
|
20
|
-
- [
|
|
20
|
+
- [Authentication Context](#authentication-context)
|
|
21
|
+
- [Notifications](#notifications)
|
|
21
22
|
|
|
22
23
|
### Working With Objects
|
|
23
24
|
|
|
@@ -160,7 +161,16 @@ Returns a function that can be used to navigate to another page. The returned fu
|
|
|
160
161
|
|
|
161
162
|
#### `useApp()`
|
|
162
163
|
|
|
163
|
-
Returns the currently loaded Evoke
|
|
164
|
+
Returns the currently loaded Evoke App as well as the following function.
|
|
165
|
+
|
|
166
|
+
- `findDefaultPageSlugFor`: An asynchronous function that takes an `objectId` as a parameter and returns the default page slug for that object, if no default page slug is found and the object is a subtype, the page slug of the first ancestor with a default page will be used. It returns `undefined` if no default page slug is found for any ancestor type.
|
|
167
|
+
|
|
168
|
+
Example usage:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
const { id: appId, findDefaultPageSlugFor } = useApp();
|
|
172
|
+
const defaultPageSlug = await findDefaultPageSlugFor(objectId);
|
|
173
|
+
```
|
|
164
174
|
|
|
165
175
|
### REST API calls
|
|
166
176
|
|
|
@@ -197,26 +207,46 @@ absolute URL.
|
|
|
197
207
|
|
|
198
208
|
##### `delete(url, options)`
|
|
199
209
|
|
|
200
|
-
###
|
|
210
|
+
### Authentication Context
|
|
211
|
+
|
|
212
|
+
- [useAuthenticationContext](#useauthenticationcontext)
|
|
213
|
+
|
|
214
|
+
#### `useAuthenticationContext()`
|
|
215
|
+
|
|
216
|
+
Hook to obtain the authentication context based on the current logged-in user.
|
|
201
217
|
|
|
202
|
-
|
|
218
|
+
The authentication context includes the following property and functions.
|
|
203
219
|
|
|
204
|
-
- [
|
|
220
|
+
- `account` _[object]_
|
|
221
|
+
- The account of the currently logged-in user. This includes both the user's `id` and `name`.
|
|
222
|
+
- `logout()`
|
|
223
|
+
- A function that logs out the currently logged-in user. The user will be redirected to Evoke's logout page upon logout.
|
|
224
|
+
- `getAccessToken()`
|
|
225
|
+
- A function that returns an access token that is associated to the currently logged-in user. This token can be used to make API calls to Evoke's APIs to authenticate the API call.
|
|
226
|
+
- Note: As a general recommendation, the [ApiService](#class-apiservices) class should be used to make API calls as it will take care
|
|
227
|
+
of appending an access token to the call.
|
|
228
|
+
|
|
229
|
+
### Notifications
|
|
230
|
+
|
|
231
|
+
- [useNofitication](#usenotification)
|
|
205
232
|
- [documentChanges](#documentchangessubscribeobjectidinstanceid-data-documentchange)
|
|
206
233
|
- [instanceChanges](#instancechangessubscribeobjectid-instanceids-instancechange)
|
|
234
|
+
- [useSignalRConnection](#usesignalrconnection) (_Deprecated_)
|
|
235
|
+
- [documentChanges](#documentchangessubscribeobjectidinstanceid-data-documentchange) (_Deprecated_)
|
|
236
|
+
- [instanceChanges](#instancechangessubscribeobjectid-instanceids-instancechange) (_Deprecated_)
|
|
207
237
|
|
|
208
|
-
#### `
|
|
238
|
+
#### `useNofitication()`
|
|
209
239
|
|
|
210
|
-
Hook used to obtain an instanceChanges instance
|
|
240
|
+
Hook used to obtain an instanceChanges instance and a documentChanges instance.
|
|
211
241
|
|
|
212
|
-
##### `documentChanges.subscribe(
|
|
242
|
+
##### `documentChanges.subscribe(objectId, instanceId, (data: DocumentChange[]]) => {})`
|
|
213
243
|
|
|
214
|
-
Subscribe to the specified object instance
|
|
244
|
+
Subscribe to the specified object instance changes.
|
|
215
245
|
|
|
216
246
|
```javascript
|
|
217
|
-
const { documentChanges } =
|
|
247
|
+
const { documentChanges } = useNotification();
|
|
218
248
|
|
|
219
|
-
documentChanges.subscribe('myObjectId
|
|
249
|
+
documentChanges.subscribe('myObjectId', 'myInstanceId', (data) => {
|
|
220
250
|
console.log(data);
|
|
221
251
|
});
|
|
222
252
|
```
|
|
@@ -233,53 +263,61 @@ following data:
|
|
|
233
263
|
- `type`
|
|
234
264
|
- The type of update. Possible values are `BlobCreated`, `BlobDeleted`, and `BlobMetadataUpdated`.
|
|
235
265
|
|
|
236
|
-
##### `documentChanges.unsubscribe(
|
|
266
|
+
##### `documentChanges.unsubscribe(objectId, instanceId, (changes: DocumentChange[]) => {})`
|
|
237
267
|
|
|
238
|
-
Unsubscribe to the specified object instance
|
|
268
|
+
Unsubscribe to the specified object instance changes.
|
|
239
269
|
|
|
240
270
|
Callback function is optional.
|
|
271
|
+
If callback function is not defined, all subscriptions will be removed.
|
|
241
272
|
If callback function is defined, you must pass the exact same Function instance as was previously passed to `documentChanges.subscribe`.
|
|
242
273
|
Passing a different instance (even if the function body is the same) will not remove the subscription.
|
|
243
274
|
|
|
244
275
|
```javascript
|
|
245
|
-
const { documentChanges } =
|
|
276
|
+
const { documentChanges } = useNotification();
|
|
246
277
|
|
|
247
|
-
const callback = (
|
|
248
|
-
console.log(
|
|
278
|
+
const callback = (changes: DocumentChange[]) => {
|
|
279
|
+
console.log(changes);
|
|
249
280
|
};
|
|
250
281
|
|
|
251
|
-
documentChanges.subscribe('myObjectId
|
|
282
|
+
documentChanges.subscribe('myObjectId', 'myInstanceId', callback);
|
|
252
283
|
|
|
253
|
-
documentChanges.unsubscribe('myObjectId
|
|
284
|
+
documentChanges.unsubscribe('myObjectId', 'myInstanceId', callback);
|
|
254
285
|
```
|
|
255
286
|
|
|
256
|
-
##### `instanceChanges.subscribe(
|
|
287
|
+
##### `instanceChanges.subscribe(objectId, (changes: InstanceChange[]) => {})`
|
|
257
288
|
|
|
258
|
-
Subscribe to the specified object
|
|
289
|
+
Subscribe to the specified object changes.
|
|
259
290
|
|
|
260
291
|
```javascript
|
|
261
|
-
const { instanceChanges } =
|
|
292
|
+
const { instanceChanges } = useNotification();
|
|
262
293
|
|
|
263
|
-
instanceChanges.subscribe('myObjectId', (
|
|
264
|
-
console.log(
|
|
294
|
+
instanceChanges.subscribe('myObjectId', (changes) => {
|
|
295
|
+
console.log(changes);
|
|
265
296
|
});
|
|
266
297
|
```
|
|
267
298
|
|
|
268
|
-
The data provided to the callback will be an array of
|
|
299
|
+
The data provided to the callback will be an array of `InstanceChange` which contains the
|
|
300
|
+
following data:
|
|
269
301
|
|
|
270
|
-
|
|
302
|
+
- `objectId`
|
|
303
|
+
- Object describing the instance associated with the updated document.
|
|
304
|
+
- `instanceId`
|
|
305
|
+
- Instance that the updated document is associated with.
|
|
271
306
|
|
|
272
|
-
|
|
307
|
+
##### `instanceChanges.unsubscribe(objectId, (changes: InstanceChange[]) => {})`
|
|
308
|
+
|
|
309
|
+
Unsubscribe to the specified object changes.
|
|
273
310
|
|
|
274
311
|
Callback function is optional.
|
|
312
|
+
If callback function is not defined, all subscriptions will be removed.
|
|
275
313
|
If callback function is defined, you must pass the exact same Function instance as was previously passed to `instanceChanges.subscribe`.
|
|
276
314
|
Passing a different instance (even if the function body is the same) will not remove the subscription.
|
|
277
315
|
|
|
278
316
|
```javascript
|
|
279
|
-
const { instanceChanges } =
|
|
317
|
+
const { instanceChanges } = useNotification();
|
|
280
318
|
|
|
281
|
-
const callback = (
|
|
282
|
-
console.log(
|
|
319
|
+
const callback = (changes: InstanceChange[]) => {
|
|
320
|
+
console.log(changes);
|
|
283
321
|
};
|
|
284
322
|
|
|
285
323
|
instanceChanges.subscribe('myObjectId', callback);
|
|
@@ -287,24 +325,24 @@ instanceChanges.subscribe('myObjectId', callback);
|
|
|
287
325
|
instanceChanges.unsubscribe('myObjectId', callback);
|
|
288
326
|
```
|
|
289
327
|
|
|
290
|
-
|
|
328
|
+
#### `useSignalRConnection()`
|
|
291
329
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
- [instanceChanges](#instancechangessubscribeobjectid-instanceids-instancechange)
|
|
330
|
+
> **Deprecated**
|
|
331
|
+
> This has been deprecated in favor of [useNotification](#usenofitication).
|
|
295
332
|
|
|
296
|
-
|
|
333
|
+
Hook used to obtain an instanceChanges instance of `SignalRConnection` and a documentChanges instance of `SignalRConnection`.
|
|
297
334
|
|
|
298
|
-
|
|
335
|
+
##### `documentChanges.subscribe('{objectId}/{instanceId}', (data: DocumentChange[]]) => {})`
|
|
299
336
|
|
|
300
|
-
|
|
337
|
+
> **Deprecated**
|
|
338
|
+
> This has been deprecated in favor of [useNotification](#usenofitication).
|
|
301
339
|
|
|
302
|
-
Subscribe to the specified object instance changes.
|
|
340
|
+
Subscribe to the specified object instance document changes.
|
|
303
341
|
|
|
304
342
|
```javascript
|
|
305
|
-
const { documentChanges } =
|
|
343
|
+
const { documentChanges } = useSignalRConnection();
|
|
306
344
|
|
|
307
|
-
documentChanges.subscribe('myObjectId
|
|
345
|
+
documentChanges.subscribe('myObjectId/myInstanceId', (data) => {
|
|
308
346
|
console.log(data);
|
|
309
347
|
});
|
|
310
348
|
```
|
|
@@ -321,61 +359,62 @@ following data:
|
|
|
321
359
|
- `type`
|
|
322
360
|
- The type of update. Possible values are `BlobCreated`, `BlobDeleted`, and `BlobMetadataUpdated`.
|
|
323
361
|
|
|
324
|
-
##### `documentChanges.unsubscribe(objectId
|
|
362
|
+
##### `documentChanges.unsubscribe('{objectId}/{instanceId}', (data: DocumentChange[]) => {})`
|
|
325
363
|
|
|
326
|
-
|
|
364
|
+
> **Deprecated**
|
|
365
|
+
> This has been deprecated in favor of [useNotification](#usenofitication).
|
|
366
|
+
|
|
367
|
+
Unsubscribe to the specified object instance document changes.
|
|
327
368
|
|
|
328
369
|
Callback function is optional.
|
|
329
|
-
If callback function is not defined, all subscriptions will be removed.
|
|
330
370
|
If callback function is defined, you must pass the exact same Function instance as was previously passed to `documentChanges.subscribe`.
|
|
331
371
|
Passing a different instance (even if the function body is the same) will not remove the subscription.
|
|
332
372
|
|
|
333
373
|
```javascript
|
|
334
|
-
const { documentChanges } =
|
|
374
|
+
const { documentChanges } = useSignalRConnection();
|
|
335
375
|
|
|
336
|
-
const callback = (
|
|
337
|
-
console.log(
|
|
376
|
+
const callback = (data: DocumentChange[]) => {
|
|
377
|
+
console.log(data);
|
|
338
378
|
};
|
|
339
379
|
|
|
340
|
-
documentChanges.subscribe('myObjectId
|
|
380
|
+
documentChanges.subscribe('myObjectId/myInstanceId', callback);
|
|
341
381
|
|
|
342
|
-
documentChanges.unsubscribe('myObjectId
|
|
382
|
+
documentChanges.unsubscribe('myObjectId/myInstanceId', callback);
|
|
343
383
|
```
|
|
344
384
|
|
|
345
|
-
##### `instanceChanges.subscribe(objectId, (
|
|
385
|
+
##### `instanceChanges.subscribe('{objectId}', (instanceIds: InstanceChange[]) => {})`
|
|
346
386
|
|
|
347
|
-
|
|
387
|
+
> **Deprecated**
|
|
388
|
+
> This has been deprecated in favor of [useNotification](#usenofitication).
|
|
389
|
+
|
|
390
|
+
Subscribe to the specified object instance changes.
|
|
348
391
|
|
|
349
392
|
```javascript
|
|
350
|
-
const { instanceChanges } =
|
|
393
|
+
const { instanceChanges } = useSignalRConnection();
|
|
351
394
|
|
|
352
|
-
instanceChanges.subscribe('myObjectId', (
|
|
353
|
-
console.log(
|
|
395
|
+
instanceChanges.subscribe('myObjectId', (instanceIds) => {
|
|
396
|
+
console.log(instanceIds);
|
|
354
397
|
});
|
|
355
398
|
```
|
|
356
399
|
|
|
357
|
-
The data provided to the callback will be an array of
|
|
358
|
-
following data:
|
|
400
|
+
The data provided to the callback will be an array of instance IDs that were updated.
|
|
359
401
|
|
|
360
|
-
|
|
361
|
-
- Object describing the instance associated with the updated document.
|
|
362
|
-
- `instanceId`
|
|
363
|
-
- Instance that the updated document is associated with.
|
|
402
|
+
##### `instanceChanges.unsubscribe('{objectId}', (instanceIds: InstanceChange[]) => {})`
|
|
364
403
|
|
|
365
|
-
|
|
404
|
+
> **Deprecated**
|
|
405
|
+
> This has been deprecated in favor of [useNotification](#usenofitication).
|
|
366
406
|
|
|
367
|
-
Unsubscribe to the specified object changes.
|
|
407
|
+
Unsubscribe to the specified object instance changes.
|
|
368
408
|
|
|
369
409
|
Callback function is optional.
|
|
370
|
-
If callback function is not defined, all subscriptions will be removed.
|
|
371
410
|
If callback function is defined, you must pass the exact same Function instance as was previously passed to `instanceChanges.subscribe`.
|
|
372
411
|
Passing a different instance (even if the function body is the same) will not remove the subscription.
|
|
373
412
|
|
|
374
413
|
```javascript
|
|
375
|
-
const { instanceChanges } =
|
|
414
|
+
const { instanceChanges } = useSignalRConnection();
|
|
376
415
|
|
|
377
|
-
const callback = (
|
|
378
|
-
console.log(
|
|
416
|
+
const callback = (instanceIds: InstanceChange[]) => {
|
|
417
|
+
console.log(instanceIds);
|
|
379
418
|
};
|
|
380
419
|
|
|
381
420
|
instanceChanges.subscribe('myObjectId', callback);
|
package/dist/api/apiServices.js
CHANGED
|
@@ -11,9 +11,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
};
|
|
12
12
|
import axios from 'axios';
|
|
13
13
|
import { useMemo } from 'react';
|
|
14
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
14
15
|
import { useAuthenticationContext } from '../authentication/AuthenticationContextProvider.js';
|
|
15
16
|
import { useApiBaseUrl } from './ApiBaseUrlProvider.js';
|
|
16
|
-
import {
|
|
17
|
+
import { paramsSerializer } from './paramsSerializer.js';
|
|
17
18
|
const sessionId = uuidv4();
|
|
18
19
|
export class ApiServices {
|
|
19
20
|
constructor(api, authContext) {
|
|
@@ -143,6 +144,6 @@ export class ApiServices {
|
|
|
143
144
|
export function useApiServices() {
|
|
144
145
|
const authContext = useAuthenticationContext();
|
|
145
146
|
const baseURL = useApiBaseUrl();
|
|
146
|
-
const apiServices = useMemo(() => new ApiServices(axios.create({ baseURL }), authContext), [authContext, baseURL]);
|
|
147
|
+
const apiServices = useMemo(() => new ApiServices(axios.create({ baseURL, paramsSerializer }), authContext), [authContext, baseURL]);
|
|
147
148
|
return apiServices;
|
|
148
149
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function paramsSerializer(params, options) {
|
|
2
|
+
const searchParams = new URLSearchParams();
|
|
3
|
+
for (const [key, value] of Object.entries(params)) {
|
|
4
|
+
if (!validateParamKey(key) || !validateParamValue(value)) {
|
|
5
|
+
continue;
|
|
6
|
+
}
|
|
7
|
+
searchParams.append(key, typeof value !== 'string' ? JSON.stringify(value) : value);
|
|
8
|
+
}
|
|
9
|
+
return searchParams.toString();
|
|
10
|
+
}
|
|
11
|
+
function validateParamKey(item) {
|
|
12
|
+
return item.length;
|
|
13
|
+
}
|
|
14
|
+
function validateParamValue(item) {
|
|
15
|
+
return item !== undefined;
|
|
16
|
+
}
|
|
@@ -38,10 +38,19 @@ export type NavigationItem = {
|
|
|
38
38
|
pageId: string;
|
|
39
39
|
pageName: string;
|
|
40
40
|
};
|
|
41
|
+
export type AppExtended = App & {
|
|
42
|
+
/**
|
|
43
|
+
* Looks up the default page slug for a given object or its nearest type ancestor.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} objectId - The ID of the object to start the search from.
|
|
46
|
+
* @returns {Promise<string | undefined>} The default page slug, or `undefined` if no default page is found.
|
|
47
|
+
*/
|
|
48
|
+
findDefaultPageSlugFor: (objectId: string) => Promise<string | undefined>;
|
|
49
|
+
};
|
|
41
50
|
export type AppProviderProps = {
|
|
42
51
|
app: App;
|
|
43
52
|
children?: ReactNode;
|
|
44
53
|
};
|
|
45
54
|
declare function AppProvider(props: AppProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
46
|
-
export declare function useApp():
|
|
55
|
+
export declare function useApp(): AppExtended;
|
|
47
56
|
export default AppProvider;
|
package/dist/app/AppProvider.js
CHANGED
|
@@ -1,13 +1,60 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
1
10
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
11
|
+
import { createContext, useCallback, useContext } from 'react';
|
|
12
|
+
import { useApiServices } from '../api/index.js';
|
|
13
|
+
const defaultApp = {
|
|
14
|
+
id: '_evoke',
|
|
15
|
+
name: 'Evoke Platform',
|
|
16
|
+
type: 'public',
|
|
17
|
+
};
|
|
18
|
+
const defaultAppExtended = Object.assign(Object.assign({}, defaultApp), { findDefaultPageSlugFor: (objectId) => Promise.resolve(undefined) });
|
|
19
|
+
const AppContext = createContext(defaultAppExtended);
|
|
7
20
|
AppContext.displayName = 'AppContext';
|
|
8
21
|
function AppProvider(props) {
|
|
9
22
|
const { app, children } = props;
|
|
10
|
-
|
|
23
|
+
const apiServices = useApiServices();
|
|
24
|
+
const appExtended = Object.assign(Object.assign({}, app), { findDefaultPageSlugFor: useCallback((objectId) => __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
var _a, _b, _c, _d;
|
|
26
|
+
let defaultPageId;
|
|
27
|
+
let currentObjectId = objectId;
|
|
28
|
+
while (currentObjectId !== undefined) {
|
|
29
|
+
if ((_a = app.defaultPages) === null || _a === void 0 ? void 0 : _a[currentObjectId]) {
|
|
30
|
+
defaultPageId = app.defaultPages[currentObjectId];
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
const effectiveObject = yield apiServices.get(`data/objects/${currentObjectId}/effective`, {
|
|
34
|
+
params: { filter: { fields: ['baseObject'] } },
|
|
35
|
+
});
|
|
36
|
+
currentObjectId = (_c = (_b = effectiveObject === null || effectiveObject === void 0 ? void 0 : effectiveObject.baseObject) === null || _b === void 0 ? void 0 : _b.objectId) !== null && _c !== void 0 ? _c : undefined;
|
|
37
|
+
}
|
|
38
|
+
let defaultPage;
|
|
39
|
+
if (defaultPageId) {
|
|
40
|
+
const pageId = defaultPageId.includes('/')
|
|
41
|
+
? defaultPageId.split('/').slice(2).join('/')
|
|
42
|
+
: defaultPageId;
|
|
43
|
+
try {
|
|
44
|
+
defaultPage = yield apiServices.get(`/webContent/apps/${app.id}/pages/${encodeURIComponent(encodeURIComponent(pageId))}`);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const err = error;
|
|
48
|
+
if (((_d = err.response) === null || _d === void 0 ? void 0 : _d.status) === 404) {
|
|
49
|
+
defaultPage = undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (defaultPage === null || defaultPage === void 0 ? void 0 : defaultPage.slug) {
|
|
54
|
+
return `/${app.id}/${defaultPage.slug}`;
|
|
55
|
+
}
|
|
56
|
+
}), [app]) });
|
|
57
|
+
return _jsx(AppContext.Provider, { value: appExtended, children: children });
|
|
11
58
|
}
|
|
12
59
|
export function useApp() {
|
|
13
60
|
return useContext(AppContext);
|
|
@@ -31,7 +31,10 @@ function AuthenticationContextProvider(props) {
|
|
|
31
31
|
? {
|
|
32
32
|
account: { id: account.localAccountId, name: account.name },
|
|
33
33
|
logout: () => {
|
|
34
|
-
msal.instance.logoutRedirect({
|
|
34
|
+
msal.instance.logoutRedirect({
|
|
35
|
+
account,
|
|
36
|
+
postLogoutRedirectUri: `/logout?p=${encodeURIComponent(window.location.pathname + window.location.search)}`,
|
|
37
|
+
});
|
|
35
38
|
},
|
|
36
39
|
getAccessToken,
|
|
37
40
|
}
|
|
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
|
-
import { HubConnectionBuilder, LogLevel, } from '@microsoft/signalr
|
|
11
|
+
import { HubConnectionBuilder, LogLevel, } from '@microsoft/signalr';
|
|
12
12
|
import { createContext, useContext, useEffect, useState } from 'react';
|
|
13
13
|
import { useApiServices } from '../api/index.js';
|
|
14
14
|
export const NotificationContext = createContext({});
|
|
@@ -4,12 +4,28 @@ export type BaseObjReference = {
|
|
|
4
4
|
objectId: string;
|
|
5
5
|
discriminatorValue: unknown;
|
|
6
6
|
};
|
|
7
|
+
export type ViewLayoutEntityReference = {
|
|
8
|
+
id: string;
|
|
9
|
+
objectId: string;
|
|
10
|
+
};
|
|
11
|
+
type ViewLayoutEntity = {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
objectId: string;
|
|
15
|
+
};
|
|
16
|
+
export type TableViewLayoutEntity = ViewLayoutEntity & TableViewLayout;
|
|
17
|
+
export type DropdownViewLayoutEntity = ViewLayoutEntity & DropdownViewLayout;
|
|
7
18
|
export type ViewLayout = {
|
|
8
19
|
table?: TableViewLayout;
|
|
9
20
|
dropdown?: DropdownViewLayout;
|
|
10
21
|
};
|
|
22
|
+
export type DropdownViewLayoutSort = {
|
|
23
|
+
propertyId: string;
|
|
24
|
+
direction?: 'asc' | 'desc';
|
|
25
|
+
};
|
|
11
26
|
export type DropdownViewLayout = {
|
|
12
27
|
secondaryTextExpression: string;
|
|
28
|
+
sort?: DropdownViewLayoutSort;
|
|
13
29
|
};
|
|
14
30
|
export type TableViewLayout = {
|
|
15
31
|
properties: PropertyReference[];
|
|
@@ -35,7 +51,7 @@ export type Obj = {
|
|
|
35
51
|
export type ObjWithRoot = Obj & {
|
|
36
52
|
rootObjectId: string;
|
|
37
53
|
};
|
|
38
|
-
export type PropertyType = 'address' | 'array' | 'boolean' | 'collection' | 'date' | 'date-time' | 'image' | 'integer' | 'number' | 'object' | 'richText' | 'string' | 'time' | 'user';
|
|
54
|
+
export type PropertyType = 'address' | 'array' | 'boolean' | 'collection' | 'criteria' | 'date' | 'date-time' | 'document' | 'image' | 'integer' | 'number' | 'object' | 'richText' | 'string' | 'time' | 'user';
|
|
39
55
|
export type NumericValidation = {
|
|
40
56
|
errorMessage?: string;
|
|
41
57
|
minimum?: number;
|
|
@@ -51,12 +67,14 @@ export type CriteriaValidation = {
|
|
|
51
67
|
};
|
|
52
68
|
export type StringValidation = {
|
|
53
69
|
operator: 'any' | 'all';
|
|
54
|
-
rules?:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
70
|
+
rules?: RegexValidation[];
|
|
71
|
+
};
|
|
72
|
+
export type DocumentValidation = {
|
|
73
|
+
errorMessage?: string;
|
|
74
|
+
maxDocuments?: number;
|
|
75
|
+
minDocuments?: number;
|
|
58
76
|
};
|
|
59
|
-
export type PropertyValidation = StringValidation | NumericValidation | DateValidation | CriteriaValidation;
|
|
77
|
+
export type PropertyValidation = StringValidation | NumericValidation | DateValidation | CriteriaValidation | DocumentValidation;
|
|
60
78
|
export type Property = {
|
|
61
79
|
id: string;
|
|
62
80
|
name: string;
|
|
@@ -109,7 +127,7 @@ export type ObjectInstance = {
|
|
|
109
127
|
};
|
|
110
128
|
export type RegexValidation = {
|
|
111
129
|
regex: string;
|
|
112
|
-
errorMessage
|
|
130
|
+
errorMessage?: string;
|
|
113
131
|
};
|
|
114
132
|
export type SelectOption = {
|
|
115
133
|
label: string;
|
|
@@ -144,12 +162,18 @@ export type DisplayConfiguration = {
|
|
|
144
162
|
mode?: 'default' | 'existingOnly';
|
|
145
163
|
relatedObjectDisplay?: 'dropdown' | 'dialogBox';
|
|
146
164
|
visibility?: VisibilityConfiguration | string;
|
|
165
|
+
viewLayout?: ViewLayoutEntityReference;
|
|
166
|
+
choicesDisplay?: {
|
|
167
|
+
type: 'dropdown' | 'radioButton';
|
|
168
|
+
sortBy?: 'ASC' | 'DESC' | 'NONE';
|
|
169
|
+
};
|
|
147
170
|
};
|
|
148
171
|
export type InputParameterReference = {
|
|
149
172
|
type: 'input';
|
|
150
173
|
parameterId: string;
|
|
151
174
|
display?: DisplayConfiguration;
|
|
152
175
|
enumWithLabels?: SelectOption[];
|
|
176
|
+
documentMetadata?: Record<string, string>;
|
|
153
177
|
};
|
|
154
178
|
export type Content = {
|
|
155
179
|
type: 'content';
|
|
@@ -178,7 +202,7 @@ export type FormEntry = InputParameterReference | Columns | Sections | Content;
|
|
|
178
202
|
export type Form = {
|
|
179
203
|
entries?: FormEntry[];
|
|
180
204
|
};
|
|
181
|
-
export type ActionInputType = 'button' | 'Section' | 'Columns' | 'Content' | 'Select' | 'TextField' | 'DateTime' | 'RepeatableField' | 'MultiSelect' | 'Decimal' | 'RichText' | 'Date' | 'Integer' | 'Image' | 'Object' | 'Time' | 'User';
|
|
205
|
+
export type ActionInputType = 'button' | 'Section' | 'Columns' | 'Content' | 'Criteria' | 'Select' | 'TextField' | 'DateTime' | 'Document' | 'RepeatableField' | 'ManyToManyRepeatableField' | 'MultiSelect' | 'Decimal' | 'RichText' | 'Date' | 'Integer' | 'Image' | 'Object' | 'Time' | 'User';
|
|
182
206
|
/**
|
|
183
207
|
* Represents an object action inputProperty object.
|
|
184
208
|
*/
|
|
@@ -187,7 +211,7 @@ export type ActionInput = {
|
|
|
187
211
|
label?: string;
|
|
188
212
|
type?: ActionInputType;
|
|
189
213
|
key?: string;
|
|
190
|
-
initialValue?: string | number | SelectOption[] | SelectOption;
|
|
214
|
+
initialValue?: string | string[] | number | RelatedObjectDefaultValue | SelectOption[] | SelectOption;
|
|
191
215
|
defaultToCurrentDate?: boolean;
|
|
192
216
|
defaultToCurrentTime?: boolean;
|
|
193
217
|
defaultValueCriteria?: object;
|
|
@@ -210,7 +234,7 @@ export type ActionInput = {
|
|
|
210
234
|
inputMaskPlaceholderChar?: string;
|
|
211
235
|
tableView?: boolean;
|
|
212
236
|
mode?: 'default' | 'existingOnly';
|
|
213
|
-
displayOption?: 'dropdown' | 'dialogBox';
|
|
237
|
+
displayOption?: 'dropdown' | 'dialogBox' | 'radioButton';
|
|
214
238
|
rows?: number;
|
|
215
239
|
showCharCount?: boolean;
|
|
216
240
|
readOnly?: boolean;
|
|
@@ -224,9 +248,9 @@ export type ActionInput = {
|
|
|
224
248
|
when?: string;
|
|
225
249
|
eq?: string | number | boolean;
|
|
226
250
|
};
|
|
227
|
-
property?:
|
|
228
|
-
|
|
229
|
-
|
|
251
|
+
property?: InputParameter;
|
|
252
|
+
viewLayout?: ViewLayoutEntityReference;
|
|
253
|
+
documentMetadata?: Record<string, string>;
|
|
230
254
|
validate?: {
|
|
231
255
|
required?: boolean;
|
|
232
256
|
criteria?: object;
|
|
@@ -240,6 +264,8 @@ export type ActionInput = {
|
|
|
240
264
|
maxTime?: string;
|
|
241
265
|
min?: number;
|
|
242
266
|
max?: number;
|
|
267
|
+
minDocuments?: number;
|
|
268
|
+
maxDocuments?: number;
|
|
243
269
|
customMessage?: string;
|
|
244
270
|
};
|
|
245
271
|
/**
|
|
@@ -306,3 +332,4 @@ export declare class ObjectStore {
|
|
|
306
332
|
instanceAction<T extends ObjectInstance = ObjectInstance>(id: string, input: ActionRequest, cb: Callback<T>): void;
|
|
307
333
|
}
|
|
308
334
|
export declare function useObject(objectId: string): ObjectStore;
|
|
335
|
+
export {};
|
|
@@ -1,142 +1,53 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
2
|
// Copyright (c) 2023 System Automation Corporation.
|
|
12
3
|
// This file is licensed under the MIT License.
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { useApiServices } from '../api/index.js';
|
|
4
|
+
import { createContext, useContext, useState } from 'react';
|
|
5
|
+
import { useNotification } from '../notification/index.js';
|
|
16
6
|
export const SignalRConnectionContext = createContext({});
|
|
17
7
|
SignalRConnectionContext.displayName = 'SignalRConnectionContext';
|
|
18
8
|
function SignalRConnectionProvider({ children }) {
|
|
19
|
-
const
|
|
20
|
-
const [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return api.post(`/signalr/hubs/${hubName}/negotiate`);
|
|
25
|
-
};
|
|
26
|
-
const getConnection = () => __awaiter(this, void 0, void 0, function* () {
|
|
27
|
-
try {
|
|
28
|
-
const instancesConnectionInfo = yield getConnectionInfo('instanceChanges');
|
|
29
|
-
const documentsConnectionInfo = yield getConnectionInfo('documentChanges');
|
|
30
|
-
if (instancesConnectionInfo) {
|
|
31
|
-
const options = {
|
|
32
|
-
accessTokenFactory: () => __awaiter(this, void 0, void 0, function* () {
|
|
33
|
-
if (instancesConnectionInfo.accessToken) {
|
|
34
|
-
return instancesConnectionInfo.accessToken;
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
return getConnection();
|
|
38
|
-
}
|
|
39
|
-
}),
|
|
40
|
-
};
|
|
41
|
-
const connection = new HubConnectionBuilder()
|
|
42
|
-
.withUrl(instancesConnectionInfo.url, options)
|
|
43
|
-
.configureLogging(LogLevel.Error)
|
|
44
|
-
.withAutomaticReconnect()
|
|
45
|
-
.build();
|
|
46
|
-
setInstancesSignalRConnection(connection);
|
|
47
|
-
}
|
|
48
|
-
if (documentsConnectionInfo) {
|
|
49
|
-
const options = {
|
|
50
|
-
accessTokenFactory: () => __awaiter(this, void 0, void 0, function* () {
|
|
51
|
-
if (documentsConnectionInfo.accessToken) {
|
|
52
|
-
return documentsConnectionInfo.accessToken;
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
return getConnection();
|
|
56
|
-
}
|
|
57
|
-
}),
|
|
58
|
-
};
|
|
59
|
-
const connection = new HubConnectionBuilder()
|
|
60
|
-
.withUrl(documentsConnectionInfo.url, options)
|
|
61
|
-
.configureLogging(LogLevel.Error)
|
|
62
|
-
.withAutomaticReconnect()
|
|
63
|
-
.build();
|
|
64
|
-
setDocumentsSignalRConnection(connection);
|
|
65
|
-
}
|
|
66
|
-
// eslint-disable-next-line no-empty
|
|
67
|
-
}
|
|
68
|
-
catch (err) { }
|
|
69
|
-
});
|
|
70
|
-
getConnection();
|
|
71
|
-
}, []);
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
let documentsConnectionStopped = false;
|
|
74
|
-
const startConnection = (connection, numOfAttempts) => __awaiter(this, void 0, void 0, function* () {
|
|
75
|
-
yield connection.start().catch((error) => {
|
|
76
|
-
if (numOfAttempts < 4 && !documentsConnectionStopped) {
|
|
77
|
-
setTimeout(() => {
|
|
78
|
-
if (!documentsConnectionStopped) {
|
|
79
|
-
startConnection(connection, numOfAttempts + 1);
|
|
80
|
-
}
|
|
81
|
-
}, 2000);
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
console.warn(`Cannot start connection to SignalR due to error "${error}"`);
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
if (documentsSignalRConnection) {
|
|
89
|
-
startConnection(documentsSignalRConnection, 0);
|
|
90
|
-
}
|
|
91
|
-
return () => {
|
|
92
|
-
documentsSignalRConnection === null || documentsSignalRConnection === void 0 ? void 0 : documentsSignalRConnection.stop();
|
|
93
|
-
documentsConnectionStopped = true;
|
|
94
|
-
};
|
|
95
|
-
}, [documentsSignalRConnection]);
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
let instancesConnectionStopped = false;
|
|
98
|
-
const startConnection = (connection, numOfAttempts) => __awaiter(this, void 0, void 0, function* () {
|
|
99
|
-
yield connection.start().catch((error) => {
|
|
100
|
-
if (numOfAttempts < 4 && !instancesConnectionStopped) {
|
|
101
|
-
setTimeout(() => {
|
|
102
|
-
if (!instancesConnectionStopped) {
|
|
103
|
-
startConnection(connection, numOfAttempts + 1);
|
|
104
|
-
}
|
|
105
|
-
}, 2000);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
console.warn(`Cannot start connection to SignalR due to error "${error}"`);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
if (instancesSignalRConnection) {
|
|
113
|
-
startConnection(instancesSignalRConnection, 0);
|
|
114
|
-
}
|
|
115
|
-
return () => {
|
|
116
|
-
instancesSignalRConnection === null || instancesSignalRConnection === void 0 ? void 0 : instancesSignalRConnection.stop();
|
|
117
|
-
instancesConnectionStopped = true;
|
|
118
|
-
};
|
|
119
|
-
}, [instancesSignalRConnection]);
|
|
9
|
+
const notifications = useNotification();
|
|
10
|
+
const [instanceCallbacks] = useState(
|
|
11
|
+
// Map provided callbacks to our wrappers that are sent to the underlying
|
|
12
|
+
// notification provider.
|
|
13
|
+
new WeakMap());
|
|
120
14
|
return (_jsx(SignalRConnectionContext.Provider, { value: {
|
|
121
|
-
documentChanges:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
15
|
+
documentChanges: {
|
|
16
|
+
subscribe: (topicName, callback) => {
|
|
17
|
+
var _a;
|
|
18
|
+
const [objectId, instanceId] = topicName.split('/');
|
|
19
|
+
(_a = notifications.documentChanges) === null || _a === void 0 ? void 0 : _a.subscribe(objectId, instanceId, callback);
|
|
20
|
+
},
|
|
21
|
+
unsubscribe: (topicName, callback) => {
|
|
22
|
+
var _a;
|
|
23
|
+
const [objectId, instanceId] = topicName.split('/');
|
|
24
|
+
(_a = notifications.documentChanges) === null || _a === void 0 ? void 0 : _a.unsubscribe(objectId, instanceId, callback);
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
instanceChanges: {
|
|
28
|
+
subscribe: (objectId, callback) => {
|
|
29
|
+
var _a;
|
|
30
|
+
// If there is already a wrapper for the given callback, we must reuse the
|
|
31
|
+
// same one. Otherwise, if we overwrite the entry in our cache, we'll lose
|
|
32
|
+
// track of the original wrapper.
|
|
33
|
+
let wrapper = instanceCallbacks.get(callback);
|
|
34
|
+
if (!wrapper) {
|
|
35
|
+
wrapper = (...changes) => {
|
|
36
|
+
callback(...changes.map((change) => change.instanceId));
|
|
37
|
+
};
|
|
38
|
+
instanceCallbacks.set(callback, wrapper);
|
|
39
|
+
}
|
|
40
|
+
(_a = notifications.instanceChanges) === null || _a === void 0 ? void 0 : _a.subscribe(objectId, wrapper);
|
|
41
|
+
},
|
|
42
|
+
unsubscribe: (objectId, callback) => {
|
|
43
|
+
var _a;
|
|
44
|
+
(_a = notifications.instanceChanges) === null || _a === void 0 ? void 0 : _a.unsubscribe(objectId, callback && instanceCallbacks.get(callback));
|
|
45
|
+
},
|
|
46
|
+
},
|
|
137
47
|
}, children: children }));
|
|
138
48
|
}
|
|
139
49
|
export function useSignalRConnection() {
|
|
50
|
+
console.warn('Use of useSignalRConnection is deprecated. Use useNotification instead.');
|
|
140
51
|
return useContext(SignalRConnectionContext);
|
|
141
52
|
}
|
|
142
53
|
export default SignalRConnectionProvider;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evoke-platform/context",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1-dev.0",
|
|
4
4
|
"description": "Utilities that provide context to Evoke platform widgets",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -35,24 +35,29 @@
|
|
|
35
35
|
"!dist/tests"
|
|
36
36
|
],
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@azure/msal-browser": "^2.38.
|
|
38
|
+
"@azure/msal-browser": "^2.38.4",
|
|
39
39
|
"@azure/msal-react": "^1.5.9",
|
|
40
|
+
"@testing-library/dom": "^10.4.0",
|
|
41
|
+
"@testing-library/react": "^16.0.1",
|
|
40
42
|
"@types/chai": "^4.3.11",
|
|
41
43
|
"@types/dirty-chai": "^2.0.4",
|
|
42
44
|
"@types/mocha": "^10.0.6",
|
|
43
45
|
"@types/node": "^18.15.7",
|
|
44
46
|
"@types/react": "^18.2.28",
|
|
45
|
-
"@types/uuid": "^9.0.8",
|
|
46
47
|
"@types/sinon": "^17.0.3",
|
|
47
|
-
"
|
|
48
|
+
"@types/uuid": "^9.0.8",
|
|
49
|
+
"chai": "^4.4.1",
|
|
48
50
|
"commit-and-tag-version": "^12.1.0",
|
|
49
51
|
"dirty-chai": "^2.0.1",
|
|
50
52
|
"eslint-plugin-react": "^7.33.2",
|
|
53
|
+
"global-jsdom": "^25.0.0",
|
|
54
|
+
"jsdom": "^25.0.1",
|
|
51
55
|
"mocha": "^10.2.0",
|
|
52
56
|
"msw": "^1.3.1",
|
|
53
57
|
"react": "^18.2.0",
|
|
58
|
+
"react-dom": "^18.3.1",
|
|
54
59
|
"react-router-dom": "^6.16.0",
|
|
55
|
-
"sinon": "^
|
|
60
|
+
"sinon": "^18.0.0",
|
|
56
61
|
"typescript": "^5.3.3"
|
|
57
62
|
},
|
|
58
63
|
"peerDependencies": {
|
|
@@ -63,7 +68,7 @@
|
|
|
63
68
|
},
|
|
64
69
|
"dependencies": {
|
|
65
70
|
"@microsoft/signalr": "^7.0.12",
|
|
66
|
-
"axios": "^1.
|
|
71
|
+
"axios": "^1.7.9",
|
|
67
72
|
"uuid": "^9.0.1"
|
|
68
73
|
}
|
|
69
74
|
}
|