@ichicraft/widgets-widget-base 1.11.6 → 1.13.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 +11 -0
- package/lib/BaseWidget.js +3 -4
- package/lib/types/index.d.ts +26 -1
- package/lib/utils/ConfigurationHelper.js +7 -10
- package/lib/utils/UserHelper.js +50 -100
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,6 +9,17 @@ All notable changes to this project will be documented here.
|
|
|
9
9
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
10
10
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
11
11
|
|
|
12
|
+
## 1.13.0 - 2025-02-17
|
|
13
|
+
- Fixed an issue with detecting external users in `UserHelper`
|
|
14
|
+
- Changed target JavaScript version to `ES6`
|
|
15
|
+
|
|
16
|
+
## 1.12.0 - 2025-02-11
|
|
17
|
+
|
|
18
|
+
- Added `ColorOption` interface.
|
|
19
|
+
- Added `WidgetDesignContext` interface.
|
|
20
|
+
- Added `design` property of type `WidgetDesignContext` to `WidgetContext` interface, to support UI settings within widgets.
|
|
21
|
+
- Deprecated `elementBorderRadius` property which is renamed to `borderRadius` and moved under `design` property in `WidgetContext` interface.
|
|
22
|
+
|
|
12
23
|
## 1.11.6 - 2025-01-30
|
|
13
24
|
|
|
14
25
|
- Added `spServiceScope` property to `WidgetContext` interface.
|
package/lib/BaseWidget.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
class BaseWidget {
|
|
4
|
+
constructor(context) {
|
|
5
5
|
this.context = context;
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
}());
|
|
7
|
+
}
|
|
9
8
|
exports.default = BaseWidget;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -33,6 +33,10 @@ export interface WidgetContext {
|
|
|
33
33
|
* can exist in a widget board configuration.
|
|
34
34
|
*/
|
|
35
35
|
manifest: WidgetManifestContext;
|
|
36
|
+
/**
|
|
37
|
+
* Metadata in the context of the user's current theme, e.g. color settings and the preferred border radius for UI elements.
|
|
38
|
+
*/
|
|
39
|
+
design: WidgetDesignContext;
|
|
36
40
|
/**
|
|
37
41
|
* Tells whether the widget board is running in a Teams context
|
|
38
42
|
*/
|
|
@@ -158,7 +162,8 @@ export interface WidgetContext {
|
|
|
158
162
|
isCurrent?: boolean;
|
|
159
163
|
}[];
|
|
160
164
|
/**
|
|
161
|
-
* Preferred border radius of UI elements as configured in Widget Board configuration
|
|
165
|
+
* Preferred border radius of UI elements as configured in Widget Board configuration.
|
|
166
|
+
* @deprecated This property has been moved under `design`.
|
|
162
167
|
*/
|
|
163
168
|
elementBorderRadius: number;
|
|
164
169
|
/**
|
|
@@ -419,6 +424,21 @@ export interface WidgetManifestContext {
|
|
|
419
424
|
*/
|
|
420
425
|
id: string;
|
|
421
426
|
}
|
|
427
|
+
export interface WidgetDesignContext {
|
|
428
|
+
/** Available options in the ColorPicker.*/
|
|
429
|
+
colorOptions: ColorOption[];
|
|
430
|
+
/** Preferred border radius of UI elements.*/
|
|
431
|
+
borderRadius: number;
|
|
432
|
+
/** The height of a single row in the board grid. Use this to determine how many columns high a widget is. */
|
|
433
|
+
rowHeight: number;
|
|
434
|
+
/** Design settings related to icon badges. */
|
|
435
|
+
badge: {
|
|
436
|
+
/** Background color of an icon badge. */
|
|
437
|
+
color: string;
|
|
438
|
+
/** Inner text color of an icon badge. */
|
|
439
|
+
textColor: string;
|
|
440
|
+
};
|
|
441
|
+
}
|
|
422
442
|
export interface ValidationResult {
|
|
423
443
|
isValid: boolean;
|
|
424
444
|
errors: string[];
|
|
@@ -888,3 +908,8 @@ export interface BadgeProperties {
|
|
|
888
908
|
count?: number;
|
|
889
909
|
color?: string;
|
|
890
910
|
}
|
|
911
|
+
export interface ColorOption {
|
|
912
|
+
id: string;
|
|
913
|
+
title: string;
|
|
914
|
+
color: string;
|
|
915
|
+
}
|
|
@@ -5,21 +5,18 @@ exports.ConfigurationHelper = void 0;
|
|
|
5
5
|
* @class
|
|
6
6
|
* Helper class for Configuration related things.
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
|
-
function ConfigurationHelper() {
|
|
10
|
-
}
|
|
8
|
+
class ConfigurationHelper {
|
|
11
9
|
/**
|
|
12
10
|
*
|
|
13
11
|
* @param config The serialized configuration to parse into an object
|
|
14
12
|
* @param schema Deprecated: schema validation is no longer possible
|
|
15
13
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
static parseConfiguration(config, schema) {
|
|
15
|
+
const data = JSON.parse(config ? config : '{}');
|
|
18
16
|
return data;
|
|
19
|
-
}
|
|
20
|
-
|
|
17
|
+
}
|
|
18
|
+
static stringifyConfiguration(config) {
|
|
21
19
|
return JSON.stringify(config);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
}());
|
|
20
|
+
}
|
|
21
|
+
}
|
|
25
22
|
exports.ConfigurationHelper = ConfigurationHelper;
|
package/lib/utils/UserHelper.js
CHANGED
|
@@ -8,132 +8,83 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
-
function step(op) {
|
|
16
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
-
switch (op[0]) {
|
|
21
|
-
case 0: case 1: t = op; break;
|
|
22
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
-
default:
|
|
26
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
-
if (t[2]) _.ops.pop();
|
|
31
|
-
_.trys.pop(); continue;
|
|
32
|
-
}
|
|
33
|
-
op = body.call(thisArg, _);
|
|
34
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
12
|
exports.UserHelper = void 0;
|
|
40
|
-
|
|
13
|
+
const types_1 = require("../types");
|
|
41
14
|
/**
|
|
42
15
|
* @class
|
|
43
16
|
* Helper class for User related methods.
|
|
44
17
|
*/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
userIsPartOfThis = false;
|
|
55
|
-
i = 0;
|
|
56
|
-
_b.label = 1;
|
|
57
|
-
case 1:
|
|
58
|
-
if (!(i < personas.length)) return [3 /*break*/, 9];
|
|
59
|
-
personaItem = personas[i];
|
|
60
|
-
_a = personaItem.type;
|
|
61
|
-
switch (_a) {
|
|
62
|
-
case types_1.ICPersonaType.SPGroup: return [3 /*break*/, 2];
|
|
63
|
-
case types_1.ICPersonaType.User: return [3 /*break*/, 4];
|
|
64
|
-
case types_1.ICPersonaType.Other: return [3 /*break*/, 5];
|
|
65
|
-
case null: return [3 /*break*/, 5];
|
|
66
|
-
}
|
|
67
|
-
return [3 /*break*/, 7];
|
|
68
|
-
case 2: return [4 /*yield*/, context.isCurrentUserMemberOfSPGroup(Number.parseInt(personaItem.id))];
|
|
69
|
-
case 3:
|
|
70
|
-
userIsMemberOfSPGroup = _b.sent();
|
|
18
|
+
class UserHelper {
|
|
19
|
+
static isCurrentUserInScope(personas, context) {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
let userIsPartOfThis = false;
|
|
22
|
+
for (let i = 0; i < personas.length; i++) {
|
|
23
|
+
const personaItem = personas[i];
|
|
24
|
+
switch (personaItem.type) {
|
|
25
|
+
case types_1.ICPersonaType.SPGroup: {
|
|
26
|
+
const userIsMemberOfSPGroup = yield context.isCurrentUserMemberOfSPGroup(Number.parseInt(personaItem.id));
|
|
71
27
|
if (userIsMemberOfSPGroup) {
|
|
72
28
|
userIsPartOfThis = true;
|
|
73
29
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
return [3 /*break*/, 7];
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
case types_1.ICPersonaType.User: {
|
|
33
|
+
// handle a username exact match and partial match in case picker is in format 'i:0#.f|membership|USERNAME'
|
|
34
|
+
if (personaItem.id.toLowerCase() === context.userName.toLowerCase() ||
|
|
35
|
+
personaItem.id.toLowerCase() ===
|
|
36
|
+
context.claimBasedLoginName.toLowerCase() ||
|
|
37
|
+
(personaItem.id.indexOf('|') > -1 &&
|
|
38
|
+
personaItem.id
|
|
39
|
+
.toLowerCase()
|
|
40
|
+
.endsWith('|' + context.userName.toLowerCase()))) {
|
|
41
|
+
userIsPartOfThis = true;
|
|
88
42
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
case types_1.ICPersonaType.Other:
|
|
46
|
+
case null: {
|
|
47
|
+
let personaItemId = personaItem.id;
|
|
48
|
+
// Check if this is the infamous "Everyone except external users" group,
|
|
49
|
+
// in which case we need special treatment to check if the user is internal
|
|
93
50
|
if (personaItemId.indexOf('c:0-.f|rolemanager|spo-grid-all-users/') === 0) {
|
|
94
51
|
// There you have it: we need special treatment.
|
|
95
52
|
// If this is an external user, break, otherwise, assume user is member of group
|
|
96
|
-
if (context.claimBasedLoginName.indexOf('#ext#') === -1) {
|
|
97
|
-
// This is an internal user
|
|
53
|
+
if (context.claimBasedLoginName.toLocaleLowerCase().indexOf('#ext#') === -1) {
|
|
54
|
+
// This is an internal user and thus a member of the group
|
|
98
55
|
userIsPartOfThis = true;
|
|
99
56
|
}
|
|
100
|
-
|
|
57
|
+
break;
|
|
101
58
|
}
|
|
102
59
|
// Check if the id of the picker item contains a pipe, this means we need to strip the id
|
|
103
60
|
if (personaItemId.indexOf('|') > -1) {
|
|
104
61
|
personaItemId = personaItemId.split('|').slice(-1)[0];
|
|
105
62
|
}
|
|
106
|
-
|
|
107
|
-
case 6:
|
|
108
|
-
userIsMemberOfSecGroup = _b.sent();
|
|
63
|
+
const userIsMemberOfSecGroup = yield context.isCurrentUserMemberOfSecGroup(personaItemId);
|
|
109
64
|
if (userIsMemberOfSecGroup) {
|
|
110
65
|
userIsPartOfThis = true;
|
|
111
66
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (userIsPartOfThis)
|
|
115
|
-
return [3 /*break*/, 9];
|
|
116
|
-
_b.label = 8;
|
|
117
|
-
case 8:
|
|
118
|
-
i++;
|
|
119
|
-
return [3 /*break*/, 1];
|
|
120
|
-
case 9: return [2 /*return*/, userIsPartOfThis];
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
121
69
|
}
|
|
122
|
-
|
|
70
|
+
if (userIsPartOfThis)
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
return userIsPartOfThis;
|
|
123
74
|
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
75
|
+
}
|
|
76
|
+
static gatherAllNormalizedUserPersonaIds(userName, claimBasedLoginName, spGroups, secGroups) {
|
|
77
|
+
const personas = [];
|
|
127
78
|
// 1. The user name in two known shapes
|
|
128
|
-
personas.push(
|
|
129
|
-
personas.push(
|
|
79
|
+
personas.push(`USER|${userName.toLowerCase()}`);
|
|
80
|
+
personas.push(`USER|${claimBasedLoginName.toLowerCase()}`);
|
|
130
81
|
// 2. The SP Groups, just as they are: numeric strings
|
|
131
|
-
spGroups.forEach(
|
|
132
|
-
personas.push(
|
|
82
|
+
spGroups.forEach((spg) => {
|
|
83
|
+
personas.push(`SPGROUP|${spg}`);
|
|
133
84
|
});
|
|
134
85
|
// 3. The Security Groups, as Guids
|
|
135
|
-
secGroups.forEach(
|
|
136
|
-
personas.push(
|
|
86
|
+
secGroups.forEach((secg) => {
|
|
87
|
+
personas.push(`ADGROUP|${secg.toLowerCase()}`);
|
|
137
88
|
});
|
|
138
89
|
// 4. Optionally the all users except external users group:
|
|
139
90
|
if (claimBasedLoginName.indexOf('#ext#') === -1) {
|
|
@@ -141,7 +92,6 @@ var UserHelper = /** @class */ (function () {
|
|
|
141
92
|
personas.push('ADGROUP|spo-grid-all-users');
|
|
142
93
|
}
|
|
143
94
|
return personas;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
}());
|
|
95
|
+
}
|
|
96
|
+
}
|
|
147
97
|
exports.UserHelper = UserHelper;
|
package/package.json
CHANGED