keycloak-api-manager 3.1.0 → 3.2.1
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/.mocharc.json +7 -0
- package/Handlers/authenticationManagementHandler.js +1 -1
- package/Handlers/clientScopesHandler.js +5 -5
- package/Handlers/clientsHandler.js +1 -1
- package/Handlers/componentsHandler.js +2 -2
- package/Handlers/groupsHandler.js +2 -2
- package/Handlers/identityProvidersHandler.js +3 -3
- package/README.md +115 -16
- package/docker-compose.yml +27 -0
- package/index.js +1 -1
- package/index.mjs +21 -0
- package/package.json +14 -2
- package/test/authenticationManagement.test.js +329 -0
- package/test/clientScopes.test.js +256 -0
- package/test/clients.test.js +284 -0
- package/test/components.test.js +122 -0
- package/test/config.js +137 -0
- package/test/docker-helpers.js +111 -0
- package/test/groups.test.js +284 -0
- package/test/identityProviders.test.js +197 -0
- package/test/mocha.env.js +55 -0
- package/test/realms.test.js +349 -0
- package/test/roles.test.js +215 -0
- package/test/users.test.js +405 -0
- package/.idea/vcs.xml +0 -6
- package/.idea/workspace.xml +0 -93
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
const { expect } = require('chai');
|
|
2
|
+
const { getAdminClient } = require('./config');
|
|
3
|
+
|
|
4
|
+
describe('Users Handler', function () {
|
|
5
|
+
this.timeout(15000);
|
|
6
|
+
let client;
|
|
7
|
+
let testUserId;
|
|
8
|
+
let testGroupId;
|
|
9
|
+
let testRoleId;
|
|
10
|
+
|
|
11
|
+
before(async function () {
|
|
12
|
+
client = getAdminClient();
|
|
13
|
+
|
|
14
|
+
// Create test group and role for later tests
|
|
15
|
+
const group = await client.groups.create(
|
|
16
|
+
{ realm: 'test-realm' },
|
|
17
|
+
{ name: 'users-test-group' }
|
|
18
|
+
);
|
|
19
|
+
testGroupId = group.id;
|
|
20
|
+
|
|
21
|
+
const role = await client.roles.create(
|
|
22
|
+
{ realm: 'test-realm' },
|
|
23
|
+
{ name: 'users-test-role' }
|
|
24
|
+
);
|
|
25
|
+
testRoleId = role.id;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// ==================== USER CRUD ====================
|
|
29
|
+
describe('CRUD Operations', function () {
|
|
30
|
+
describe('create', function () {
|
|
31
|
+
it('should create a user with minimal representation', async function () {
|
|
32
|
+
const userRep = {
|
|
33
|
+
username: `testuser-${Date.now()}`,
|
|
34
|
+
enabled: true,
|
|
35
|
+
firstName: 'Test',
|
|
36
|
+
lastName: 'User',
|
|
37
|
+
email: `test-${Date.now()}@example.com`,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const result = await client.users.create({ realm: 'test-realm' }, userRep);
|
|
41
|
+
testUserId = result.id;
|
|
42
|
+
|
|
43
|
+
expect(result).to.have.property('id');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should fail creating duplicate username', async function () {
|
|
47
|
+
const username = `duplicate-${Date.now()}`;
|
|
48
|
+
|
|
49
|
+
await client.users.create(
|
|
50
|
+
{ realm: 'test-realm' },
|
|
51
|
+
{ username, enabled: true }
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
await client.users.create(
|
|
56
|
+
{ realm: 'test-realm' },
|
|
57
|
+
{ username, enabled: true }
|
|
58
|
+
);
|
|
59
|
+
expect.fail('Should have thrown an error for duplicate username');
|
|
60
|
+
} catch (err) {
|
|
61
|
+
expect(err).to.exist;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('find', function () {
|
|
67
|
+
it('should list users with pagination', async function () {
|
|
68
|
+
const users = await client.users.find({
|
|
69
|
+
realm: 'test-realm',
|
|
70
|
+
first: 0,
|
|
71
|
+
max: 10,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(users).to.be.an('array');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should search users by username', async function () {
|
|
78
|
+
const users = await client.users.find({
|
|
79
|
+
realm: 'test-realm',
|
|
80
|
+
username: 'testuser',
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(users).to.be.an('array');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should search users by email', async function () {
|
|
87
|
+
const users = await client.users.find({
|
|
88
|
+
realm: 'test-realm',
|
|
89
|
+
email: 'test@example.com',
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(users).to.be.an('array');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('findOne', function () {
|
|
97
|
+
it('should find a specific user by id', async function () {
|
|
98
|
+
const user = await client.users.findOne({
|
|
99
|
+
realm: 'test-realm',
|
|
100
|
+
id: testUserId,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(user).to.exist;
|
|
104
|
+
expect(user.id).to.equal(testUserId);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe('count', function () {
|
|
109
|
+
it('should count total users in realm', async function () {
|
|
110
|
+
const count = await client.users.count({
|
|
111
|
+
realm: 'test-realm',
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(count).to.be.a('number');
|
|
115
|
+
expect(count).to.be.greaterThan(0);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('update', function () {
|
|
120
|
+
it('should update user attributes', async function () {
|
|
121
|
+
const updateRep = {
|
|
122
|
+
firstName: 'Updated',
|
|
123
|
+
lastName: 'Name',
|
|
124
|
+
email: 'updated@example.com',
|
|
125
|
+
attributes: {
|
|
126
|
+
department: ['Engineering'],
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
await client.users.update(
|
|
131
|
+
{ realm: 'test-realm', id: testUserId },
|
|
132
|
+
updateRep
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const updated = await client.users.findOne({
|
|
136
|
+
realm: 'test-realm',
|
|
137
|
+
id: testUserId,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
expect(updated.firstName).to.equal('Updated');
|
|
141
|
+
expect(updated.attributes.department[0]).to.equal('Engineering');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// ==================== PASSWORD MANAGEMENT ====================
|
|
147
|
+
describe('Password Management', function () {
|
|
148
|
+
describe('resetPassword', function () {
|
|
149
|
+
it('should set/reset user password', async function () {
|
|
150
|
+
const passwordRep = {
|
|
151
|
+
type: 'password',
|
|
152
|
+
value: 'NewPassword123!@#',
|
|
153
|
+
temporary: false,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
await client.users.resetPassword(
|
|
157
|
+
{ realm: 'test-realm', id: testUserId },
|
|
158
|
+
passwordRep
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// Verify no error thrown
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('getCredentials', function () {
|
|
166
|
+
it('should retrieve user credentials', async function () {
|
|
167
|
+
const creds = await client.users.getCredentials({
|
|
168
|
+
realm: 'test-realm',
|
|
169
|
+
id: testUserId,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
expect(creds).to.be.an('array');
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('deleteCredential', function () {
|
|
177
|
+
it('should delete a user credential', async function () {
|
|
178
|
+
// First get credentials to have an id to delete
|
|
179
|
+
const creds = await client.users.getCredentials({
|
|
180
|
+
realm: 'test-realm',
|
|
181
|
+
id: testUserId,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
if (creds.length > 0) {
|
|
185
|
+
await client.users.deleteCredential({
|
|
186
|
+
realm: 'test-realm',
|
|
187
|
+
id: testUserId,
|
|
188
|
+
credentialId: creds[0].id,
|
|
189
|
+
});
|
|
190
|
+
// Verify no error thrown
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// ==================== GROUP MEMBERSHIP ====================
|
|
197
|
+
describe('Group Membership', function () {
|
|
198
|
+
describe('addToGroup', function () {
|
|
199
|
+
it('should add user to a group', async function () {
|
|
200
|
+
await client.users.addToGroup({
|
|
201
|
+
realm: 'test-realm',
|
|
202
|
+
id: testUserId,
|
|
203
|
+
groupId: testGroupId,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Verify in list groups
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe('listGroups', function () {
|
|
211
|
+
it('should list user groups', async function () {
|
|
212
|
+
const groups = await client.users.listGroups({
|
|
213
|
+
realm: 'test-realm',
|
|
214
|
+
id: testUserId,
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
expect(groups).to.be.an('array');
|
|
218
|
+
expect(groups.some((g) => g.id === testGroupId)).to.be.true;
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
describe('countGroups', function () {
|
|
223
|
+
it('should count user groups', async function () {
|
|
224
|
+
const count = await client.users.countGroups({
|
|
225
|
+
realm: 'test-realm',
|
|
226
|
+
id: testUserId,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
expect(count).to.be.a('number');
|
|
230
|
+
expect(count).to.be.greaterThan(0);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
describe('delFromGroup', function () {
|
|
235
|
+
it('should remove user from group', async function () {
|
|
236
|
+
await client.users.delFromGroup({
|
|
237
|
+
realm: 'test-realm',
|
|
238
|
+
id: testUserId,
|
|
239
|
+
groupId: testGroupId,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const groups = await client.users.listGroups({
|
|
243
|
+
realm: 'test-realm',
|
|
244
|
+
id: testUserId,
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
expect(groups.some((g) => g.id === testGroupId)).to.be.false;
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// ==================== ROLE MAPPINGS ====================
|
|
253
|
+
describe('Role Mappings', function () {
|
|
254
|
+
describe('addRealmRoleMappings', function () {
|
|
255
|
+
it('should add realm roles to user', async function () {
|
|
256
|
+
await client.users.addRealmRoleMappings({
|
|
257
|
+
realm: 'test-realm',
|
|
258
|
+
id: testUserId,
|
|
259
|
+
roles: [
|
|
260
|
+
{
|
|
261
|
+
id: testRoleId,
|
|
262
|
+
name: 'users-test-role',
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Verify role added
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
describe('listRoleMappings', function () {
|
|
272
|
+
it('should list all user role mappings', async function () {
|
|
273
|
+
const mappings = await client.users.listRoleMappings({
|
|
274
|
+
realm: 'test-realm',
|
|
275
|
+
id: testUserId,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
expect(mappings).to.be.an('object');
|
|
279
|
+
expect(mappings).to.have.property('realmMappings');
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
describe('listRealmRoleMappings', function () {
|
|
284
|
+
it('should list user realm role mappings', async function () {
|
|
285
|
+
const roles = await client.users.listRealmRoleMappings({
|
|
286
|
+
realm: 'test-realm',
|
|
287
|
+
id: testUserId,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
expect(roles).to.be.an('array');
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
describe('listCompositeRealmRoleMappings', function () {
|
|
295
|
+
it('should list composite realm role mappings', async function () {
|
|
296
|
+
const roles = await client.users.listCompositeRealmRoleMappings({
|
|
297
|
+
realm: 'test-realm',
|
|
298
|
+
id: testUserId,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
expect(roles).to.be.an('array');
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
describe('listAvailableRealmRoleMappings', function () {
|
|
306
|
+
it('should list available realm roles for user', async function () {
|
|
307
|
+
const availableRoles = await client.users.listAvailableRealmRoleMappings({
|
|
308
|
+
realm: 'test-realm',
|
|
309
|
+
id: testUserId,
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
expect(availableRoles).to.be.an('array');
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe('delRealmRoleMappings', function () {
|
|
317
|
+
it('should remove realm roles from user', async function () {
|
|
318
|
+
await client.users.delRealmRoleMappings({
|
|
319
|
+
realm: 'test-realm',
|
|
320
|
+
id: testUserId,
|
|
321
|
+
roles: [
|
|
322
|
+
{
|
|
323
|
+
id: testRoleId,
|
|
324
|
+
name: 'users-test-role',
|
|
325
|
+
},
|
|
326
|
+
],
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const mappings = await client.users.listRealmRoleMappings({
|
|
330
|
+
realm: 'test-realm',
|
|
331
|
+
id: testUserId,
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
expect(mappings.some((r) => r.id === testRoleId)).to.be.false;
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// ==================== SESSION MANAGEMENT ====================
|
|
340
|
+
describe('Session Management', function () {
|
|
341
|
+
describe('listSessions', function () {
|
|
342
|
+
it('should list user active sessions', async function () {
|
|
343
|
+
const sessions = await client.users.listSessions({
|
|
344
|
+
realm: 'test-realm',
|
|
345
|
+
id: testUserId,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
expect(sessions).to.be.an('array');
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
describe('listOfflineSessions', function () {
|
|
353
|
+
it('should list user offline sessions', async function () {
|
|
354
|
+
const sessions = await client.users.listOfflineSessions({
|
|
355
|
+
realm: 'test-realm',
|
|
356
|
+
id: testUserId,
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
expect(sessions).to.be.an('array');
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
describe('logout', function () {
|
|
364
|
+
it('should logout user from all sessions', async function () {
|
|
365
|
+
await client.users.logout({
|
|
366
|
+
realm: 'test-realm',
|
|
367
|
+
id: testUserId,
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// Verify no error thrown
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// ==================== FEDERATED IDENTITIES ====================
|
|
376
|
+
describe('Federated Identities', function () {
|
|
377
|
+
describe('listFederatedIdentities', function () {
|
|
378
|
+
it('should list user federated identities', async function () {
|
|
379
|
+
const identities = await client.users.listFederatedIdentities({
|
|
380
|
+
realm: 'test-realm',
|
|
381
|
+
id: testUserId,
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
expect(identities).to.be.an('array');
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// ==================== CLEANUP ====================
|
|
390
|
+
after(async function () {
|
|
391
|
+
try {
|
|
392
|
+
if (testUserId) {
|
|
393
|
+
await client.users.del({ realm: 'test-realm', id: testUserId });
|
|
394
|
+
}
|
|
395
|
+
if (testGroupId) {
|
|
396
|
+
await client.groups.del({ realm: 'test-realm', id: testGroupId });
|
|
397
|
+
}
|
|
398
|
+
if (testRoleId) {
|
|
399
|
+
await client.roles.del({ realm: 'test-realm', id: testRoleId });
|
|
400
|
+
}
|
|
401
|
+
} catch (err) {
|
|
402
|
+
console.error('Cleanup error:', err.message);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
});
|
package/.idea/vcs.xml
DELETED
package/.idea/workspace.xml
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="AutoImportSettings">
|
|
4
|
-
<option name="autoReloadType" value="SELECTIVE" />
|
|
5
|
-
</component>
|
|
6
|
-
<component name="ChangeListManager">
|
|
7
|
-
<list default="true" id="880daed6-aedf-444b-8c4d-611b1320145a" name="Changes" comment="">
|
|
8
|
-
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
|
9
|
-
<change beforePath="$PROJECT_DIR$/index.js" beforeDir="false" afterPath="$PROJECT_DIR$/index.js" afterDir="false" />
|
|
10
|
-
</list>
|
|
11
|
-
<option name="SHOW_DIALOG" value="false" />
|
|
12
|
-
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
13
|
-
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
14
|
-
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
15
|
-
</component>
|
|
16
|
-
<component name="FileTemplateManagerImpl">
|
|
17
|
-
<option name="RECENT_TEMPLATES">
|
|
18
|
-
<list>
|
|
19
|
-
<option value="JavaScript File" />
|
|
20
|
-
</list>
|
|
21
|
-
</option>
|
|
22
|
-
</component>
|
|
23
|
-
<component name="Git.Settings">
|
|
24
|
-
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
25
|
-
</component>
|
|
26
|
-
<component name="GitHubPullRequestSearchHistory">{
|
|
27
|
-
"lastFilter": {
|
|
28
|
-
"state": "OPEN",
|
|
29
|
-
"assignee": "aromanino"
|
|
30
|
-
}
|
|
31
|
-
}</component>
|
|
32
|
-
<component name="GithubPullRequestsUISettings">{
|
|
33
|
-
"selectedUrlAndAccountId": {
|
|
34
|
-
"url": "git@github.com:smartenv-crs4/keycloak-api-manager.git",
|
|
35
|
-
"accountId": "baec5ccc-6ac4-4547-bd61-37c96763840e"
|
|
36
|
-
}
|
|
37
|
-
}</component>
|
|
38
|
-
<component name="ProjectColorInfo">{
|
|
39
|
-
"associatedIndex": 7
|
|
40
|
-
}</component>
|
|
41
|
-
<component name="ProjectId" id="33k7K3DFOx1LzhDcuw8398H2Az4" />
|
|
42
|
-
<component name="ProjectViewState">
|
|
43
|
-
<option name="hideEmptyMiddlePackages" value="true" />
|
|
44
|
-
<option name="showLibraryContents" value="true" />
|
|
45
|
-
</component>
|
|
46
|
-
<component name="PropertiesComponent">{
|
|
47
|
-
"keyToString": {
|
|
48
|
-
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
49
|
-
"git-widget-placeholder": "main",
|
|
50
|
-
"last_opened_file_path": "/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/Handlers",
|
|
51
|
-
"node.js.detected.package.eslint": "true",
|
|
52
|
-
"node.js.detected.package.tslint": "true",
|
|
53
|
-
"node.js.selected.package.eslint": "(autodetect)",
|
|
54
|
-
"node.js.selected.package.tslint": "(autodetect)",
|
|
55
|
-
"nodejs_package_manager_path": "npm",
|
|
56
|
-
"ts.external.directory.path": "/Applications/WebStorm.app/Contents/plugins/javascript-plugin/jsLanguageServicesImpl/external",
|
|
57
|
-
"vue.rearranger.settings.migration": "true"
|
|
58
|
-
}
|
|
59
|
-
}</component>
|
|
60
|
-
<component name="RecentsManager">
|
|
61
|
-
<key name="CopyFile.RECENT_KEYS">
|
|
62
|
-
<recent name="$PROJECT_DIR$/Handlers" />
|
|
63
|
-
<recent name="$PROJECT_DIR$" />
|
|
64
|
-
</key>
|
|
65
|
-
<key name="MoveFile.RECENT_KEYS">
|
|
66
|
-
<recent name="$PROJECT_DIR$/Handlers" />
|
|
67
|
-
</key>
|
|
68
|
-
</component>
|
|
69
|
-
<component name="SharedIndexes">
|
|
70
|
-
<attachedChunks>
|
|
71
|
-
<set>
|
|
72
|
-
<option value="bundled-js-predefined-1d06a55b98c1-0b3e54e931b4-JavaScript-WS-241.18034.50" />
|
|
73
|
-
</set>
|
|
74
|
-
</attachedChunks>
|
|
75
|
-
</component>
|
|
76
|
-
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
77
|
-
<component name="TaskManager">
|
|
78
|
-
<task active="true" id="Default" summary="Default task">
|
|
79
|
-
<changelist id="880daed6-aedf-444b-8c4d-611b1320145a" name="Changes" comment="" />
|
|
80
|
-
<created>1759849149064</created>
|
|
81
|
-
<option name="number" value="Default" />
|
|
82
|
-
<option name="presentableId" value="Default" />
|
|
83
|
-
<updated>1759849149064</updated>
|
|
84
|
-
<workItem from="1759849150239" duration="1214000" />
|
|
85
|
-
<workItem from="1759917554117" duration="69806000" />
|
|
86
|
-
<workItem from="1761132079959" duration="2468000" />
|
|
87
|
-
</task>
|
|
88
|
-
<servers />
|
|
89
|
-
</component>
|
|
90
|
-
<component name="TypeScriptGeneratedFilesManager">
|
|
91
|
-
<option name="version" value="3" />
|
|
92
|
-
</component>
|
|
93
|
-
</project>
|