@trackunit/react-core-hooks 1.12.43 → 1.12.44-alpha-57a40ea11fa.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/index.cjs.js +48 -36
- package/index.esm.js +48 -36
- package/package.json +4 -4
- package/src/navigation/useHasAccessTo.d.ts +19 -20
package/index.cjs.js
CHANGED
|
@@ -379,64 +379,76 @@ const useModalDialogContext = () => {
|
|
|
379
379
|
return modalDialogContext;
|
|
380
380
|
};
|
|
381
381
|
|
|
382
|
-
const isMultipleCriteriaOneOf = (options) =>
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
382
|
+
const isMultipleCriteriaOneOf = (options) => typeof options === "object" && "oneOf" in options;
|
|
383
|
+
const isMultipleCriteriaRequireAll = (options) => typeof options === "object" && "requireAll" in options;
|
|
384
|
+
const resolveAccess = async (context, options) => {
|
|
385
|
+
if (isMultipleCriteriaOneOf(options) && isMultipleCriteriaRequireAll(options)) {
|
|
386
|
+
throw new Error("Multiple criteria are not allowed, use one of or require all - not both");
|
|
387
|
+
}
|
|
388
|
+
if (isMultipleCriteriaOneOf(options)) {
|
|
389
|
+
const results = await Promise.all(options.oneOf.map(option => context.hasAccessTo(option)));
|
|
390
|
+
return results.some(Boolean);
|
|
391
|
+
}
|
|
392
|
+
if (isMultipleCriteriaRequireAll(options)) {
|
|
393
|
+
const results = await Promise.all(options.requireAll.map(option => context.hasAccessTo(option)));
|
|
394
|
+
return results.every(Boolean);
|
|
395
|
+
}
|
|
396
|
+
return context.hasAccessTo(options);
|
|
387
397
|
};
|
|
388
398
|
/**
|
|
389
|
-
*
|
|
390
|
-
*
|
|
399
|
+
* Hook to check if the current user has access to a navigation target.
|
|
400
|
+
* Useful for conditionally rendering links based on user permissions.
|
|
391
401
|
*
|
|
392
402
|
* @requires NavigationContext
|
|
393
403
|
* @example
|
|
394
404
|
* import { useHasAccessTo } from "@trackunit/react-core-hooks";
|
|
395
405
|
* useHasAccessTo({ assetId: assetInfo?.assetId, page: "movement" })
|
|
396
|
-
* @see
|
|
397
|
-
* @see
|
|
398
|
-
* @see (@link HasAccessToOptions.assetId)
|
|
399
|
-
* @see (@link HasAccessToOptions.page)
|
|
400
|
-
* @see (@link HasAccessToOptions.siteId)
|
|
401
|
-
* @see (@link NavigationRuntimeApi)
|
|
406
|
+
* @see {@link NavigationRuntimeApi}
|
|
407
|
+
* @see {@link HasAccessToOptions}
|
|
402
408
|
*/
|
|
403
409
|
const useHasAccessTo = (options) => {
|
|
404
410
|
const context = react.useContext(reactCoreContextsApi.NavigationContext);
|
|
405
|
-
|
|
406
|
-
throw new Error("useHasAccessTo must be used within an NavigationContext");
|
|
407
|
-
}
|
|
411
|
+
const [stableOptions, setStableOptions] = react.useState(options);
|
|
408
412
|
const [hasAccess, setHasAccess] = react.useState();
|
|
409
413
|
const [loading, setLoading] = react.useState(true);
|
|
410
414
|
const [error, setError] = react.useState();
|
|
415
|
+
if (JSON.stringify(stableOptions) !== JSON.stringify(options)) {
|
|
416
|
+
setStableOptions(options);
|
|
417
|
+
}
|
|
411
418
|
react.useEffect(() => {
|
|
412
|
-
|
|
419
|
+
if (!context)
|
|
420
|
+
return;
|
|
421
|
+
let cancelled = false;
|
|
422
|
+
setLoading(true);
|
|
423
|
+
setError(undefined);
|
|
424
|
+
const checkAccess = async () => {
|
|
413
425
|
try {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (isMultipleCriteriaOneOf(options)) {
|
|
418
|
-
const doHaveAccess = await Promise.all(options.oneOf.map(option => context?.hasAccessTo(option)));
|
|
419
|
-
setHasAccess(doHaveAccess.some(access => access));
|
|
420
|
-
}
|
|
421
|
-
else if (isMultipleCriteriaRequireAll(options)) {
|
|
422
|
-
const doHaveAccess = await Promise.all(options.requireAll.map(option => context?.hasAccessTo(option)));
|
|
423
|
-
setHasAccess(doHaveAccess.every(access => access));
|
|
424
|
-
}
|
|
425
|
-
else {
|
|
426
|
-
const doHaveAccess = await context?.hasAccessTo(options);
|
|
427
|
-
setHasAccess(doHaveAccess);
|
|
426
|
+
const accessResult = await resolveAccess(context, stableOptions);
|
|
427
|
+
if (!cancelled) {
|
|
428
|
+
setHasAccess(accessResult);
|
|
428
429
|
}
|
|
429
430
|
}
|
|
430
431
|
catch (e) {
|
|
431
|
-
|
|
432
|
+
if (!cancelled) {
|
|
433
|
+
setError(new Error("Failed to check access", { cause: e }));
|
|
434
|
+
}
|
|
432
435
|
}
|
|
433
436
|
finally {
|
|
434
|
-
|
|
437
|
+
if (!cancelled) {
|
|
438
|
+
setLoading(false);
|
|
439
|
+
}
|
|
435
440
|
}
|
|
436
|
-
}
|
|
441
|
+
};
|
|
437
442
|
void checkAccess();
|
|
438
|
-
|
|
439
|
-
|
|
443
|
+
return () => {
|
|
444
|
+
cancelled = true;
|
|
445
|
+
};
|
|
446
|
+
}, [context, stableOptions]);
|
|
447
|
+
const result = react.useMemo(() => ({ hasAccess, loading, error }), [hasAccess, loading, error]);
|
|
448
|
+
if (!context) {
|
|
449
|
+
throw new Error("useHasAccessTo must be used within a NavigationContext");
|
|
450
|
+
}
|
|
451
|
+
return result;
|
|
440
452
|
};
|
|
441
453
|
|
|
442
454
|
/**
|
package/index.esm.js
CHANGED
|
@@ -377,64 +377,76 @@ const useModalDialogContext = () => {
|
|
|
377
377
|
return modalDialogContext;
|
|
378
378
|
};
|
|
379
379
|
|
|
380
|
-
const isMultipleCriteriaOneOf = (options) =>
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
380
|
+
const isMultipleCriteriaOneOf = (options) => typeof options === "object" && "oneOf" in options;
|
|
381
|
+
const isMultipleCriteriaRequireAll = (options) => typeof options === "object" && "requireAll" in options;
|
|
382
|
+
const resolveAccess = async (context, options) => {
|
|
383
|
+
if (isMultipleCriteriaOneOf(options) && isMultipleCriteriaRequireAll(options)) {
|
|
384
|
+
throw new Error("Multiple criteria are not allowed, use one of or require all - not both");
|
|
385
|
+
}
|
|
386
|
+
if (isMultipleCriteriaOneOf(options)) {
|
|
387
|
+
const results = await Promise.all(options.oneOf.map(option => context.hasAccessTo(option)));
|
|
388
|
+
return results.some(Boolean);
|
|
389
|
+
}
|
|
390
|
+
if (isMultipleCriteriaRequireAll(options)) {
|
|
391
|
+
const results = await Promise.all(options.requireAll.map(option => context.hasAccessTo(option)));
|
|
392
|
+
return results.every(Boolean);
|
|
393
|
+
}
|
|
394
|
+
return context.hasAccessTo(options);
|
|
385
395
|
};
|
|
386
396
|
/**
|
|
387
|
-
*
|
|
388
|
-
*
|
|
397
|
+
* Hook to check if the current user has access to a navigation target.
|
|
398
|
+
* Useful for conditionally rendering links based on user permissions.
|
|
389
399
|
*
|
|
390
400
|
* @requires NavigationContext
|
|
391
401
|
* @example
|
|
392
402
|
* import { useHasAccessTo } from "@trackunit/react-core-hooks";
|
|
393
403
|
* useHasAccessTo({ assetId: assetInfo?.assetId, page: "movement" })
|
|
394
|
-
* @see
|
|
395
|
-
* @see
|
|
396
|
-
* @see (@link HasAccessToOptions.assetId)
|
|
397
|
-
* @see (@link HasAccessToOptions.page)
|
|
398
|
-
* @see (@link HasAccessToOptions.siteId)
|
|
399
|
-
* @see (@link NavigationRuntimeApi)
|
|
404
|
+
* @see {@link NavigationRuntimeApi}
|
|
405
|
+
* @see {@link HasAccessToOptions}
|
|
400
406
|
*/
|
|
401
407
|
const useHasAccessTo = (options) => {
|
|
402
408
|
const context = useContext(NavigationContext);
|
|
403
|
-
|
|
404
|
-
throw new Error("useHasAccessTo must be used within an NavigationContext");
|
|
405
|
-
}
|
|
409
|
+
const [stableOptions, setStableOptions] = useState(options);
|
|
406
410
|
const [hasAccess, setHasAccess] = useState();
|
|
407
411
|
const [loading, setLoading] = useState(true);
|
|
408
412
|
const [error, setError] = useState();
|
|
413
|
+
if (JSON.stringify(stableOptions) !== JSON.stringify(options)) {
|
|
414
|
+
setStableOptions(options);
|
|
415
|
+
}
|
|
409
416
|
useEffect(() => {
|
|
410
|
-
|
|
417
|
+
if (!context)
|
|
418
|
+
return;
|
|
419
|
+
let cancelled = false;
|
|
420
|
+
setLoading(true);
|
|
421
|
+
setError(undefined);
|
|
422
|
+
const checkAccess = async () => {
|
|
411
423
|
try {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
if (isMultipleCriteriaOneOf(options)) {
|
|
416
|
-
const doHaveAccess = await Promise.all(options.oneOf.map(option => context?.hasAccessTo(option)));
|
|
417
|
-
setHasAccess(doHaveAccess.some(access => access));
|
|
418
|
-
}
|
|
419
|
-
else if (isMultipleCriteriaRequireAll(options)) {
|
|
420
|
-
const doHaveAccess = await Promise.all(options.requireAll.map(option => context?.hasAccessTo(option)));
|
|
421
|
-
setHasAccess(doHaveAccess.every(access => access));
|
|
422
|
-
}
|
|
423
|
-
else {
|
|
424
|
-
const doHaveAccess = await context?.hasAccessTo(options);
|
|
425
|
-
setHasAccess(doHaveAccess);
|
|
424
|
+
const accessResult = await resolveAccess(context, stableOptions);
|
|
425
|
+
if (!cancelled) {
|
|
426
|
+
setHasAccess(accessResult);
|
|
426
427
|
}
|
|
427
428
|
}
|
|
428
429
|
catch (e) {
|
|
429
|
-
|
|
430
|
+
if (!cancelled) {
|
|
431
|
+
setError(new Error("Failed to check access", { cause: e }));
|
|
432
|
+
}
|
|
430
433
|
}
|
|
431
434
|
finally {
|
|
432
|
-
|
|
435
|
+
if (!cancelled) {
|
|
436
|
+
setLoading(false);
|
|
437
|
+
}
|
|
433
438
|
}
|
|
434
|
-
}
|
|
439
|
+
};
|
|
435
440
|
void checkAccess();
|
|
436
|
-
|
|
437
|
-
|
|
441
|
+
return () => {
|
|
442
|
+
cancelled = true;
|
|
443
|
+
};
|
|
444
|
+
}, [context, stableOptions]);
|
|
445
|
+
const result = useMemo(() => ({ hasAccess, loading, error }), [hasAccess, loading, error]);
|
|
446
|
+
if (!context) {
|
|
447
|
+
throw new Error("useHasAccessTo must be used within a NavigationContext");
|
|
448
|
+
}
|
|
449
|
+
return result;
|
|
438
450
|
};
|
|
439
451
|
|
|
440
452
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-core-hooks",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.44-alpha-57a40ea11fa.0",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"react": "19.0.0",
|
|
11
|
-
"@trackunit/iris-app-runtime-core": "1.13.
|
|
12
|
-
"@trackunit/iris-app-runtime-core-api": "1.12.
|
|
13
|
-
"@trackunit/react-core-contexts-api": "1.13.
|
|
11
|
+
"@trackunit/iris-app-runtime-core": "1.13.42-alpha-57a40ea11fa.0",
|
|
12
|
+
"@trackunit/iris-app-runtime-core-api": "1.12.40-alpha-57a40ea11fa.0",
|
|
13
|
+
"@trackunit/react-core-contexts-api": "1.13.40-alpha-57a40ea11fa.0"
|
|
14
14
|
},
|
|
15
15
|
"module": "./index.esm.js",
|
|
16
16
|
"main": "./index.cjs.js",
|
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import { HasAccessToOptions } from "@trackunit/iris-app-runtime-core-api";
|
|
2
|
-
export
|
|
3
|
-
oneOf: Array<HasAccessToOptions>;
|
|
4
|
-
}
|
|
5
|
-
export
|
|
6
|
-
requireAll: Array<HasAccessToOptions>;
|
|
7
|
-
}
|
|
1
|
+
import type { HasAccessToOptions } from "@trackunit/iris-app-runtime-core-api";
|
|
2
|
+
export type MultipleCriteriaOneOf = {
|
|
3
|
+
readonly oneOf: Array<HasAccessToOptions>;
|
|
4
|
+
};
|
|
5
|
+
export type MultipleCriteriaRequireAll = {
|
|
6
|
+
readonly requireAll: Array<HasAccessToOptions>;
|
|
7
|
+
};
|
|
8
|
+
type AccessOptions = HasAccessToOptions | MultipleCriteriaOneOf | MultipleCriteriaRequireAll;
|
|
9
|
+
type UseHasAccessToResult = {
|
|
10
|
+
readonly hasAccess: boolean | undefined;
|
|
11
|
+
readonly loading: boolean;
|
|
12
|
+
readonly error: Error | undefined;
|
|
13
|
+
};
|
|
8
14
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
15
|
+
* Hook to check if the current user has access to a navigation target.
|
|
16
|
+
* Useful for conditionally rendering links based on user permissions.
|
|
11
17
|
*
|
|
12
18
|
* @requires NavigationContext
|
|
13
19
|
* @example
|
|
14
20
|
* import { useHasAccessTo } from "@trackunit/react-core-hooks";
|
|
15
21
|
* useHasAccessTo({ assetId: assetInfo?.assetId, page: "movement" })
|
|
16
|
-
* @see
|
|
17
|
-
* @see
|
|
18
|
-
* @see (@link HasAccessToOptions.assetId)
|
|
19
|
-
* @see (@link HasAccessToOptions.page)
|
|
20
|
-
* @see (@link HasAccessToOptions.siteId)
|
|
21
|
-
* @see (@link NavigationRuntimeApi)
|
|
22
|
+
* @see {@link NavigationRuntimeApi}
|
|
23
|
+
* @see {@link HasAccessToOptions}
|
|
22
24
|
*/
|
|
23
|
-
export declare const useHasAccessTo: (options:
|
|
24
|
-
|
|
25
|
-
loading: boolean;
|
|
26
|
-
error: Error | undefined;
|
|
27
|
-
};
|
|
25
|
+
export declare const useHasAccessTo: (options: AccessOptions) => UseHasAccessToResult;
|
|
26
|
+
export {};
|