@webiny/app-record-locking 6.3.0-beta.4 → 6.4.0-beta.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.
Files changed (101) hide show
  1. package/components/HeadlessCmsActionsAcoCell.js +29 -51
  2. package/components/HeadlessCmsActionsAcoCell.js.map +1 -1
  3. package/components/HeadlessCmsContentEntry/ContentEntryGuard.js +26 -34
  4. package/components/HeadlessCmsContentEntry/ContentEntryGuard.js.map +1 -1
  5. package/components/HeadlessCmsContentEntry/ContentEntryLocker.js +70 -89
  6. package/components/HeadlessCmsContentEntry/ContentEntryLocker.js.map +1 -1
  7. package/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.js +38 -62
  8. package/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.js.map +1 -1
  9. package/components/HeadlessCmsContentEntry/index.js +0 -2
  10. package/components/LockedRecord/LockedRecord.js +45 -57
  11. package/components/LockedRecord/LockedRecord.js.map +1 -1
  12. package/components/LockedRecord/LockedRecordForceUnlock.js +49 -63
  13. package/components/LockedRecord/LockedRecordForceUnlock.js.map +1 -1
  14. package/components/LockedRecord/index.js +0 -2
  15. package/components/RecordLockingProvider.js +103 -117
  16. package/components/RecordLockingProvider.js.map +1 -1
  17. package/components/SecurityPermissions.js +11 -14
  18. package/components/SecurityPermissions.js.map +1 -1
  19. package/components/decorators/UseContentEntriesListHookDecorator.js +18 -18
  20. package/components/decorators/UseContentEntriesListHookDecorator.js.map +1 -1
  21. package/components/decorators/UseRecordsDecorator.js +13 -22
  22. package/components/decorators/UseRecordsDecorator.js.map +1 -1
  23. package/components/decorators/UseSaveEntryDecorator.js +35 -49
  24. package/components/decorators/UseSaveEntryDecorator.js.map +1 -1
  25. package/domain/RecordLocking.js +229 -291
  26. package/domain/RecordLocking.js.map +1 -1
  27. package/domain/RecordLockingClient.js +17 -16
  28. package/domain/RecordLockingClient.js.map +1 -1
  29. package/domain/RecordLockingGetLockRecord.js +13 -15
  30. package/domain/RecordLockingGetLockRecord.js.map +1 -1
  31. package/domain/RecordLockingGetLockedEntryLockRecord.js +12 -13
  32. package/domain/RecordLockingGetLockedEntryLockRecord.js.map +1 -1
  33. package/domain/RecordLockingIsEntryLocked.js +15 -14
  34. package/domain/RecordLockingIsEntryLocked.js.map +1 -1
  35. package/domain/RecordLockingListLockRecords.js +18 -24
  36. package/domain/RecordLockingListLockRecords.js.map +1 -1
  37. package/domain/RecordLockingLockEntry.js +8 -9
  38. package/domain/RecordLockingLockEntry.js.map +1 -1
  39. package/domain/RecordLockingUnlockEntry.js +12 -13
  40. package/domain/RecordLockingUnlockEntry.js.map +1 -1
  41. package/domain/RecordLockingUpdateEntryLock.js +12 -13
  42. package/domain/RecordLockingUpdateEntryLock.js.map +1 -1
  43. package/domain/abstractions/IRecordLocking.js +0 -3
  44. package/domain/abstractions/IRecordLockingClient.js +0 -3
  45. package/domain/abstractions/IRecordLockingGetLockRecord.js +0 -3
  46. package/domain/abstractions/IRecordLockingGetLockedEntryLockRecord.js +0 -3
  47. package/domain/abstractions/IRecordLockingIsEntryLocked.js +0 -3
  48. package/domain/abstractions/IRecordLockingListLockRecords.js +0 -3
  49. package/domain/abstractions/IRecordLockingLockEntry.js +0 -3
  50. package/domain/abstractions/IRecordLockingUnlockEntry.js +0 -3
  51. package/domain/abstractions/IRecordLockingUpdateEntryLock.js +0 -3
  52. package/domain/graphql/fields.js +3 -2
  53. package/domain/graphql/fields.js.map +1 -1
  54. package/domain/graphql/getLockRecord.js +3 -2
  55. package/domain/graphql/getLockRecord.js.map +1 -1
  56. package/domain/graphql/getLockedEntryLockRecord.js +3 -2
  57. package/domain/graphql/getLockedEntryLockRecord.js.map +1 -1
  58. package/domain/graphql/isEntryLocked.js +3 -2
  59. package/domain/graphql/isEntryLocked.js.map +1 -1
  60. package/domain/graphql/listLockRecords.js +4 -5
  61. package/domain/graphql/listLockRecords.js.map +1 -1
  62. package/domain/graphql/lockEntry.js +3 -4
  63. package/domain/graphql/lockEntry.js.map +1 -1
  64. package/domain/graphql/unlockEntry.js +3 -2
  65. package/domain/graphql/unlockEntry.js.map +1 -1
  66. package/domain/graphql/updateEntryLock.js +3 -2
  67. package/domain/graphql/updateEntryLock.js.map +1 -1
  68. package/domain/permissionsSchema.js +6 -5
  69. package/domain/permissionsSchema.js.map +1 -1
  70. package/domain/utils/createRecordLockingClient.js +5 -6
  71. package/domain/utils/createRecordLockingClient.js.map +1 -1
  72. package/domain/utils/createRecordLockingError.js +10 -11
  73. package/domain/utils/createRecordLockingError.js.map +1 -1
  74. package/features/permissions/abstractions.js +2 -1
  75. package/features/permissions/abstractions.js.map +1 -1
  76. package/features/permissions/feature.js +2 -1
  77. package/features/permissions/feature.js.map +1 -1
  78. package/hooks/index.js +0 -2
  79. package/hooks/usePermission.js +14 -15
  80. package/hooks/usePermission.js.map +1 -1
  81. package/hooks/useRecordLocking.js +5 -6
  82. package/hooks/useRecordLocking.js.map +1 -1
  83. package/index.js +15 -21
  84. package/index.js.map +1 -1
  85. package/package.json +12 -12
  86. package/types.js +0 -3
  87. package/utils/createCacheKey.js +9 -10
  88. package/utils/createCacheKey.js.map +1 -1
  89. package/components/HeadlessCmsContentEntry/index.js.map +0 -1
  90. package/components/LockedRecord/index.js.map +0 -1
  91. package/domain/abstractions/IRecordLocking.js.map +0 -1
  92. package/domain/abstractions/IRecordLockingClient.js.map +0 -1
  93. package/domain/abstractions/IRecordLockingGetLockRecord.js.map +0 -1
  94. package/domain/abstractions/IRecordLockingGetLockedEntryLockRecord.js.map +0 -1
  95. package/domain/abstractions/IRecordLockingIsEntryLocked.js.map +0 -1
  96. package/domain/abstractions/IRecordLockingListLockRecords.js.map +0 -1
  97. package/domain/abstractions/IRecordLockingLockEntry.js.map +0 -1
  98. package/domain/abstractions/IRecordLockingUnlockEntry.js.map +0 -1
  99. package/domain/abstractions/IRecordLockingUpdateEntryLock.js.map +0 -1
  100. package/hooks/index.js.map +0 -1
  101. package/types.js.map +0 -1
@@ -10,312 +10,250 @@ import { createCacheKey } from "../utils/createCacheKey.js";
10
10
  import { RecordLockingUpdateEntryLock } from "./RecordLockingUpdateEntryLock.js";
11
11
  import { RecordLockingGetLockedEntryLockRecord } from "./RecordLockingGetLockedEntryLockRecord.js";
12
12
  class RecordLocking {
13
- loading = false;
14
- records = [];
15
- onErrorCb = null;
16
- constructor(params) {
17
- this._setLoading = params.setLoading;
18
- this._getLockRecord = params.getLockRecord;
19
- this._getLockedEntryLockRecord = params.getLockedEntryLockRecord;
20
- this._listLockRecords = params.listLockRecords;
21
- this._unlockEntry = params.unlockEntry;
22
- this._updateEntryLock = params.updateEntryLock;
23
- }
24
- async setRecords(folderId, type, records) {
25
- const result = await this.fetchAndAssignRecords(folderId, type, records);
26
- if (!result) {
27
- return undefined;
13
+ constructor(params){
14
+ this.loading = false;
15
+ this.records = [];
16
+ this.onErrorCb = null;
17
+ this._setLoading = params.setLoading;
18
+ this._getLockRecord = params.getLockRecord;
19
+ this._getLockedEntryLockRecord = params.getLockedEntryLockRecord;
20
+ this._listLockRecords = params.listLockRecords;
21
+ this._unlockEntry = params.unlockEntry;
22
+ this._updateEntryLock = params.updateEntryLock;
28
23
  }
29
- return result.map(record => {
30
- const {
31
- id: entryId
32
- } = parseIdentifier(record.id);
33
- return {
34
- ...record,
35
- $type: "RECORD",
36
- $lockingType: type,
37
- $locked: record.$locked,
38
- $selectable: record.$locked ? false : record.$selectable,
39
- entryId
40
- };
41
- });
42
- }
43
- async fetchLockRecord(params) {
44
- const {
45
- id,
46
- $lockingType
47
- } = params;
48
- const {
49
- id: entryId
50
- } = parseIdentifier(id);
51
- try {
52
- const result = await this._getLockRecord.execute({
53
- id: entryId,
54
- type: $lockingType
55
- });
56
- return {
57
- data: result.data,
58
- error: result.error
59
- };
60
- } catch (ex) {
61
- return {
62
- data: null,
63
- error: ex
64
- };
24
+ async setRecords(folderId, type, records) {
25
+ const result = await this.fetchAndAssignRecords(folderId, type, records);
26
+ if (!result) return;
27
+ return result.map((record)=>{
28
+ const { id: entryId } = parseIdentifier(record.id);
29
+ return {
30
+ ...record,
31
+ $type: "RECORD",
32
+ $lockingType: type,
33
+ $locked: record.$locked,
34
+ $selectable: record.$locked ? false : record.$selectable,
35
+ entryId
36
+ };
37
+ });
65
38
  }
66
- }
67
- async fetchLockedEntryLockRecord(params) {
68
- const {
69
- id,
70
- $lockingType
71
- } = params;
72
- const {
73
- id: entryId
74
- } = parseIdentifier(id);
75
- const result = await this._getLockedEntryLockRecord.execute({
76
- id: entryId,
77
- type: $lockingType
78
- });
79
- return result.data;
80
- }
81
- getLockRecordEntry(id) {
82
- return this.records.find(record => {
83
- const {
84
- id: entryId
85
- } = parseIdentifier(id);
86
- return record.entryId === entryId;
87
- });
88
- }
89
- isRecordLocked(record) {
90
- const result = this.records.find(r => {
91
- const {
92
- id: entryId
93
- } = parseIdentifier(record.id);
94
- return r.entryId === entryId && !!r.$locked && r.$lockingType === record.$lockingType;
95
- });
96
- if (!result?.$locked?.expiresOn) {
97
- return false;
39
+ async fetchLockRecord(params) {
40
+ const { id, $lockingType } = params;
41
+ const { id: entryId } = parseIdentifier(id);
42
+ try {
43
+ const result = await this._getLockRecord.execute({
44
+ id: entryId,
45
+ type: $lockingType
46
+ });
47
+ return {
48
+ data: result.data,
49
+ error: result.error
50
+ };
51
+ } catch (ex) {
52
+ return {
53
+ data: null,
54
+ error: ex
55
+ };
56
+ }
98
57
  }
99
- const isExpired = this.isLockExpired(result.$locked.expiresOn);
100
- return !isExpired;
101
- }
102
- async updateEntryLock(params) {
103
- try {
104
- return await this._updateEntryLock.execute({
105
- id: params.id,
106
- type: params.$lockingType
107
- });
108
- } catch (ex) {
109
- this.triggerOnError(ex);
110
- return {
111
- data: null,
112
- error: ex
113
- };
58
+ async fetchLockedEntryLockRecord(params) {
59
+ const { id, $lockingType } = params;
60
+ const { id: entryId } = parseIdentifier(id);
61
+ const result = await this._getLockedEntryLockRecord.execute({
62
+ id: entryId,
63
+ type: $lockingType
64
+ });
65
+ return result.data;
114
66
  }
115
- }
116
- removeEntryLock(params) {
117
- const index = this.records.findIndex(record => {
118
- return record.entryId === params.id && record.$lockingType === params.$lockingType;
119
- });
120
- if (index === -1) {
121
- return;
67
+ getLockRecordEntry(id) {
68
+ return this.records.find((record)=>{
69
+ const { id: entryId } = parseIdentifier(id);
70
+ return record.entryId === entryId;
71
+ });
122
72
  }
123
- this.records[index] = {
124
- ...this.records[index],
125
- $locked: null,
126
- $selectable: true
127
- };
128
- }
129
- async unlockEntry(params, force) {
130
- try {
131
- const result = await this._unlockEntry.execute({
132
- id: params.id,
133
- type: params.$lockingType,
134
- force
135
- });
136
- const id = result.data?.id;
137
- if (!id) {
138
- return result;
139
- }
140
- this.removeEntryLock({
141
- ...params
142
- });
143
- return result;
144
- } catch (ex) {
145
- this.triggerOnError(ex);
146
- return {
147
- data: null,
148
- error: ex
149
- };
73
+ isRecordLocked(record) {
74
+ const result = this.records.find((r)=>{
75
+ const { id: entryId } = parseIdentifier(record.id);
76
+ return r.entryId === entryId && !!r.$locked && r.$lockingType === record.$lockingType;
77
+ });
78
+ if (!result?.$locked?.expiresOn) return false;
79
+ const isExpired = this.isLockExpired(result.$locked.expiresOn);
80
+ return !isExpired;
150
81
  }
151
- }
152
- onError(cb) {
153
- this.onErrorCb = cb;
154
- }
155
- triggerOnError(error) {
156
- this.setIsLoading(false);
157
- if (!this.onErrorCb) {
158
- return;
82
+ async updateEntryLock(params) {
83
+ try {
84
+ return await this._updateEntryLock.execute({
85
+ id: params.id,
86
+ type: params.$lockingType
87
+ });
88
+ } catch (ex) {
89
+ this.triggerOnError(ex);
90
+ return {
91
+ data: null,
92
+ error: ex
93
+ };
94
+ }
159
95
  }
160
- this.onErrorCb(error);
161
- }
162
- isLockExpired(input) {
163
- const expiresOn = new Date(input);
164
- return expiresOn <= new Date();
165
- }
166
- setIsLoading(loading) {
167
- this._setLoading(loading);
168
- this.loading = loading;
169
- }
170
- async fetchAndAssignRecords(folderId, type, records) {
171
- if (records.length === 0) {
172
- return;
173
- } else if (this.loading) {
174
- return;
96
+ removeEntryLock(params) {
97
+ const index = this.records.findIndex((record)=>record.entryId === params.id && record.$lockingType === params.$lockingType);
98
+ if (-1 === index) return;
99
+ this.records[index] = {
100
+ ...this.records[index],
101
+ $locked: null,
102
+ $selectable: true
103
+ };
175
104
  }
176
- const assignedIdList = await this.assignRecords(folderId, type, records);
177
- if (assignedIdList.length === 0) {
178
- return;
105
+ async unlockEntry(params, force) {
106
+ try {
107
+ const result = await this._unlockEntry.execute({
108
+ id: params.id,
109
+ type: params.$lockingType,
110
+ force
111
+ });
112
+ const id = result.data?.id;
113
+ if (!id) return result;
114
+ this.removeEntryLock({
115
+ ...params
116
+ });
117
+ return result;
118
+ } catch (ex) {
119
+ this.triggerOnError(ex);
120
+ return {
121
+ data: null,
122
+ error: ex
123
+ };
124
+ }
179
125
  }
180
- this.setIsLoading(true);
181
- let result;
182
- try {
183
- result = await this._listLockRecords.execute({
184
- where: {
185
- id_in: assignedIdList,
186
- type
187
- },
188
- limit: 10000
189
- });
190
- } catch (ex) {
191
- console.error(ex);
192
- this.triggerOnError(ex);
193
- return;
194
- } finally {
195
- this.setIsLoading(false);
126
+ onError(cb) {
127
+ this.onErrorCb = cb;
196
128
  }
197
- if (result.error) {
198
- this.triggerOnError(result.error);
199
- return;
200
- } else if (!result.data) {
201
- this.triggerOnError(createRecordLockingError({
202
- message: `There is no data in the result and there is no error. Please check the network tab for more info.`,
203
- code: "NO_DATA_IN_RESULT"
204
- }));
205
- return;
206
- } else if (result.data.length === 0) {
207
- return;
129
+ triggerOnError(error) {
130
+ this.setIsLoading(false);
131
+ if (!this.onErrorCb) return;
132
+ this.onErrorCb(error);
208
133
  }
209
- for (const record of result.data) {
210
- const index = this.records.findIndex(r => {
211
- const {
212
- id: entryId
213
- } = parseIdentifier(record.id);
214
- return r.entryId === entryId;
215
- });
216
- if (index < 0) {
217
- console.error(`There is no record with id ${record.id} in the records array.`);
218
- continue;
219
- }
220
- this.records[index] = {
221
- ...this.records[index],
222
- $locked: {
223
- lockedBy: record.lockedBy,
224
- expiresOn: record.expiresOn,
225
- lockedOn: record.lockedOn,
226
- actions: record.actions
227
- }
228
- };
134
+ isLockExpired(input) {
135
+ const expiresOn = new Date(input);
136
+ return expiresOn <= new Date();
229
137
  }
230
- return this.records;
231
- }
232
- /**
233
- * Assign records and return the assigned ID list.
234
- */
235
- async assignRecords(folderId, type, records) {
236
- /**
237
- * First we check the record keys against ones in the local cache.
238
- */
239
- const keys = records.map(record => {
240
- if (record.entryId) {
241
- return record.entryId;
242
- }
243
- const {
244
- id: entryId
245
- } = parseIdentifier(record.id);
246
- return entryId;
247
- });
248
- const cacheKey = await createCacheKey(keys);
249
- if (this.currentRecordsCacheKey === cacheKey) {
250
- return [];
138
+ setIsLoading(loading) {
139
+ this._setLoading(loading);
140
+ this.loading = loading;
251
141
  }
252
- this.currentRecordsCacheKey = cacheKey;
253
-
254
- /**
255
- * Reset records if new type is not as same as the old type / folderId.
256
- */
257
- if (this.currentRecordType !== type || this.currentFolderId !== folderId) {
258
- this.records = [];
259
- this.currentRecordType = type;
260
- this.currentFolderId = folderId;
142
+ async fetchAndAssignRecords(folderId, type, records) {
143
+ if (0 === records.length) return;
144
+ if (this.loading) return;
145
+ const assignedIdList = await this.assignRecords(folderId, type, records);
146
+ if (0 === assignedIdList.length) return;
147
+ this.setIsLoading(true);
148
+ let result;
149
+ try {
150
+ result = await this._listLockRecords.execute({
151
+ where: {
152
+ id_in: assignedIdList,
153
+ type
154
+ },
155
+ limit: 10000
156
+ });
157
+ } catch (ex) {
158
+ console.error(ex);
159
+ this.triggerOnError(ex);
160
+ return;
161
+ } finally{
162
+ this.setIsLoading(false);
163
+ }
164
+ if (result.error) return void this.triggerOnError(result.error);
165
+ if (!result.data) return void this.triggerOnError(createRecordLockingError({
166
+ message: "There is no data in the result and there is no error. Please check the network tab for more info.",
167
+ code: "NO_DATA_IN_RESULT"
168
+ }));
169
+ if (0 === result.data.length) return;
170
+ for (const record of result.data){
171
+ const index = this.records.findIndex((r)=>{
172
+ const { id: entryId } = parseIdentifier(record.id);
173
+ return r.entryId === entryId;
174
+ });
175
+ if (index < 0) {
176
+ console.error(`There is no record with id ${record.id} in the records array.`);
177
+ continue;
178
+ }
179
+ this.records[index] = {
180
+ ...this.records[index],
181
+ $locked: {
182
+ lockedBy: record.lockedBy,
183
+ expiresOn: record.expiresOn,
184
+ lockedOn: record.lockedOn,
185
+ actions: record.actions
186
+ }
187
+ };
188
+ }
189
+ return this.records;
190
+ }
191
+ async assignRecords(folderId, type, records) {
192
+ const keys = records.map((record)=>{
193
+ if (record.entryId) return record.entryId;
194
+ const { id: entryId } = parseIdentifier(record.id);
195
+ return entryId;
196
+ });
197
+ const cacheKey = await createCacheKey(keys);
198
+ if (this.currentRecordsCacheKey === cacheKey) return [];
199
+ this.currentRecordsCacheKey = cacheKey;
200
+ if (this.currentRecordType !== type || this.currentFolderId !== folderId) {
201
+ this.records = [];
202
+ this.currentRecordType = type;
203
+ this.currentFolderId = folderId;
204
+ }
205
+ return records.reduce((collection, record)=>{
206
+ const { id: entryId } = parseIdentifier(record.id);
207
+ const index = this.records.findIndex((r)=>r.entryId === entryId);
208
+ if (index >= 0) return collection;
209
+ this.records.push({
210
+ ...record,
211
+ entryId,
212
+ $lockingType: type,
213
+ $locked: void 0
214
+ });
215
+ if ("RECORD" !== record.$type) return collection;
216
+ collection.push(entryId);
217
+ return collection;
218
+ }, []);
261
219
  }
262
- return records.reduce((collection, record) => {
263
- const {
264
- id: entryId
265
- } = parseIdentifier(record.id);
266
- const index = this.records.findIndex(r => r.entryId === entryId);
267
- if (index >= 0) {
268
- return collection;
269
- }
270
- this.records.push({
271
- ...record,
272
- entryId,
273
- $lockingType: type,
274
- $locked: undefined
275
- });
276
- if (record.$type !== "RECORD") {
277
- return collection;
278
- }
279
- collection.push(entryId);
280
- return collection;
281
- }, []);
282
- }
283
220
  }
284
- export const createRecordLocking = config => {
285
- const client = new RecordLockingClient({
286
- client: config.client
287
- });
288
- const getLockRecord = new RecordLockingGetLockRecord({
289
- client
290
- });
291
- const getLockedEntryLockRecord = new RecordLockingGetLockedEntryLockRecord({
292
- client
293
- });
294
- const isEntryLocked = new RecordLockingIsEntryLocked({
295
- client
296
- });
297
- const listLockRecords = new RecordLockingListLockRecords({
298
- client
299
- });
300
- const lockEntry = new RecordLockingLockEntry({
301
- client
302
- });
303
- const unlockEntry = new RecordLockingUnlockEntry({
304
- client
305
- });
306
- const updateEntryLock = new RecordLockingUpdateEntryLock({
307
- client
308
- });
309
- return new RecordLocking({
310
- setLoading: config.setLoading,
311
- getLockRecord,
312
- getLockedEntryLockRecord,
313
- isEntryLocked,
314
- listLockRecords,
315
- updateEntryLock,
316
- lockEntry,
317
- unlockEntry
318
- });
221
+ const createRecordLocking = (config)=>{
222
+ const client = new RecordLockingClient({
223
+ client: config.client
224
+ });
225
+ const getLockRecord = new RecordLockingGetLockRecord({
226
+ client
227
+ });
228
+ const getLockedEntryLockRecord = new RecordLockingGetLockedEntryLockRecord({
229
+ client
230
+ });
231
+ const isEntryLocked = new RecordLockingIsEntryLocked({
232
+ client
233
+ });
234
+ const listLockRecords = new RecordLockingListLockRecords({
235
+ client
236
+ });
237
+ const lockEntry = new RecordLockingLockEntry({
238
+ client
239
+ });
240
+ const unlockEntry = new RecordLockingUnlockEntry({
241
+ client
242
+ });
243
+ const updateEntryLock = new RecordLockingUpdateEntryLock({
244
+ client
245
+ });
246
+ return new RecordLocking({
247
+ setLoading: config.setLoading,
248
+ getLockRecord,
249
+ getLockedEntryLockRecord,
250
+ isEntryLocked,
251
+ listLockRecords,
252
+ updateEntryLock,
253
+ lockEntry,
254
+ unlockEntry
255
+ });
319
256
  };
257
+ export { createRecordLocking };
320
258
 
321
259
  //# sourceMappingURL=RecordLocking.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["RecordLockingGetLockRecord","RecordLockingIsEntryLocked","RecordLockingListLockRecords","RecordLockingLockEntry","RecordLockingUnlockEntry","RecordLockingClient","createRecordLockingError","parseIdentifier","createCacheKey","RecordLockingUpdateEntryLock","RecordLockingGetLockedEntryLockRecord","RecordLocking","loading","records","onErrorCb","constructor","params","_setLoading","setLoading","_getLockRecord","getLockRecord","_getLockedEntryLockRecord","getLockedEntryLockRecord","_listLockRecords","listLockRecords","_unlockEntry","unlockEntry","_updateEntryLock","updateEntryLock","setRecords","folderId","type","result","fetchAndAssignRecords","undefined","map","record","id","entryId","$type","$lockingType","$locked","$selectable","fetchLockRecord","execute","data","error","ex","fetchLockedEntryLockRecord","getLockRecordEntry","find","isRecordLocked","r","expiresOn","isExpired","isLockExpired","triggerOnError","removeEntryLock","index","findIndex","force","onError","cb","setIsLoading","input","Date","length","assignedIdList","assignRecords","where","id_in","limit","console","message","code","lockedBy","lockedOn","actions","keys","cacheKey","currentRecordsCacheKey","currentRecordType","currentFolderId","reduce","collection","push","createRecordLocking","config","client","isEntryLocked","lockEntry"],"sources":["RecordLocking.ts"],"sourcesContent":["import type {\n IRecordLocking,\n IRecordLockingUpdateEntryLockResult\n} from \"./abstractions/IRecordLocking.js\";\nimport type { ApolloClient } from \"apollo-client\";\nimport { RecordLockingGetLockRecord } from \"./RecordLockingGetLockRecord.js\";\nimport { RecordLockingIsEntryLocked } from \"./RecordLockingIsEntryLocked.js\";\nimport { RecordLockingListLockRecords } from \"./RecordLockingListLockRecords.js\";\nimport { RecordLockingLockEntry } from \"./RecordLockingLockEntry.js\";\nimport { RecordLockingUnlockEntry } from \"./RecordLockingUnlockEntry.js\";\nimport { RecordLockingClient } from \"./RecordLockingClient.js\";\nimport type { IRecordLockingGetLockRecord } from \"./abstractions/IRecordLockingGetLockRecord.js\";\nimport type { IRecordLockingIsEntryLocked } from \"./abstractions/IRecordLockingIsEntryLocked.js\";\nimport type {\n IRecordLockingListLockRecords,\n IRecordLockingListLockRecordsResult\n} from \"./abstractions/IRecordLockingListLockRecords.js\";\nimport type { IRecordLockingLockEntry } from \"./abstractions/IRecordLockingLockEntry.js\";\nimport type {\n IRecordLockingUnlockEntry,\n IRecordLockingUnlockEntryResult\n} from \"./abstractions/IRecordLockingUnlockEntry.js\";\nimport type {\n IFetchLockedEntryLockRecordParams,\n IFetchLockRecordParams,\n IFetchLockRecordResult,\n IIsRecordLockedParams,\n IPossiblyRecordLockingRecord,\n IRecordLockingError,\n IRecordLockingLockRecord,\n IRecordLockingRecord,\n IUnlockEntryParams,\n IUpdateEntryLockParams\n} from \"~/types.js\";\nimport { createRecordLockingError } from \"./utils/createRecordLockingError.js\";\nimport { parseIdentifier } from \"@webiny/utils/parseIdentifier.js\";\nimport { createCacheKey } from \"~/utils/createCacheKey.js\";\nimport { RecordLockingUpdateEntryLock } from \"~/domain/RecordLockingUpdateEntryLock.js\";\nimport type { IRecordLockingUpdateEntryLock } from \"~/domain/abstractions/IRecordLockingUpdateEntryLock.js\";\nimport { RecordLockingGetLockedEntryLockRecord } from \"~/domain/RecordLockingGetLockedEntryLockRecord.js\";\nimport type { IRecordLockingGetLockedEntryLockRecord } from \"./abstractions/IRecordLockingGetLockedEntryLockRecord.js\";\n\nexport interface ICreateRecordLockingParams {\n client: ApolloClient<any>;\n setLoading: (loading: boolean) => void;\n}\n\nexport interface IRecordLockingParams {\n setLoading: (loading: boolean) => void;\n getLockRecord: IRecordLockingGetLockRecord;\n getLockedEntryLockRecord: IRecordLockingGetLockedEntryLockRecord;\n isEntryLocked: IRecordLockingIsEntryLocked;\n listLockRecords: IRecordLockingListLockRecords;\n lockEntry: IRecordLockingLockEntry;\n unlockEntry: IRecordLockingUnlockEntry;\n updateEntryLock: IRecordLockingUpdateEntryLock;\n}\n\nexport interface IOnErrorCb {\n (error: IRecordLockingError): void;\n}\n\nclass RecordLocking<\n T extends IPossiblyRecordLockingRecord = IPossiblyRecordLockingRecord\n> implements IRecordLocking<T> {\n private currentRecordType?: string;\n private currentFolderId?: string;\n private currentRecordsCacheKey?: string;\n private readonly _setLoading: (loading: boolean) => void;\n public loading = false;\n public records: IRecordLockingRecord[] = [];\n private readonly _getLockRecord: IRecordLockingGetLockRecord;\n private readonly _getLockedEntryLockRecord: IRecordLockingGetLockedEntryLockRecord;\n private readonly _listLockRecords: IRecordLockingListLockRecords;\n private readonly _unlockEntry: IRecordLockingUnlockEntry;\n private readonly _updateEntryLock: IRecordLockingUpdateEntryLock;\n\n private onErrorCb: IOnErrorCb | null = null;\n\n public constructor(params: IRecordLockingParams) {\n this._setLoading = params.setLoading;\n this._getLockRecord = params.getLockRecord;\n this._getLockedEntryLockRecord = params.getLockedEntryLockRecord;\n this._listLockRecords = params.listLockRecords;\n this._unlockEntry = params.unlockEntry;\n this._updateEntryLock = params.updateEntryLock;\n }\n\n public async setRecords(\n folderId: string,\n type: string,\n records: T[]\n ): Promise<IRecordLockingRecord[] | undefined> {\n const result = await this.fetchAndAssignRecords(folderId, type, records);\n if (!result) {\n return undefined;\n }\n\n return result.map(record => {\n const { id: entryId } = parseIdentifier(record.id);\n return {\n ...record,\n $type: \"RECORD\",\n $lockingType: type,\n $locked: record.$locked,\n $selectable: record.$locked ? false : record.$selectable,\n entryId\n };\n });\n }\n\n public async fetchLockRecord(params: IFetchLockRecordParams): Promise<IFetchLockRecordResult> {\n const { id, $lockingType } = params;\n\n const { id: entryId } = parseIdentifier(id);\n\n try {\n const result = await this._getLockRecord.execute({\n id: entryId,\n type: $lockingType\n });\n\n return {\n data: result.data,\n error: result.error\n };\n } catch (ex) {\n return {\n data: null,\n error: ex\n };\n }\n }\n\n public async fetchLockedEntryLockRecord(\n params: IFetchLockedEntryLockRecordParams\n ): Promise<IRecordLockingLockRecord | null> {\n const { id, $lockingType } = params;\n\n const { id: entryId } = parseIdentifier(id);\n const result = await this._getLockedEntryLockRecord.execute({\n id: entryId,\n type: $lockingType\n });\n return result.data;\n }\n\n public getLockRecordEntry(id: string): IRecordLockingRecord | undefined {\n return this.records.find(record => {\n const { id: entryId } = parseIdentifier(id);\n return record.entryId === entryId;\n });\n }\n\n public isRecordLocked(record: IIsRecordLockedParams): boolean {\n const result = this.records.find(r => {\n const { id: entryId } = parseIdentifier(record.id);\n\n return r.entryId === entryId && !!r.$locked && r.$lockingType === record.$lockingType;\n });\n if (!result?.$locked?.expiresOn) {\n return false;\n }\n const isExpired = this.isLockExpired(result.$locked.expiresOn);\n return !isExpired;\n }\n\n public async updateEntryLock(\n params: IUpdateEntryLockParams\n ): Promise<IRecordLockingUpdateEntryLockResult> {\n try {\n return await this._updateEntryLock.execute({\n id: params.id,\n type: params.$lockingType\n });\n } catch (ex) {\n this.triggerOnError(ex);\n return {\n data: null,\n error: ex\n };\n }\n }\n\n public removeEntryLock(params: IUnlockEntryParams): void {\n const index = this.records.findIndex(record => {\n return record.entryId === params.id && record.$lockingType === params.$lockingType;\n });\n if (index === -1) {\n return;\n }\n this.records[index] = {\n ...this.records[index],\n $locked: null,\n $selectable: true\n };\n }\n\n public async unlockEntry(\n params: IUnlockEntryParams,\n force?: boolean\n ): Promise<IRecordLockingUnlockEntryResult> {\n try {\n const result = await this._unlockEntry.execute({\n id: params.id,\n type: params.$lockingType,\n force\n });\n\n const id = result.data?.id;\n if (!id) {\n return result;\n }\n this.removeEntryLock({\n ...params\n });\n return result;\n } catch (ex) {\n this.triggerOnError(ex);\n return {\n data: null,\n error: ex\n };\n }\n }\n\n public onError(cb: IOnErrorCb): void {\n this.onErrorCb = cb;\n }\n\n public triggerOnError(error: IRecordLockingError): void {\n this.setIsLoading(false);\n if (!this.onErrorCb) {\n return;\n }\n this.onErrorCb(error);\n }\n\n public isLockExpired(input: Date | string): boolean {\n const expiresOn = new Date(input);\n return expiresOn <= new Date();\n }\n\n private setIsLoading(loading: boolean): void {\n this._setLoading(loading);\n this.loading = loading;\n }\n\n private async fetchAndAssignRecords(\n folderId: string,\n type: string,\n records: T[]\n ): Promise<IPossiblyRecordLockingRecord[] | undefined> {\n if (records.length === 0) {\n return;\n } else if (this.loading) {\n return;\n }\n const assignedIdList = await this.assignRecords(folderId, type, records);\n if (assignedIdList.length === 0) {\n return;\n }\n this.setIsLoading(true);\n let result: IRecordLockingListLockRecordsResult;\n try {\n result = await this._listLockRecords.execute({\n where: {\n id_in: assignedIdList,\n type\n },\n limit: 10000\n });\n } catch (ex) {\n console.error(ex);\n this.triggerOnError(ex);\n return;\n } finally {\n this.setIsLoading(false);\n }\n if (result.error) {\n this.triggerOnError(result.error);\n return;\n } else if (!result.data) {\n this.triggerOnError(\n createRecordLockingError({\n message: `There is no data in the result and there is no error. Please check the network tab for more info.`,\n code: \"NO_DATA_IN_RESULT\"\n })\n );\n return;\n } else if (result.data.length === 0) {\n return;\n }\n\n for (const record of result.data) {\n const index = this.records.findIndex(r => {\n const { id: entryId } = parseIdentifier(record.id);\n return r.entryId === entryId;\n });\n if (index < 0) {\n console.error(`There is no record with id ${record.id} in the records array.`);\n continue;\n }\n this.records[index] = {\n ...this.records[index],\n $locked: {\n lockedBy: record.lockedBy,\n expiresOn: record.expiresOn,\n lockedOn: record.lockedOn,\n actions: record.actions\n }\n };\n }\n\n return this.records;\n }\n /**\n * Assign records and return the assigned ID list.\n */\n private async assignRecords(folderId: string, type: string, records: T[]): Promise<string[]> {\n /**\n * First we check the record keys against ones in the local cache.\n */\n const keys = records.map(record => {\n if (record.entryId) {\n return record.entryId;\n }\n const { id: entryId } = parseIdentifier(record.id);\n return entryId;\n });\n const cacheKey = await createCacheKey(keys);\n if (this.currentRecordsCacheKey === cacheKey) {\n return [];\n }\n this.currentRecordsCacheKey = cacheKey;\n\n /**\n * Reset records if new type is not as same as the old type / folderId.\n */\n if (this.currentRecordType !== type || this.currentFolderId !== folderId) {\n this.records = [];\n this.currentRecordType = type;\n this.currentFolderId = folderId;\n }\n\n return records.reduce<string[]>((collection, record) => {\n const { id: entryId } = parseIdentifier(record.id);\n const index = this.records.findIndex(r => r.entryId === entryId);\n if (index >= 0) {\n return collection;\n }\n this.records.push({\n ...record,\n entryId,\n $lockingType: type,\n $locked: undefined\n });\n if (record.$type !== \"RECORD\") {\n return collection;\n }\n collection.push(entryId);\n return collection;\n }, []);\n }\n}\n\nexport const createRecordLocking = <T extends IRecordLockingRecord>(\n config: ICreateRecordLockingParams\n): IRecordLocking => {\n const client = new RecordLockingClient({\n client: config.client\n });\n\n const getLockRecord = new RecordLockingGetLockRecord({\n client\n });\n\n const getLockedEntryLockRecord = new RecordLockingGetLockedEntryLockRecord({\n client\n });\n\n const isEntryLocked = new RecordLockingIsEntryLocked({\n client\n });\n\n const listLockRecords = new RecordLockingListLockRecords({\n client\n });\n\n const lockEntry = new RecordLockingLockEntry({\n client\n });\n\n const unlockEntry = new RecordLockingUnlockEntry({\n client\n });\n\n const updateEntryLock = new RecordLockingUpdateEntryLock({\n client\n });\n\n return new RecordLocking<T>({\n setLoading: config.setLoading,\n getLockRecord,\n getLockedEntryLockRecord,\n isEntryLocked,\n listLockRecords,\n updateEntryLock,\n lockEntry,\n unlockEntry\n });\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"domain/RecordLocking.js","sources":["../../src/domain/RecordLocking.ts"],"sourcesContent":["import type {\n IRecordLocking,\n IRecordLockingUpdateEntryLockResult\n} from \"./abstractions/IRecordLocking.js\";\nimport type { ApolloClient } from \"apollo-client\";\nimport { RecordLockingGetLockRecord } from \"./RecordLockingGetLockRecord.js\";\nimport { RecordLockingIsEntryLocked } from \"./RecordLockingIsEntryLocked.js\";\nimport { RecordLockingListLockRecords } from \"./RecordLockingListLockRecords.js\";\nimport { RecordLockingLockEntry } from \"./RecordLockingLockEntry.js\";\nimport { RecordLockingUnlockEntry } from \"./RecordLockingUnlockEntry.js\";\nimport { RecordLockingClient } from \"./RecordLockingClient.js\";\nimport type { IRecordLockingGetLockRecord } from \"./abstractions/IRecordLockingGetLockRecord.js\";\nimport type { IRecordLockingIsEntryLocked } from \"./abstractions/IRecordLockingIsEntryLocked.js\";\nimport type {\n IRecordLockingListLockRecords,\n IRecordLockingListLockRecordsResult\n} from \"./abstractions/IRecordLockingListLockRecords.js\";\nimport type { IRecordLockingLockEntry } from \"./abstractions/IRecordLockingLockEntry.js\";\nimport type {\n IRecordLockingUnlockEntry,\n IRecordLockingUnlockEntryResult\n} from \"./abstractions/IRecordLockingUnlockEntry.js\";\nimport type {\n IFetchLockedEntryLockRecordParams,\n IFetchLockRecordParams,\n IFetchLockRecordResult,\n IIsRecordLockedParams,\n IPossiblyRecordLockingRecord,\n IRecordLockingError,\n IRecordLockingLockRecord,\n IRecordLockingRecord,\n IUnlockEntryParams,\n IUpdateEntryLockParams\n} from \"~/types.js\";\nimport { createRecordLockingError } from \"./utils/createRecordLockingError.js\";\nimport { parseIdentifier } from \"@webiny/utils/parseIdentifier.js\";\nimport { createCacheKey } from \"~/utils/createCacheKey.js\";\nimport { RecordLockingUpdateEntryLock } from \"~/domain/RecordLockingUpdateEntryLock.js\";\nimport type { IRecordLockingUpdateEntryLock } from \"~/domain/abstractions/IRecordLockingUpdateEntryLock.js\";\nimport { RecordLockingGetLockedEntryLockRecord } from \"~/domain/RecordLockingGetLockedEntryLockRecord.js\";\nimport type { IRecordLockingGetLockedEntryLockRecord } from \"./abstractions/IRecordLockingGetLockedEntryLockRecord.js\";\n\nexport interface ICreateRecordLockingParams {\n client: ApolloClient<any>;\n setLoading: (loading: boolean) => void;\n}\n\nexport interface IRecordLockingParams {\n setLoading: (loading: boolean) => void;\n getLockRecord: IRecordLockingGetLockRecord;\n getLockedEntryLockRecord: IRecordLockingGetLockedEntryLockRecord;\n isEntryLocked: IRecordLockingIsEntryLocked;\n listLockRecords: IRecordLockingListLockRecords;\n lockEntry: IRecordLockingLockEntry;\n unlockEntry: IRecordLockingUnlockEntry;\n updateEntryLock: IRecordLockingUpdateEntryLock;\n}\n\nexport interface IOnErrorCb {\n (error: IRecordLockingError): void;\n}\n\nclass RecordLocking<\n T extends IPossiblyRecordLockingRecord = IPossiblyRecordLockingRecord\n> implements IRecordLocking<T> {\n private currentRecordType?: string;\n private currentFolderId?: string;\n private currentRecordsCacheKey?: string;\n private readonly _setLoading: (loading: boolean) => void;\n public loading = false;\n public records: IRecordLockingRecord[] = [];\n private readonly _getLockRecord: IRecordLockingGetLockRecord;\n private readonly _getLockedEntryLockRecord: IRecordLockingGetLockedEntryLockRecord;\n private readonly _listLockRecords: IRecordLockingListLockRecords;\n private readonly _unlockEntry: IRecordLockingUnlockEntry;\n private readonly _updateEntryLock: IRecordLockingUpdateEntryLock;\n\n private onErrorCb: IOnErrorCb | null = null;\n\n public constructor(params: IRecordLockingParams) {\n this._setLoading = params.setLoading;\n this._getLockRecord = params.getLockRecord;\n this._getLockedEntryLockRecord = params.getLockedEntryLockRecord;\n this._listLockRecords = params.listLockRecords;\n this._unlockEntry = params.unlockEntry;\n this._updateEntryLock = params.updateEntryLock;\n }\n\n public async setRecords(\n folderId: string,\n type: string,\n records: T[]\n ): Promise<IRecordLockingRecord[] | undefined> {\n const result = await this.fetchAndAssignRecords(folderId, type, records);\n if (!result) {\n return undefined;\n }\n\n return result.map(record => {\n const { id: entryId } = parseIdentifier(record.id);\n return {\n ...record,\n $type: \"RECORD\",\n $lockingType: type,\n $locked: record.$locked,\n $selectable: record.$locked ? false : record.$selectable,\n entryId\n };\n });\n }\n\n public async fetchLockRecord(params: IFetchLockRecordParams): Promise<IFetchLockRecordResult> {\n const { id, $lockingType } = params;\n\n const { id: entryId } = parseIdentifier(id);\n\n try {\n const result = await this._getLockRecord.execute({\n id: entryId,\n type: $lockingType\n });\n\n return {\n data: result.data,\n error: result.error\n };\n } catch (ex) {\n return {\n data: null,\n error: ex\n };\n }\n }\n\n public async fetchLockedEntryLockRecord(\n params: IFetchLockedEntryLockRecordParams\n ): Promise<IRecordLockingLockRecord | null> {\n const { id, $lockingType } = params;\n\n const { id: entryId } = parseIdentifier(id);\n const result = await this._getLockedEntryLockRecord.execute({\n id: entryId,\n type: $lockingType\n });\n return result.data;\n }\n\n public getLockRecordEntry(id: string): IRecordLockingRecord | undefined {\n return this.records.find(record => {\n const { id: entryId } = parseIdentifier(id);\n return record.entryId === entryId;\n });\n }\n\n public isRecordLocked(record: IIsRecordLockedParams): boolean {\n const result = this.records.find(r => {\n const { id: entryId } = parseIdentifier(record.id);\n\n return r.entryId === entryId && !!r.$locked && r.$lockingType === record.$lockingType;\n });\n if (!result?.$locked?.expiresOn) {\n return false;\n }\n const isExpired = this.isLockExpired(result.$locked.expiresOn);\n return !isExpired;\n }\n\n public async updateEntryLock(\n params: IUpdateEntryLockParams\n ): Promise<IRecordLockingUpdateEntryLockResult> {\n try {\n return await this._updateEntryLock.execute({\n id: params.id,\n type: params.$lockingType\n });\n } catch (ex) {\n this.triggerOnError(ex);\n return {\n data: null,\n error: ex\n };\n }\n }\n\n public removeEntryLock(params: IUnlockEntryParams): void {\n const index = this.records.findIndex(record => {\n return record.entryId === params.id && record.$lockingType === params.$lockingType;\n });\n if (index === -1) {\n return;\n }\n this.records[index] = {\n ...this.records[index],\n $locked: null,\n $selectable: true\n };\n }\n\n public async unlockEntry(\n params: IUnlockEntryParams,\n force?: boolean\n ): Promise<IRecordLockingUnlockEntryResult> {\n try {\n const result = await this._unlockEntry.execute({\n id: params.id,\n type: params.$lockingType,\n force\n });\n\n const id = result.data?.id;\n if (!id) {\n return result;\n }\n this.removeEntryLock({\n ...params\n });\n return result;\n } catch (ex) {\n this.triggerOnError(ex);\n return {\n data: null,\n error: ex\n };\n }\n }\n\n public onError(cb: IOnErrorCb): void {\n this.onErrorCb = cb;\n }\n\n public triggerOnError(error: IRecordLockingError): void {\n this.setIsLoading(false);\n if (!this.onErrorCb) {\n return;\n }\n this.onErrorCb(error);\n }\n\n public isLockExpired(input: Date | string): boolean {\n const expiresOn = new Date(input);\n return expiresOn <= new Date();\n }\n\n private setIsLoading(loading: boolean): void {\n this._setLoading(loading);\n this.loading = loading;\n }\n\n private async fetchAndAssignRecords(\n folderId: string,\n type: string,\n records: T[]\n ): Promise<IPossiblyRecordLockingRecord[] | undefined> {\n if (records.length === 0) {\n return;\n } else if (this.loading) {\n return;\n }\n const assignedIdList = await this.assignRecords(folderId, type, records);\n if (assignedIdList.length === 0) {\n return;\n }\n this.setIsLoading(true);\n let result: IRecordLockingListLockRecordsResult;\n try {\n result = await this._listLockRecords.execute({\n where: {\n id_in: assignedIdList,\n type\n },\n limit: 10000\n });\n } catch (ex) {\n console.error(ex);\n this.triggerOnError(ex);\n return;\n } finally {\n this.setIsLoading(false);\n }\n if (result.error) {\n this.triggerOnError(result.error);\n return;\n } else if (!result.data) {\n this.triggerOnError(\n createRecordLockingError({\n message: `There is no data in the result and there is no error. Please check the network tab for more info.`,\n code: \"NO_DATA_IN_RESULT\"\n })\n );\n return;\n } else if (result.data.length === 0) {\n return;\n }\n\n for (const record of result.data) {\n const index = this.records.findIndex(r => {\n const { id: entryId } = parseIdentifier(record.id);\n return r.entryId === entryId;\n });\n if (index < 0) {\n console.error(`There is no record with id ${record.id} in the records array.`);\n continue;\n }\n this.records[index] = {\n ...this.records[index],\n $locked: {\n lockedBy: record.lockedBy,\n expiresOn: record.expiresOn,\n lockedOn: record.lockedOn,\n actions: record.actions\n }\n };\n }\n\n return this.records;\n }\n /**\n * Assign records and return the assigned ID list.\n */\n private async assignRecords(folderId: string, type: string, records: T[]): Promise<string[]> {\n /**\n * First we check the record keys against ones in the local cache.\n */\n const keys = records.map(record => {\n if (record.entryId) {\n return record.entryId;\n }\n const { id: entryId } = parseIdentifier(record.id);\n return entryId;\n });\n const cacheKey = await createCacheKey(keys);\n if (this.currentRecordsCacheKey === cacheKey) {\n return [];\n }\n this.currentRecordsCacheKey = cacheKey;\n\n /**\n * Reset records if new type is not as same as the old type / folderId.\n */\n if (this.currentRecordType !== type || this.currentFolderId !== folderId) {\n this.records = [];\n this.currentRecordType = type;\n this.currentFolderId = folderId;\n }\n\n return records.reduce<string[]>((collection, record) => {\n const { id: entryId } = parseIdentifier(record.id);\n const index = this.records.findIndex(r => r.entryId === entryId);\n if (index >= 0) {\n return collection;\n }\n this.records.push({\n ...record,\n entryId,\n $lockingType: type,\n $locked: undefined\n });\n if (record.$type !== \"RECORD\") {\n return collection;\n }\n collection.push(entryId);\n return collection;\n }, []);\n }\n}\n\nexport const createRecordLocking = <T extends IRecordLockingRecord>(\n config: ICreateRecordLockingParams\n): IRecordLocking => {\n const client = new RecordLockingClient({\n client: config.client\n });\n\n const getLockRecord = new RecordLockingGetLockRecord({\n client\n });\n\n const getLockedEntryLockRecord = new RecordLockingGetLockedEntryLockRecord({\n client\n });\n\n const isEntryLocked = new RecordLockingIsEntryLocked({\n client\n });\n\n const listLockRecords = new RecordLockingListLockRecords({\n client\n });\n\n const lockEntry = new RecordLockingLockEntry({\n client\n });\n\n const unlockEntry = new RecordLockingUnlockEntry({\n client\n });\n\n const updateEntryLock = new RecordLockingUpdateEntryLock({\n client\n });\n\n return new RecordLocking<T>({\n setLoading: config.setLoading,\n getLockRecord,\n getLockedEntryLockRecord,\n isEntryLocked,\n listLockRecords,\n updateEntryLock,\n lockEntry,\n unlockEntry\n });\n};\n"],"names":["RecordLocking","params","folderId","type","records","result","record","entryId","parseIdentifier","id","$lockingType","ex","r","isExpired","index","force","cb","error","input","expiresOn","Date","loading","assignedIdList","console","createRecordLockingError","keys","cacheKey","createCacheKey","collection","undefined","createRecordLocking","config","client","RecordLockingClient","getLockRecord","RecordLockingGetLockRecord","getLockedEntryLockRecord","RecordLockingGetLockedEntryLockRecord","isEntryLocked","RecordLockingIsEntryLocked","listLockRecords","RecordLockingListLockRecords","lockEntry","RecordLockingLockEntry","unlockEntry","RecordLockingUnlockEntry","updateEntryLock","RecordLockingUpdateEntryLock"],"mappings":"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"}