@webiny/app-record-locking 6.4.5-beta.0 → 6.6.0-alpha.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 (250) hide show
  1. package/RecordLockingModule.d.ts +2 -0
  2. package/RecordLockingModule.js +74 -0
  3. package/RecordLockingModule.js.map +1 -0
  4. package/{components/SecurityPermissions.js → SecurityPermissions.js} +1 -1
  5. package/SecurityPermissions.js.map +1 -0
  6. package/features/acquireLock/AcquireLockGateway.d.ts +12 -0
  7. package/features/acquireLock/AcquireLockGateway.js +43 -0
  8. package/features/acquireLock/AcquireLockGateway.js.map +1 -0
  9. package/features/acquireLock/AcquireLockUseCase.d.ts +10 -0
  10. package/features/acquireLock/AcquireLockUseCase.js +18 -0
  11. package/features/acquireLock/AcquireLockUseCase.js.map +1 -0
  12. package/features/acquireLock/abstractions.d.ts +19 -0
  13. package/features/acquireLock/abstractions.js +6 -0
  14. package/features/acquireLock/abstractions.js.map +1 -0
  15. package/features/acquireLock/feature.d.ts +3 -0
  16. package/features/acquireLock/feature.js +19 -0
  17. package/features/acquireLock/feature.js.map +1 -0
  18. package/features/checkLockStatus/CheckLockStatusGateway.d.ts +12 -0
  19. package/features/checkLockStatus/CheckLockStatusGateway.js +43 -0
  20. package/features/checkLockStatus/CheckLockStatusGateway.js.map +1 -0
  21. package/features/checkLockStatus/CheckLockStatusUseCase.d.ts +10 -0
  22. package/features/checkLockStatus/CheckLockStatusUseCase.js +18 -0
  23. package/features/checkLockStatus/CheckLockStatusUseCase.js.map +1 -0
  24. package/features/checkLockStatus/abstractions.d.ts +19 -0
  25. package/features/checkLockStatus/abstractions.js +6 -0
  26. package/features/checkLockStatus/abstractions.js.map +1 -0
  27. package/features/checkLockStatus/feature.d.ts +3 -0
  28. package/features/checkLockStatus/feature.js +19 -0
  29. package/features/checkLockStatus/feature.js.map +1 -0
  30. package/features/feature.d.ts +1 -0
  31. package/features/feature.js +19 -0
  32. package/features/feature.js.map +1 -0
  33. package/features/forceUnlock/ForceUnlockGateway.d.ts +12 -0
  34. package/features/forceUnlock/ForceUnlockGateway.js +44 -0
  35. package/features/forceUnlock/ForceUnlockGateway.js.map +1 -0
  36. package/features/forceUnlock/ForceUnlockUseCase.d.ts +10 -0
  37. package/features/forceUnlock/ForceUnlockUseCase.js +18 -0
  38. package/features/forceUnlock/ForceUnlockUseCase.js.map +1 -0
  39. package/features/forceUnlock/abstractions.d.ts +19 -0
  40. package/features/forceUnlock/abstractions.js +6 -0
  41. package/features/forceUnlock/abstractions.js.map +1 -0
  42. package/features/forceUnlock/feature.d.ts +3 -0
  43. package/features/forceUnlock/feature.js +19 -0
  44. package/features/forceUnlock/feature.js.map +1 -0
  45. package/{domain/graphql/fields.js → features/graphqlFields.js} +1 -1
  46. package/features/graphqlFields.js.map +1 -0
  47. package/features/listLockRecords/ListLockRecordsGateway.d.ts +12 -0
  48. package/features/listLockRecords/ListLockRecordsGateway.js +48 -0
  49. package/features/listLockRecords/ListLockRecordsGateway.js.map +1 -0
  50. package/features/listLockRecords/ListLockRecordsUseCase.d.ts +10 -0
  51. package/features/listLockRecords/ListLockRecordsUseCase.js +18 -0
  52. package/features/listLockRecords/ListLockRecordsUseCase.js.map +1 -0
  53. package/features/listLockRecords/abstractions.d.ts +22 -0
  54. package/features/listLockRecords/abstractions.js +6 -0
  55. package/features/listLockRecords/abstractions.js.map +1 -0
  56. package/features/listLockRecords/feature.d.ts +3 -0
  57. package/features/listLockRecords/feature.js +19 -0
  58. package/features/listLockRecords/feature.js.map +1 -0
  59. package/features/permissions/abstractions.d.ts +1 -1
  60. package/features/permissions/abstractions.js +1 -1
  61. package/features/permissions/abstractions.js.map +1 -1
  62. package/features/permissions/feature.js +1 -1
  63. package/features/permissions/feature.js.map +1 -1
  64. package/features/releaseLock/ReleaseLockGateway.d.ts +12 -0
  65. package/features/releaseLock/ReleaseLockGateway.js +44 -0
  66. package/features/releaseLock/ReleaseLockGateway.js.map +1 -0
  67. package/features/releaseLock/ReleaseLockUseCase.d.ts +10 -0
  68. package/features/releaseLock/ReleaseLockUseCase.js +18 -0
  69. package/features/releaseLock/ReleaseLockUseCase.js.map +1 -0
  70. package/features/releaseLock/abstractions.d.ts +19 -0
  71. package/features/releaseLock/abstractions.js +6 -0
  72. package/features/releaseLock/abstractions.js.map +1 -0
  73. package/features/releaseLock/feature.d.ts +3 -0
  74. package/features/releaseLock/feature.js +19 -0
  75. package/features/releaseLock/feature.js.map +1 -0
  76. package/index.d.ts +0 -5
  77. package/index.js +12 -13
  78. package/index.js.map +1 -1
  79. package/package.json +13 -17
  80. package/permissions/permissionsSchema.js.map +1 -0
  81. package/presentation/entryLocking/ContentEntryFormPresenterDecorator.d.ts +22 -0
  82. package/presentation/entryLocking/ContentEntryFormPresenterDecorator.js +61 -0
  83. package/presentation/entryLocking/ContentEntryFormPresenterDecorator.js.map +1 -0
  84. package/presentation/entryLocking/RecordLockingPresenter.d.ts +32 -0
  85. package/presentation/entryLocking/RecordLockingPresenter.js +164 -0
  86. package/presentation/entryLocking/RecordLockingPresenter.js.map +1 -0
  87. package/presentation/entryLocking/SingleEntryContentDecorator.d.ts +2 -0
  88. package/presentation/entryLocking/SingleEntryContentDecorator.js +72 -0
  89. package/presentation/entryLocking/SingleEntryContentDecorator.js.map +1 -0
  90. package/presentation/entryLocking/SingleEntryPresenterDecorator.d.ts +15 -0
  91. package/presentation/entryLocking/SingleEntryPresenterDecorator.js +40 -0
  92. package/presentation/entryLocking/SingleEntryPresenterDecorator.js.map +1 -0
  93. package/presentation/entryLocking/abstractions.d.ts +26 -0
  94. package/presentation/entryLocking/abstractions.js +5 -0
  95. package/presentation/entryLocking/abstractions.js.map +1 -0
  96. package/presentation/entryLocking/components/ForceUnlockButton.d.ts +11 -0
  97. package/presentation/entryLocking/components/ForceUnlockButton.js +37 -0
  98. package/presentation/entryLocking/components/ForceUnlockButton.js.map +1 -0
  99. package/presentation/entryLocking/components/LockedEntryOverlay.d.ts +10 -0
  100. package/presentation/entryLocking/components/LockedEntryOverlay.js +52 -0
  101. package/presentation/entryLocking/components/LockedEntryOverlay.js.map +1 -0
  102. package/presentation/entryLocking/components/RecordLockingGuard.d.ts +12 -0
  103. package/presentation/entryLocking/components/RecordLockingGuard.js +74 -0
  104. package/presentation/entryLocking/components/RecordLockingGuard.js.map +1 -0
  105. package/presentation/entryLocking/feature.d.ts +3 -0
  106. package/presentation/entryLocking/feature.js +21 -0
  107. package/presentation/entryLocking/feature.js.map +1 -0
  108. package/presentation/listLocking/ContentEntriesPresenterDecorator.d.ts +24 -0
  109. package/presentation/listLocking/ContentEntriesPresenterDecorator.js +67 -0
  110. package/presentation/listLocking/ContentEntriesPresenterDecorator.js.map +1 -0
  111. package/presentation/listLocking/ListLockRecordsPresenter.d.ts +17 -0
  112. package/presentation/listLocking/ListLockRecordsPresenter.js +52 -0
  113. package/presentation/listLocking/ListLockRecordsPresenter.js.map +1 -0
  114. package/presentation/listLocking/abstractions.d.ts +16 -0
  115. package/presentation/listLocking/abstractions.js +5 -0
  116. package/presentation/listLocking/abstractions.js.map +1 -0
  117. package/presentation/listLocking/components/ListLockRecordsSync.d.ts +3 -0
  118. package/presentation/listLocking/components/ListLockRecordsSync.js +26 -0
  119. package/presentation/listLocking/components/ListLockRecordsSync.js.map +1 -0
  120. package/presentation/listLocking/components/LockIndicatorCell.d.ts +2 -0
  121. package/presentation/listLocking/components/LockIndicatorCell.js +39 -0
  122. package/presentation/listLocking/components/LockIndicatorCell.js.map +1 -0
  123. package/presentation/listLocking/feature.d.ts +3 -0
  124. package/presentation/listLocking/feature.js +19 -0
  125. package/presentation/listLocking/feature.js.map +1 -0
  126. package/types.d.ts +1 -62
  127. package/components/HeadlessCmsActionsAcoCell.d.ts +0 -2
  128. package/components/HeadlessCmsActionsAcoCell.js +0 -38
  129. package/components/HeadlessCmsActionsAcoCell.js.map +0 -1
  130. package/components/HeadlessCmsContentEntry/ContentEntryGuard.d.ts +0 -9
  131. package/components/HeadlessCmsContentEntry/ContentEntryGuard.js +0 -34
  132. package/components/HeadlessCmsContentEntry/ContentEntryGuard.js.map +0 -1
  133. package/components/HeadlessCmsContentEntry/ContentEntryLocker.d.ts +0 -18
  134. package/components/HeadlessCmsContentEntry/ContentEntryLocker.js +0 -80
  135. package/components/HeadlessCmsContentEntry/ContentEntryLocker.js.map +0 -1
  136. package/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.d.ts +0 -2
  137. package/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.js +0 -44
  138. package/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.js.map +0 -1
  139. package/components/HeadlessCmsContentEntry/index.d.ts +0 -1
  140. package/components/HeadlessCmsContentEntry/index.js +0 -1
  141. package/components/LockedRecord/LockedRecord.d.ts +0 -6
  142. package/components/LockedRecord/LockedRecord.js +0 -54
  143. package/components/LockedRecord/LockedRecord.js.map +0 -1
  144. package/components/LockedRecord/LockedRecordForceUnlock.d.ts +0 -9
  145. package/components/LockedRecord/LockedRecordForceUnlock.js +0 -57
  146. package/components/LockedRecord/LockedRecordForceUnlock.js.map +0 -1
  147. package/components/LockedRecord/index.d.ts +0 -1
  148. package/components/LockedRecord/index.js +0 -1
  149. package/components/RecordLockingProvider.d.ts +0 -7
  150. package/components/RecordLockingProvider.js +0 -111
  151. package/components/RecordLockingProvider.js.map +0 -1
  152. package/components/SecurityPermissions.js.map +0 -1
  153. package/components/decorators/UseContentEntriesListHookDecorator.d.ts +0 -1
  154. package/components/decorators/UseContentEntriesListHookDecorator.js +0 -23
  155. package/components/decorators/UseContentEntriesListHookDecorator.js.map +0 -1
  156. package/components/decorators/UseRecordsDecorator.d.ts +0 -8
  157. package/components/decorators/UseRecordsDecorator.js +0 -16
  158. package/components/decorators/UseRecordsDecorator.js.map +0 -1
  159. package/components/decorators/UseSaveEntryDecorator.d.ts +0 -1
  160. package/components/decorators/UseSaveEntryDecorator.js +0 -41
  161. package/components/decorators/UseSaveEntryDecorator.js.map +0 -1
  162. package/domain/RecordLocking.d.ts +0 -28
  163. package/domain/RecordLocking.js +0 -259
  164. package/domain/RecordLocking.js.map +0 -1
  165. package/domain/RecordLockingClient.d.ts +0 -12
  166. package/domain/RecordLockingClient.js +0 -20
  167. package/domain/RecordLockingClient.js.map +0 -1
  168. package/domain/RecordLockingGetLockRecord.d.ts +0 -11
  169. package/domain/RecordLockingGetLockRecord.js +0 -19
  170. package/domain/RecordLockingGetLockRecord.js.map +0 -1
  171. package/domain/RecordLockingGetLockedEntryLockRecord.d.ts +0 -11
  172. package/domain/RecordLockingGetLockedEntryLockRecord.js +0 -18
  173. package/domain/RecordLockingGetLockedEntryLockRecord.js.map +0 -1
  174. package/domain/RecordLockingIsEntryLocked.d.ts +0 -11
  175. package/domain/RecordLockingIsEntryLocked.js +0 -20
  176. package/domain/RecordLockingIsEntryLocked.js.map +0 -1
  177. package/domain/RecordLockingListLockRecords.d.ts +0 -12
  178. package/domain/RecordLockingListLockRecords.js +0 -25
  179. package/domain/RecordLockingListLockRecords.js.map +0 -1
  180. package/domain/RecordLockingLockEntry.d.ts +0 -11
  181. package/domain/RecordLockingLockEntry.js +0 -12
  182. package/domain/RecordLockingLockEntry.js.map +0 -1
  183. package/domain/RecordLockingUnlockEntry.d.ts +0 -11
  184. package/domain/RecordLockingUnlockEntry.js +0 -18
  185. package/domain/RecordLockingUnlockEntry.js.map +0 -1
  186. package/domain/RecordLockingUpdateEntryLock.d.ts +0 -11
  187. package/domain/RecordLockingUpdateEntryLock.js +0 -18
  188. package/domain/RecordLockingUpdateEntryLock.js.map +0 -1
  189. package/domain/abstractions/IRecordLocking.d.ts +0 -25
  190. package/domain/abstractions/IRecordLocking.js +0 -0
  191. package/domain/abstractions/IRecordLockingClient.d.ts +0 -6
  192. package/domain/abstractions/IRecordLockingClient.js +0 -0
  193. package/domain/abstractions/IRecordLockingGetLockRecord.d.ts +0 -12
  194. package/domain/abstractions/IRecordLockingGetLockRecord.js +0 -0
  195. package/domain/abstractions/IRecordLockingGetLockedEntryLockRecord.d.ts +0 -12
  196. package/domain/abstractions/IRecordLockingGetLockedEntryLockRecord.js +0 -0
  197. package/domain/abstractions/IRecordLockingIsEntryLocked.d.ts +0 -8
  198. package/domain/abstractions/IRecordLockingIsEntryLocked.js +0 -0
  199. package/domain/abstractions/IRecordLockingListLockRecords.d.ts +0 -19
  200. package/domain/abstractions/IRecordLockingListLockRecords.js +0 -0
  201. package/domain/abstractions/IRecordLockingLockEntry.d.ts +0 -12
  202. package/domain/abstractions/IRecordLockingLockEntry.js +0 -0
  203. package/domain/abstractions/IRecordLockingUnlockEntry.d.ts +0 -13
  204. package/domain/abstractions/IRecordLockingUnlockEntry.js +0 -0
  205. package/domain/abstractions/IRecordLockingUpdateEntryLock.d.ts +0 -12
  206. package/domain/abstractions/IRecordLockingUpdateEntryLock.js +0 -0
  207. package/domain/graphql/fields.js.map +0 -1
  208. package/domain/graphql/getLockRecord.d.ts +0 -12
  209. package/domain/graphql/getLockRecord.js +0 -19
  210. package/domain/graphql/getLockRecord.js.map +0 -1
  211. package/domain/graphql/getLockedEntryLockRecord.d.ts +0 -12
  212. package/domain/graphql/getLockedEntryLockRecord.js +0 -19
  213. package/domain/graphql/getLockedEntryLockRecord.js.map +0 -1
  214. package/domain/graphql/isEntryLocked.d.ts +0 -12
  215. package/domain/graphql/isEntryLocked.js +0 -17
  216. package/domain/graphql/isEntryLocked.js.map +0 -1
  217. package/domain/graphql/listLockRecords.d.ts +0 -17
  218. package/domain/graphql/listLockRecords.js +0 -25
  219. package/domain/graphql/listLockRecords.js.map +0 -1
  220. package/domain/graphql/lockEntry.d.ts +0 -12
  221. package/domain/graphql/lockEntry.js +0 -19
  222. package/domain/graphql/lockEntry.js.map +0 -1
  223. package/domain/graphql/unlockEntry.d.ts +0 -12
  224. package/domain/graphql/unlockEntry.js +0 -19
  225. package/domain/graphql/unlockEntry.js.map +0 -1
  226. package/domain/graphql/updateEntryLock.d.ts +0 -12
  227. package/domain/graphql/updateEntryLock.js +0 -19
  228. package/domain/graphql/updateEntryLock.js.map +0 -1
  229. package/domain/permissionsSchema.js.map +0 -1
  230. package/domain/utils/createRecordLockingClient.d.ts +0 -3
  231. package/domain/utils/createRecordLockingClient.js +0 -11
  232. package/domain/utils/createRecordLockingClient.js.map +0 -1
  233. package/domain/utils/createRecordLockingError.d.ts +0 -6
  234. package/domain/utils/createRecordLockingError.js +0 -15
  235. package/domain/utils/createRecordLockingError.js.map +0 -1
  236. package/hooks/index.d.ts +0 -2
  237. package/hooks/index.js +0 -2
  238. package/hooks/usePermission.d.ts +0 -3
  239. package/hooks/usePermission.js +0 -19
  240. package/hooks/usePermission.js.map +0 -1
  241. package/hooks/useRecordLocking.d.ts +0 -2
  242. package/hooks/useRecordLocking.js +0 -11
  243. package/hooks/useRecordLocking.js.map +0 -1
  244. package/utils/createCacheKey.d.ts +0 -3
  245. package/utils/createCacheKey.js +0 -14
  246. package/utils/createCacheKey.js.map +0 -1
  247. /package/{components/SecurityPermissions.d.ts → SecurityPermissions.d.ts} +0 -0
  248. /package/{domain/graphql/fields.d.ts → features/graphqlFields.d.ts} +0 -0
  249. /package/{domain → permissions}/permissionsSchema.d.ts +0 -0
  250. /package/{domain → permissions}/permissionsSchema.js +0 -0
@@ -0,0 +1,61 @@
1
+ import { computed, makeAutoObservable } from "mobx";
2
+ import { ContentEntryFormPresenter } from "@webiny/app-headless-cms/presentation/contentEntries/form/abstractions.js";
3
+ import { RecordLockingPresenter } from "./abstractions.js";
4
+ class ContentEntryFormPresenterWithLocking {
5
+ constructor(lockingPresenter, original){
6
+ this.lockingPresenter = lockingPresenter;
7
+ this.original = original;
8
+ makeAutoObservable(this, {
9
+ lockingPresenter: false,
10
+ original: false,
11
+ vm: computed
12
+ });
13
+ }
14
+ get vm() {
15
+ const base = this.original.vm;
16
+ if (base.isNewEntry) return base;
17
+ const canEdit = this.lockingPresenter.vm.canEdit;
18
+ return {
19
+ ...base,
20
+ canSave: base.canSave && canEdit,
21
+ canPublish: base.canPublish && canEdit,
22
+ canUnpublish: base.canUnpublish && canEdit,
23
+ canDelete: base.canDelete && canEdit
24
+ };
25
+ }
26
+ async saveRevision(options) {
27
+ const result = await this.original.saveRevision(options);
28
+ if (result) await this.lockingPresenter.refreshLock();
29
+ return result;
30
+ }
31
+ publishRevision() {
32
+ return this.original.publishRevision();
33
+ }
34
+ unpublishRevision() {
35
+ return this.original.unpublishRevision();
36
+ }
37
+ deleteEntry() {
38
+ return this.original.deleteEntry();
39
+ }
40
+ loadRevision(id) {
41
+ return this.original.loadRevision(id);
42
+ }
43
+ setFolderId(folderId) {
44
+ this.original.setFolderId(folderId);
45
+ }
46
+ newEntry(initialValues) {
47
+ return this.original.newEntry(initialValues);
48
+ }
49
+ reset() {
50
+ return this.original.reset();
51
+ }
52
+ }
53
+ const ContentEntryFormPresenterLockingDecorator = ContentEntryFormPresenter.createDecorator({
54
+ decorator: ContentEntryFormPresenterWithLocking,
55
+ dependencies: [
56
+ RecordLockingPresenter
57
+ ]
58
+ });
59
+ export { ContentEntryFormPresenterLockingDecorator };
60
+
61
+ //# sourceMappingURL=ContentEntryFormPresenterDecorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/entryLocking/ContentEntryFormPresenterDecorator.js","sources":["../../../src/presentation/entryLocking/ContentEntryFormPresenterDecorator.ts"],"sourcesContent":["import { computed, makeAutoObservable } from \"mobx\";\nimport {\n ContentEntryFormPresenter,\n type IContentEntryFormPresenter,\n type IContentEntryFormViewModel\n} from \"@webiny/app-headless-cms/presentation/contentEntries/form/abstractions.js\";\nimport { RecordLockingPresenter } from \"./abstractions.js\";\n\nclass ContentEntryFormPresenterWithLocking implements IContentEntryFormPresenter {\n constructor(\n private lockingPresenter: RecordLockingPresenter.Interface,\n private original: IContentEntryFormPresenter\n ) {\n makeAutoObservable<ContentEntryFormPresenterWithLocking, \"lockingPresenter\" | \"original\">(\n this,\n {\n lockingPresenter: false,\n original: false,\n vm: computed\n }\n );\n }\n\n get vm(): IContentEntryFormViewModel {\n const base = this.original.vm;\n\n if (base.isNewEntry) {\n return base;\n }\n\n const canEdit = this.lockingPresenter.vm.canEdit;\n\n return {\n ...base,\n canSave: base.canSave && canEdit,\n canPublish: base.canPublish && canEdit,\n canUnpublish: base.canUnpublish && canEdit,\n canDelete: base.canDelete && canEdit\n };\n }\n\n async saveRevision(options?: { skipValidation?: boolean }): Promise<boolean> {\n const result = await this.original.saveRevision(options);\n\n if (result) {\n await this.lockingPresenter.refreshLock();\n }\n\n return result;\n }\n\n publishRevision(): Promise<boolean> {\n return this.original.publishRevision();\n }\n\n unpublishRevision(): Promise<boolean> {\n return this.original.unpublishRevision();\n }\n\n deleteEntry(): Promise<boolean> {\n return this.original.deleteEntry();\n }\n\n loadRevision(id: string): Promise<void> {\n return this.original.loadRevision(id);\n }\n\n setFolderId(folderId: string | null): void {\n this.original.setFolderId(folderId);\n }\n\n newEntry(initialValues?: Record<string, unknown>): void {\n return this.original.newEntry(initialValues);\n }\n\n reset(): void {\n return this.original.reset();\n }\n}\n\nexport const ContentEntryFormPresenterLockingDecorator = ContentEntryFormPresenter.createDecorator({\n decorator: ContentEntryFormPresenterWithLocking,\n dependencies: [RecordLockingPresenter]\n});\n"],"names":["ContentEntryFormPresenterWithLocking","lockingPresenter","original","makeAutoObservable","computed","base","canEdit","options","result","id","folderId","initialValues","ContentEntryFormPresenterLockingDecorator","ContentEntryFormPresenter","RecordLockingPresenter"],"mappings":";;;AAQA,MAAMA;IACF,YACYC,gBAAkD,EAClDC,QAAoC,CAC9C;aAFUD,gBAAgB,GAAhBA;aACAC,QAAQ,GAARA;QAERC,mBACI,IAAI,EACJ;YACI,kBAAkB;YAClB,UAAU;YACV,IAAIC;QACR;IAER;IAEA,IAAI,KAAiC;QACjC,MAAMC,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE;QAE7B,IAAIA,KAAK,UAAU,EACf,OAAOA;QAGX,MAAMC,UAAU,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,OAAO;QAEhD,OAAO;YACH,GAAGD,IAAI;YACP,SAASA,KAAK,OAAO,IAAIC;YACzB,YAAYD,KAAK,UAAU,IAAIC;YAC/B,cAAcD,KAAK,YAAY,IAAIC;YACnC,WAAWD,KAAK,SAAS,IAAIC;QACjC;IACJ;IAEA,MAAM,aAAaC,OAAsC,EAAoB;QACzE,MAAMC,SAAS,MAAM,IAAI,CAAC,QAAQ,CAAC,YAAY,CAACD;QAEhD,IAAIC,QACA,MAAM,IAAI,CAAC,gBAAgB,CAAC,WAAW;QAG3C,OAAOA;IACX;IAEA,kBAAoC;QAChC,OAAO,IAAI,CAAC,QAAQ,CAAC,eAAe;IACxC;IAEA,oBAAsC;QAClC,OAAO,IAAI,CAAC,QAAQ,CAAC,iBAAiB;IAC1C;IAEA,cAAgC;QAC5B,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW;IACpC;IAEA,aAAaC,EAAU,EAAiB;QACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAACA;IACtC;IAEA,YAAYC,QAAuB,EAAQ;QACvC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAACA;IAC9B;IAEA,SAASC,aAAuC,EAAQ;QACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAACA;IAClC;IAEA,QAAc;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK;IAC9B;AACJ;AAEO,MAAMC,4CAA4CC,0BAA0B,eAAe,CAAC;IAC/F,WAAWb;IACX,cAAc;QAACc;KAAuB;AAC1C"}
@@ -0,0 +1,32 @@
1
+ import { IdentityContext } from "@webiny/app-admin/features/security/IdentityContext/abstractions.js";
2
+ import { AcquireLockUseCase } from "../../features/acquireLock/abstractions.js";
3
+ import { CheckLockStatusUseCase } from "../../features/checkLockStatus/abstractions.js";
4
+ import { ReleaseLockUseCase } from "../../features/releaseLock/abstractions.js";
5
+ import { ForceUnlockUseCase } from "../../features/forceUnlock/abstractions.js";
6
+ import { type IRecordLockingPresenter, type IRecordLockingViewModel, type IKickOutData } from "./abstractions.js";
7
+ declare class RecordLockingPresenterImpl implements IRecordLockingPresenter {
8
+ private acquireLockUseCase;
9
+ private checkLockStatusUseCase;
10
+ private releaseLockUseCase;
11
+ private forceUnlockUseCase;
12
+ private identityContext;
13
+ private _status;
14
+ private _lockRecord;
15
+ private _entryId;
16
+ private _type;
17
+ private _heartbeatTimer;
18
+ constructor(acquireLockUseCase: AcquireLockUseCase.Interface, checkLockStatusUseCase: CheckLockStatusUseCase.Interface, releaseLockUseCase: ReleaseLockUseCase.Interface, forceUnlockUseCase: ForceUnlockUseCase.Interface, identityContext: IdentityContext.Interface);
19
+ get vm(): IRecordLockingViewModel;
20
+ private checkCanForceUnlock;
21
+ init(entryId: string, type: string): Promise<void>;
22
+ refreshLock(): Promise<void>;
23
+ forceUnlock(): Promise<boolean>;
24
+ handleKickOut(data: IKickOutData): void;
25
+ dispose(): void;
26
+ private startHeartbeat;
27
+ private stopHeartbeat;
28
+ }
29
+ export declare const RecordLockingPresenter: typeof RecordLockingPresenterImpl & {
30
+ __abstraction: import("@webiny/di").Abstraction<IRecordLockingPresenter>;
31
+ };
32
+ export {};
@@ -0,0 +1,164 @@
1
+ import { computed, makeAutoObservable, runInAction } from "mobx";
2
+ import { parseIdentifier } from "@webiny/utils";
3
+ import { IdentityContext } from "@webiny/app-admin/features/security/IdentityContext/abstractions.js";
4
+ import { AcquireLockUseCase } from "../../features/acquireLock/abstractions.js";
5
+ import { CheckLockStatusUseCase } from "../../features/checkLockStatus/abstractions.js";
6
+ import { ReleaseLockUseCase } from "../../features/releaseLock/abstractions.js";
7
+ import { ForceUnlockUseCase } from "../../features/forceUnlock/abstractions.js";
8
+ import { RecordLockingPresenter } from "./abstractions.js";
9
+ const HEARTBEAT_INTERVAL_MS = 20000;
10
+ class RecordLockingPresenterImpl {
11
+ constructor(acquireLockUseCase, checkLockStatusUseCase, releaseLockUseCase, forceUnlockUseCase, identityContext){
12
+ this.acquireLockUseCase = acquireLockUseCase;
13
+ this.checkLockStatusUseCase = checkLockStatusUseCase;
14
+ this.releaseLockUseCase = releaseLockUseCase;
15
+ this.forceUnlockUseCase = forceUnlockUseCase;
16
+ this.identityContext = identityContext;
17
+ this._status = null;
18
+ this._lockRecord = null;
19
+ this._entryId = null;
20
+ this._type = null;
21
+ this._heartbeatTimer = null;
22
+ makeAutoObservable(this, {
23
+ acquireLockUseCase: false,
24
+ checkLockStatusUseCase: false,
25
+ releaseLockUseCase: false,
26
+ forceUnlockUseCase: false,
27
+ identityContext: false,
28
+ vm: computed
29
+ });
30
+ }
31
+ get vm() {
32
+ return {
33
+ status: this._status,
34
+ lockRecord: this._lockRecord,
35
+ lockedByUserName: this._lockRecord?.lockedBy?.displayName ?? null,
36
+ canForceUnlock: this.checkCanForceUnlock(),
37
+ canEdit: "acquired" === this._status
38
+ };
39
+ }
40
+ checkCanForceUnlock() {
41
+ const identity = this.identityContext.getIdentity();
42
+ if (identity.getPermission("recordLocking.*")) return true;
43
+ const permission = identity.getPermission("recordLocking");
44
+ return permission?.canForceUnlock === true;
45
+ }
46
+ async init(entryId, type) {
47
+ const { id } = parseIdentifier(entryId);
48
+ this._entryId = id;
49
+ this._type = type;
50
+ this._status = "checking";
51
+ try {
52
+ const lockRecord = await this.checkLockStatusUseCase.execute({
53
+ id,
54
+ type
55
+ });
56
+ if (lockRecord) return void runInAction(()=>{
57
+ this._status = "locked";
58
+ this._lockRecord = lockRecord;
59
+ });
60
+ const acquired = await this.acquireLockUseCase.execute({
61
+ id,
62
+ type
63
+ });
64
+ runInAction(()=>{
65
+ this._status = "acquired";
66
+ this._lockRecord = acquired;
67
+ });
68
+ this.startHeartbeat(id, type);
69
+ } catch {
70
+ runInAction(()=>{
71
+ this._status = "error";
72
+ });
73
+ }
74
+ }
75
+ async refreshLock() {
76
+ if ("acquired" !== this._status || !this._entryId || !this._type) return;
77
+ try {
78
+ const record = await this.acquireLockUseCase.execute({
79
+ id: this._entryId,
80
+ type: this._type
81
+ });
82
+ runInAction(()=>{
83
+ this._lockRecord = record;
84
+ });
85
+ } catch {}
86
+ }
87
+ async forceUnlock() {
88
+ if (!this._lockRecord || !this._type) return false;
89
+ try {
90
+ await this.forceUnlockUseCase.execute({
91
+ id: this._lockRecord.targetId,
92
+ type: this._type
93
+ });
94
+ const acquired = await this.acquireLockUseCase.execute({
95
+ id: this._lockRecord.targetId,
96
+ type: this._type
97
+ });
98
+ runInAction(()=>{
99
+ this._status = "acquired";
100
+ this._lockRecord = acquired;
101
+ });
102
+ this.startHeartbeat(this._lockRecord.targetId, this._type);
103
+ return true;
104
+ } catch {
105
+ return false;
106
+ }
107
+ }
108
+ handleKickOut(data) {
109
+ this.stopHeartbeat();
110
+ runInAction(()=>{
111
+ this._status = "kicked-out";
112
+ this._lockRecord = data.record;
113
+ });
114
+ }
115
+ dispose() {
116
+ this.stopHeartbeat();
117
+ if ("acquired" === this._status && this._entryId && this._type) this.releaseLockUseCase.execute({
118
+ id: this._entryId,
119
+ type: this._type
120
+ }).catch(()=>{});
121
+ this._status = null;
122
+ this._lockRecord = null;
123
+ this._entryId = null;
124
+ this._type = null;
125
+ }
126
+ startHeartbeat(entryId, type) {
127
+ this.stopHeartbeat();
128
+ this._heartbeatTimer = setInterval(async ()=>{
129
+ try {
130
+ const record = await this.acquireLockUseCase.execute({
131
+ id: entryId,
132
+ type
133
+ });
134
+ runInAction(()=>{
135
+ this._lockRecord = record;
136
+ });
137
+ } catch {
138
+ this.stopHeartbeat();
139
+ runInAction(()=>{
140
+ this._status = "error";
141
+ });
142
+ }
143
+ }, HEARTBEAT_INTERVAL_MS);
144
+ }
145
+ stopHeartbeat() {
146
+ if (null !== this._heartbeatTimer) {
147
+ clearInterval(this._heartbeatTimer);
148
+ this._heartbeatTimer = null;
149
+ }
150
+ }
151
+ }
152
+ const RecordLockingPresenter_RecordLockingPresenter = RecordLockingPresenter.createImplementation({
153
+ implementation: RecordLockingPresenterImpl,
154
+ dependencies: [
155
+ AcquireLockUseCase,
156
+ CheckLockStatusUseCase,
157
+ ReleaseLockUseCase,
158
+ ForceUnlockUseCase,
159
+ IdentityContext
160
+ ]
161
+ });
162
+ export { RecordLockingPresenter_RecordLockingPresenter as RecordLockingPresenter };
163
+
164
+ //# sourceMappingURL=RecordLockingPresenter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/entryLocking/RecordLockingPresenter.js","sources":["../../../src/presentation/entryLocking/RecordLockingPresenter.ts"],"sourcesContent":["import { computed, makeAutoObservable, runInAction } from \"mobx\";\nimport { parseIdentifier } from \"@webiny/utils\";\nimport { IdentityContext } from \"@webiny/app-admin/features/security/IdentityContext/abstractions.js\";\nimport { AcquireLockUseCase } from \"~/features/acquireLock/abstractions.js\";\nimport { CheckLockStatusUseCase } from \"~/features/checkLockStatus/abstractions.js\";\nimport { ReleaseLockUseCase } from \"~/features/releaseLock/abstractions.js\";\nimport { ForceUnlockUseCase } from \"~/features/forceUnlock/abstractions.js\";\nimport {\n RecordLockingPresenter as Abstraction,\n type IRecordLockingPresenter,\n type IRecordLockingViewModel,\n type IKickOutData,\n type RecordLockingStatus\n} from \"./abstractions.js\";\nimport type { IRecordLockingLockRecord } from \"~/types.js\";\n\nconst HEARTBEAT_INTERVAL_MS = 20_000;\n\nclass RecordLockingPresenterImpl implements IRecordLockingPresenter {\n private _status: RecordLockingStatus = null;\n private _lockRecord: IRecordLockingLockRecord | null = null;\n private _entryId: string | null = null;\n private _type: string | null = null;\n private _heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(\n private acquireLockUseCase: AcquireLockUseCase.Interface,\n private checkLockStatusUseCase: CheckLockStatusUseCase.Interface,\n private releaseLockUseCase: ReleaseLockUseCase.Interface,\n private forceUnlockUseCase: ForceUnlockUseCase.Interface,\n private identityContext: IdentityContext.Interface\n ) {\n makeAutoObservable<\n RecordLockingPresenterImpl,\n | \"acquireLockUseCase\"\n | \"checkLockStatusUseCase\"\n | \"releaseLockUseCase\"\n | \"forceUnlockUseCase\"\n | \"identityContext\"\n >(this, {\n acquireLockUseCase: false,\n checkLockStatusUseCase: false,\n releaseLockUseCase: false,\n forceUnlockUseCase: false,\n identityContext: false,\n vm: computed\n });\n }\n\n get vm(): IRecordLockingViewModel {\n return {\n status: this._status,\n lockRecord: this._lockRecord,\n lockedByUserName: this._lockRecord?.lockedBy?.displayName ?? null,\n canForceUnlock: this.checkCanForceUnlock(),\n canEdit: this._status === \"acquired\"\n };\n }\n\n private checkCanForceUnlock(): boolean {\n const identity = this.identityContext.getIdentity();\n\n if (identity.getPermission(\"recordLocking.*\")) {\n return true;\n }\n\n const permission = identity.getPermission(\"recordLocking\");\n return permission?.canForceUnlock === true;\n }\n\n async init(entryId: string, type: string): Promise<void> {\n const { id } = parseIdentifier(entryId);\n\n this._entryId = id;\n this._type = type;\n this._status = \"checking\";\n\n try {\n const lockRecord = await this.checkLockStatusUseCase.execute({\n id,\n type\n });\n\n if (lockRecord) {\n runInAction(() => {\n this._status = \"locked\";\n this._lockRecord = lockRecord;\n });\n return;\n }\n\n const acquired = await this.acquireLockUseCase.execute({\n id,\n type\n });\n\n runInAction(() => {\n this._status = \"acquired\";\n this._lockRecord = acquired;\n });\n\n this.startHeartbeat(id, type);\n } catch {\n runInAction(() => {\n this._status = \"error\";\n });\n }\n }\n\n async refreshLock(): Promise<void> {\n if (this._status !== \"acquired\" || !this._entryId || !this._type) {\n return;\n }\n\n try {\n const record = await this.acquireLockUseCase.execute({\n id: this._entryId,\n type: this._type\n });\n\n runInAction(() => {\n this._lockRecord = record;\n });\n } catch {\n // Heartbeat will retry\n }\n }\n\n async forceUnlock(): Promise<boolean> {\n if (!this._lockRecord || !this._type) {\n return false;\n }\n\n try {\n await this.forceUnlockUseCase.execute({\n id: this._lockRecord.targetId,\n type: this._type\n });\n\n const acquired = await this.acquireLockUseCase.execute({\n id: this._lockRecord.targetId,\n type: this._type\n });\n\n runInAction(() => {\n this._status = \"acquired\";\n this._lockRecord = acquired;\n });\n\n this.startHeartbeat(this._lockRecord.targetId, this._type);\n\n return true;\n } catch {\n return false;\n }\n }\n\n handleKickOut(data: IKickOutData): void {\n this.stopHeartbeat();\n\n runInAction(() => {\n this._status = \"kicked-out\";\n this._lockRecord = data.record;\n });\n }\n\n dispose(): void {\n this.stopHeartbeat();\n\n if (this._status === \"acquired\" && this._entryId && this._type) {\n this.releaseLockUseCase\n .execute({ id: this._entryId, type: this._type })\n .catch(() => {});\n }\n\n this._status = null;\n this._lockRecord = null;\n this._entryId = null;\n this._type = null;\n }\n\n private startHeartbeat(entryId: string, type: string): void {\n this.stopHeartbeat();\n\n this._heartbeatTimer = setInterval(async () => {\n try {\n const record = await this.acquireLockUseCase.execute({ id: entryId, type });\n runInAction(() => {\n this._lockRecord = record;\n });\n } catch {\n this.stopHeartbeat();\n runInAction(() => {\n this._status = \"error\";\n });\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n private stopHeartbeat(): void {\n if (this._heartbeatTimer !== null) {\n clearInterval(this._heartbeatTimer);\n this._heartbeatTimer = null;\n }\n }\n}\n\nexport const RecordLockingPresenter = Abstraction.createImplementation({\n implementation: RecordLockingPresenterImpl,\n dependencies: [\n AcquireLockUseCase,\n CheckLockStatusUseCase,\n ReleaseLockUseCase,\n ForceUnlockUseCase,\n IdentityContext\n ]\n});\n"],"names":["HEARTBEAT_INTERVAL_MS","RecordLockingPresenterImpl","acquireLockUseCase","checkLockStatusUseCase","releaseLockUseCase","forceUnlockUseCase","identityContext","makeAutoObservable","computed","identity","permission","entryId","type","id","parseIdentifier","lockRecord","runInAction","acquired","record","data","setInterval","clearInterval","RecordLockingPresenter","Abstraction","AcquireLockUseCase","CheckLockStatusUseCase","ReleaseLockUseCase","ForceUnlockUseCase","IdentityContext"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import React from "react";
2
+ export declare const SingleEntryContentDecorator: (props: unknown) => React.JSX.Element;
@@ -0,0 +1,72 @@
1
+ import react from "react";
2
+ import { observer } from "mobx-react-lite";
3
+ import { useContainer, useRouter } from "@webiny/app";
4
+ import { useDialogs } from "@webiny/app-admin";
5
+ import { useWebsockets } from "@webiny/app-websockets";
6
+ import { OverlayLoader } from "@webiny/admin-ui";
7
+ import { parseIdentifier } from "@webiny/utils";
8
+ import { SingleEntryFormContent } from "@webiny/app-headless-cms/presentation/contentEntries/views/SingleEntryFormContent.js";
9
+ import { SingleEntryPresenter } from "@webiny/app-headless-cms/presentation/contentEntries/singleEntry/abstractions.js";
10
+ import { CmsModelContext } from "@webiny/app-headless-cms/features/contentEntry/abstractions.js";
11
+ import { RecordLockingPresenter } from "./abstractions.js";
12
+ import { LockedEntryOverlay } from "./components/LockedEntryOverlay.js";
13
+ const SingleEntryContentDecorator = SingleEntryFormContent.createDecorator((Original)=>observer(function(props) {
14
+ const container = useContainer();
15
+ const websockets = useWebsockets();
16
+ const router = useRouter();
17
+ const { showDialog } = useDialogs();
18
+ const singleEntryPresenter = react.useMemo(()=>container.resolve(SingleEntryPresenter), [
19
+ container
20
+ ]);
21
+ const lockingPresenter = react.useMemo(()=>container.resolve(RecordLockingPresenter), [
22
+ container
23
+ ]);
24
+ const modelAccessor = react.useMemo(()=>container.resolve(CmsModelContext), [
25
+ container
26
+ ]);
27
+ const entry = singleEntryPresenter.vm.entry;
28
+ react.useEffect(()=>{
29
+ if (!entry?.id) return;
30
+ lockingPresenter.init(entry.id, modelAccessor.getModel().modelId);
31
+ return ()=>lockingPresenter.dispose();
32
+ }, [
33
+ entry?.id
34
+ ]);
35
+ react.useEffect(()=>{
36
+ if (!entry?.id) return;
37
+ const { id } = parseIdentifier(entry.id);
38
+ const sub = websockets.onMessage(`recordLocking.entry.kickOut.${id}`, (incoming)=>lockingPresenter.handleKickOut(incoming.data));
39
+ return ()=>{
40
+ sub.off();
41
+ };
42
+ }, [
43
+ entry?.id
44
+ ]);
45
+ react.useEffect(()=>{
46
+ if ("kicked-out" !== lockingPresenter.vm.status) return;
47
+ router.unblockTransition();
48
+ showDialog({
49
+ title: "Entry was forcefully unlocked!",
50
+ content: /*#__PURE__*/ react.createElement(react.Fragment, null, "The entry you were editing was forcefully unlocked by", " ", /*#__PURE__*/ react.createElement("strong", null, lockingPresenter.vm.lockRecord?.lockedBy?.displayName || "Unknown user"), ". Unfortunately, this means you lost the unsaved changes."),
51
+ acceptLabel: "Ok",
52
+ onClose: void 0,
53
+ cancelLabel: null
54
+ });
55
+ }, [
56
+ lockingPresenter.vm.status
57
+ ]);
58
+ if (!entry?.id) return /*#__PURE__*/ react.createElement(Original, props);
59
+ if ("checking" === lockingPresenter.vm.status) return /*#__PURE__*/ react.createElement(OverlayLoader, {
60
+ text: "Checking record status..."
61
+ });
62
+ if ("locked" === lockingPresenter.vm.status) return /*#__PURE__*/ react.createElement(LockedEntryOverlay, {
63
+ vm: lockingPresenter.vm,
64
+ entryTitle: entry.meta?.title,
65
+ onForceUnlock: ()=>lockingPresenter.forceUnlock(),
66
+ onNavigateBack: ()=>{}
67
+ });
68
+ return /*#__PURE__*/ react.createElement(Original, props);
69
+ }));
70
+ export { SingleEntryContentDecorator };
71
+
72
+ //# sourceMappingURL=SingleEntryContentDecorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/entryLocking/SingleEntryContentDecorator.js","sources":["../../../src/presentation/entryLocking/SingleEntryContentDecorator.tsx"],"sourcesContent":["import React from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { useContainer, useRouter } from \"@webiny/app\";\nimport { useDialogs } from \"@webiny/app-admin\";\nimport { useWebsockets } from \"@webiny/app-websockets\";\nimport { OverlayLoader } from \"@webiny/admin-ui\";\nimport { parseIdentifier } from \"@webiny/utils\";\nimport { SingleEntryFormContent } from \"@webiny/app-headless-cms/presentation/contentEntries/views/SingleEntryFormContent.js\";\nimport { SingleEntryPresenter } from \"@webiny/app-headless-cms/presentation/contentEntries/singleEntry/abstractions.js\";\nimport { CmsModelContext } from \"@webiny/app-headless-cms/features/contentEntry/abstractions.js\";\nimport { RecordLockingPresenter } from \"./abstractions.js\";\nimport { LockedEntryOverlay } from \"./components/LockedEntryOverlay.js\";\nimport type { IKickOutData } from \"./abstractions.js\";\nimport type { IncomingGenericData } from \"@webiny/app-websockets\";\n\ninterface KickOutMessage extends IncomingGenericData {\n data: IKickOutData;\n}\n\nexport const SingleEntryContentDecorator = SingleEntryFormContent.createDecorator(Original => {\n return observer(function RecordLockingSingleEntryContent(props) {\n const container = useContainer();\n const websockets = useWebsockets();\n const router = useRouter();\n const { showDialog } = useDialogs();\n\n const singleEntryPresenter = React.useMemo(\n () => container.resolve(SingleEntryPresenter),\n [container]\n );\n\n const lockingPresenter = React.useMemo(\n () => container.resolve(RecordLockingPresenter),\n [container]\n );\n\n const modelAccessor = React.useMemo(() => container.resolve(CmsModelContext), [container]);\n\n const entry = singleEntryPresenter.vm.entry;\n\n React.useEffect(() => {\n if (!entry?.id) {\n return;\n }\n lockingPresenter.init(entry.id, modelAccessor.getModel().modelId);\n return () => lockingPresenter.dispose();\n }, [entry?.id]);\n\n React.useEffect(() => {\n if (!entry?.id) {\n return;\n }\n const { id } = parseIdentifier(entry.id);\n const sub = websockets.onMessage<KickOutMessage>(\n `recordLocking.entry.kickOut.${id}`,\n incoming => lockingPresenter.handleKickOut(incoming.data)\n );\n return () => {\n sub.off();\n };\n }, [entry?.id]);\n\n React.useEffect(() => {\n if (lockingPresenter.vm.status !== \"kicked-out\") {\n return;\n }\n\n router.unblockTransition();\n showDialog({\n title: \"Entry was forcefully unlocked!\",\n content: (\n <>\n The entry you were editing was forcefully unlocked by{\" \"}\n <strong>\n {lockingPresenter.vm.lockRecord?.lockedBy?.displayName ||\n \"Unknown user\"}\n </strong>\n . Unfortunately, this means you lost the unsaved changes.\n </>\n ),\n acceptLabel: \"Ok\",\n onClose: undefined,\n cancelLabel: null\n });\n }, [lockingPresenter.vm.status]);\n\n if (!entry?.id) {\n return <Original {...props} />;\n }\n\n if (lockingPresenter.vm.status === \"checking\") {\n return <OverlayLoader text={\"Checking record status...\"} />;\n }\n\n if (lockingPresenter.vm.status === \"locked\") {\n return (\n <LockedEntryOverlay\n vm={lockingPresenter.vm}\n entryTitle={entry.meta?.title}\n onForceUnlock={() => lockingPresenter.forceUnlock()}\n onNavigateBack={() => {\n // It's a single-entry model, so there's nowhere to go.\n }}\n />\n );\n }\n\n return <Original {...props} />;\n });\n});\n"],"names":["SingleEntryContentDecorator","SingleEntryFormContent","Original","observer","props","container","useContainer","websockets","useWebsockets","router","useRouter","showDialog","useDialogs","singleEntryPresenter","React","SingleEntryPresenter","lockingPresenter","RecordLockingPresenter","modelAccessor","CmsModelContext","entry","id","parseIdentifier","sub","incoming","undefined","OverlayLoader","LockedEntryOverlay"],"mappings":";;;;;;;;;;;;AAmBO,MAAMA,8BAA8BC,uBAAuB,eAAe,CAACC,CAAAA,WACvEC,SAAS,SAAyCC,KAAK;QAC1D,MAAMC,YAAYC;QAClB,MAAMC,aAAaC;QACnB,MAAMC,SAASC;QACf,MAAM,EAAEC,UAAU,EAAE,GAAGC;QAEvB,MAAMC,uBAAuBC,MAAAA,OAAa,CACtC,IAAMT,UAAU,OAAO,CAACU,uBACxB;YAACV;SAAU;QAGf,MAAMW,mBAAmBF,MAAAA,OAAa,CAClC,IAAMT,UAAU,OAAO,CAACY,yBACxB;YAACZ;SAAU;QAGf,MAAMa,gBAAgBJ,MAAAA,OAAa,CAAC,IAAMT,UAAU,OAAO,CAACc,kBAAkB;YAACd;SAAU;QAEzF,MAAMe,QAAQP,qBAAqB,EAAE,CAAC,KAAK;QAE3CC,MAAAA,SAAe,CAAC;YACZ,IAAI,CAACM,OAAO,IACR;YAEJJ,iBAAiB,IAAI,CAACI,MAAM,EAAE,EAAEF,cAAc,QAAQ,GAAG,OAAO;YAChE,OAAO,IAAMF,iBAAiB,OAAO;QACzC,GAAG;YAACI,OAAO;SAAG;QAEdN,MAAAA,SAAe,CAAC;YACZ,IAAI,CAACM,OAAO,IACR;YAEJ,MAAM,EAAEC,EAAE,EAAE,GAAGC,gBAAgBF,MAAM,EAAE;YACvC,MAAMG,MAAMhB,WAAW,SAAS,CAC5B,CAAC,4BAA4B,EAAEc,IAAI,EACnCG,CAAAA,WAAYR,iBAAiB,aAAa,CAACQ,SAAS,IAAI;YAE5D,OAAO;gBACHD,IAAI,GAAG;YACX;QACJ,GAAG;YAACH,OAAO;SAAG;QAEdN,MAAAA,SAAe,CAAC;YACZ,IAAIE,AAA+B,iBAA/BA,iBAAiB,EAAE,CAAC,MAAM,EAC1B;YAGJP,OAAO,iBAAiB;YACxBE,WAAW;gBACP,OAAO;gBACP,SAAS,WAAT,GACI,0CAAE,yDACwD,mBACtD,oBAAC,gBACIK,iBAAiB,EAAE,CAAC,UAAU,EAAE,UAAU,eACvC,iBACC;gBAIjB,aAAa;gBACb,SAASS;gBACT,aAAa;YACjB;QACJ,GAAG;YAACT,iBAAiB,EAAE,CAAC,MAAM;SAAC;QAE/B,IAAI,CAACI,OAAO,IACR,OAAO,WAAP,GAAO,oBAAClB,UAAaE;QAGzB,IAAIY,AAA+B,eAA/BA,iBAAiB,EAAE,CAAC,MAAM,EAC1B,OAAO,WAAP,GAAO,oBAACU,eAAaA;YAAC,MAAM;;QAGhC,IAAIV,AAA+B,aAA/BA,iBAAiB,EAAE,CAAC,MAAM,EAC1B,OAAO,WAAP,GACI,oBAACW,oBAAkBA;YACf,IAAIX,iBAAiB,EAAE;YACvB,YAAYI,MAAM,IAAI,EAAE;YACxB,eAAe,IAAMJ,iBAAiB,WAAW;YACjD,gBAAgB,KAEhB;;QAKZ,OAAO,WAAP,GAAO,oBAACd,UAAaE;IACzB"}
@@ -0,0 +1,15 @@
1
+ import { type ISingleEntryPresenter, type ISingleEntryViewModel } from "@webiny/app-headless-cms/presentation/contentEntries/singleEntry/abstractions.js";
2
+ import { RecordLockingPresenter } from "./abstractions.js";
3
+ declare class SingleEntryPresenterWithLocking implements ISingleEntryPresenter {
4
+ private lockingPresenter;
5
+ private original;
6
+ constructor(lockingPresenter: RecordLockingPresenter.Interface, original: ISingleEntryPresenter);
7
+ get vm(): ISingleEntryViewModel;
8
+ init(): Promise<void>;
9
+ save(): Promise<boolean>;
10
+ dispose(): void;
11
+ }
12
+ export declare const SingleEntryPresenterLockingDecorator: typeof SingleEntryPresenterWithLocking & {
13
+ __abstraction: import("@webiny/di").Abstraction<ISingleEntryPresenter>;
14
+ };
15
+ export {};
@@ -0,0 +1,40 @@
1
+ import { computed, makeAutoObservable } from "mobx";
2
+ import { SingleEntryPresenter } from "@webiny/app-headless-cms/presentation/contentEntries/singleEntry/abstractions.js";
3
+ import { RecordLockingPresenter } from "./abstractions.js";
4
+ class SingleEntryPresenterWithLocking {
5
+ constructor(lockingPresenter, original){
6
+ this.lockingPresenter = lockingPresenter;
7
+ this.original = original;
8
+ makeAutoObservable(this, {
9
+ lockingPresenter: false,
10
+ original: false,
11
+ vm: computed
12
+ });
13
+ }
14
+ get vm() {
15
+ const base = this.original.vm;
16
+ const canEdit = this.lockingPresenter.vm.canEdit;
17
+ return {
18
+ ...base,
19
+ canSave: base.canSave && canEdit
20
+ };
21
+ }
22
+ async init() {
23
+ return this.original.init();
24
+ }
25
+ async save() {
26
+ return this.original.save();
27
+ }
28
+ dispose() {
29
+ return this.original.dispose();
30
+ }
31
+ }
32
+ const SingleEntryPresenterLockingDecorator = SingleEntryPresenter.createDecorator({
33
+ decorator: SingleEntryPresenterWithLocking,
34
+ dependencies: [
35
+ RecordLockingPresenter
36
+ ]
37
+ });
38
+ export { SingleEntryPresenterLockingDecorator };
39
+
40
+ //# sourceMappingURL=SingleEntryPresenterDecorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/entryLocking/SingleEntryPresenterDecorator.js","sources":["../../../src/presentation/entryLocking/SingleEntryPresenterDecorator.ts"],"sourcesContent":["import { computed, makeAutoObservable } from \"mobx\";\nimport {\n SingleEntryPresenter,\n type ISingleEntryPresenter,\n type ISingleEntryViewModel\n} from \"@webiny/app-headless-cms/presentation/contentEntries/singleEntry/abstractions.js\";\nimport { RecordLockingPresenter } from \"./abstractions.js\";\n\nclass SingleEntryPresenterWithLocking implements ISingleEntryPresenter {\n constructor(\n private lockingPresenter: RecordLockingPresenter.Interface,\n private original: ISingleEntryPresenter\n ) {\n makeAutoObservable<SingleEntryPresenterWithLocking, \"lockingPresenter\" | \"original\">(this, {\n lockingPresenter: false,\n original: false,\n vm: computed\n });\n }\n\n get vm(): ISingleEntryViewModel {\n const base = this.original.vm;\n const canEdit = this.lockingPresenter.vm.canEdit;\n\n return {\n ...base,\n canSave: base.canSave && canEdit\n };\n }\n\n async init(): Promise<void> {\n return this.original.init();\n }\n\n async save(): Promise<boolean> {\n return this.original.save();\n }\n\n dispose(): void {\n return this.original.dispose();\n }\n}\n\nexport const SingleEntryPresenterLockingDecorator = SingleEntryPresenter.createDecorator({\n decorator: SingleEntryPresenterWithLocking,\n dependencies: [RecordLockingPresenter]\n});\n"],"names":["SingleEntryPresenterWithLocking","lockingPresenter","original","makeAutoObservable","computed","base","canEdit","SingleEntryPresenterLockingDecorator","SingleEntryPresenter","RecordLockingPresenter"],"mappings":";;;AAQA,MAAMA;IACF,YACYC,gBAAkD,EAClDC,QAA+B,CACzC;aAFUD,gBAAgB,GAAhBA;aACAC,QAAQ,GAARA;QAERC,mBAAqF,IAAI,EAAE;YACvF,kBAAkB;YAClB,UAAU;YACV,IAAIC;QACR;IACJ;IAEA,IAAI,KAA4B;QAC5B,MAAMC,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE;QAC7B,MAAMC,UAAU,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,OAAO;QAEhD,OAAO;YACH,GAAGD,IAAI;YACP,SAASA,KAAK,OAAO,IAAIC;QAC7B;IACJ;IAEA,MAAM,OAAsB;QACxB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI;IAC7B;IAEA,MAAM,OAAyB;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI;IAC7B;IAEA,UAAgB;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO;IAChC;AACJ;AAEO,MAAMC,uCAAuCC,qBAAqB,eAAe,CAAC;IACrF,WAAWR;IACX,cAAc;QAACS;KAAuB;AAC1C"}
@@ -0,0 +1,26 @@
1
+ import type { IRecordLockingIdentity, IRecordLockingLockRecord } from "../../types.js";
2
+ export type RecordLockingStatus = "checking" | "locked" | "acquired" | "kicked-out" | "error" | null;
3
+ export interface IRecordLockingViewModel {
4
+ status: RecordLockingStatus;
5
+ lockRecord: IRecordLockingLockRecord | null;
6
+ lockedByUserName: string | null;
7
+ canForceUnlock: boolean;
8
+ canEdit: boolean;
9
+ }
10
+ export interface IKickOutData {
11
+ record: IRecordLockingLockRecord;
12
+ user: IRecordLockingIdentity;
13
+ }
14
+ export interface IRecordLockingPresenter {
15
+ readonly vm: IRecordLockingViewModel;
16
+ init(entryId: string, type: string): Promise<void>;
17
+ refreshLock(): Promise<void>;
18
+ forceUnlock(): Promise<boolean>;
19
+ handleKickOut(data: IKickOutData): void;
20
+ dispose(): void;
21
+ }
22
+ export declare const RecordLockingPresenter: import("@webiny/di").Abstraction<IRecordLockingPresenter>;
23
+ export declare namespace RecordLockingPresenter {
24
+ type Interface = IRecordLockingPresenter;
25
+ type ViewModel = IRecordLockingViewModel;
26
+ }
@@ -0,0 +1,5 @@
1
+ import { createAbstraction } from "@webiny/feature/admin";
2
+ const RecordLockingPresenter = createAbstraction("RecordLockingPresenter");
3
+ export { RecordLockingPresenter };
4
+
5
+ //# sourceMappingURL=abstractions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/entryLocking/abstractions.js","sources":["../../../src/presentation/entryLocking/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\nimport type { IRecordLockingIdentity, IRecordLockingLockRecord } from \"~/types.js\";\n\nexport type RecordLockingStatus =\n | \"checking\"\n | \"locked\"\n | \"acquired\"\n | \"kicked-out\"\n | \"error\"\n | null;\n\nexport interface IRecordLockingViewModel {\n status: RecordLockingStatus;\n lockRecord: IRecordLockingLockRecord | null;\n lockedByUserName: string | null;\n canForceUnlock: boolean;\n canEdit: boolean;\n}\n\nexport interface IKickOutData {\n record: IRecordLockingLockRecord;\n user: IRecordLockingIdentity;\n}\n\nexport interface IRecordLockingPresenter {\n readonly vm: IRecordLockingViewModel;\n init(entryId: string, type: string): Promise<void>;\n refreshLock(): Promise<void>;\n forceUnlock(): Promise<boolean>;\n handleKickOut(data: IKickOutData): void;\n dispose(): void;\n}\n\nexport const RecordLockingPresenter =\n createAbstraction<IRecordLockingPresenter>(\"RecordLockingPresenter\");\n\nexport namespace RecordLockingPresenter {\n export type Interface = IRecordLockingPresenter;\n export type ViewModel = IRecordLockingViewModel;\n}\n"],"names":["RecordLockingPresenter","createAbstraction"],"mappings":";AAiCO,MAAMA,yBACTC,kBAA2C"}
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ import type { IRecordLockingIdentity } from "../../../types.js";
3
+ interface ForceUnlockButtonProps {
4
+ canForceUnlock: boolean;
5
+ lockedBy: IRecordLockingIdentity | null;
6
+ entryTitle?: string;
7
+ onForceUnlock: () => Promise<boolean>;
8
+ onNavigateBack: () => void;
9
+ }
10
+ export declare const ForceUnlockButton: ({ canForceUnlock, lockedBy, entryTitle, onForceUnlock, onNavigateBack }: ForceUnlockButtonProps) => React.JSX.Element | null;
11
+ export {};
@@ -0,0 +1,37 @@
1
+ import react, { useCallback } from "react";
2
+ import { Alert, Button, Text } from "@webiny/admin-ui";
3
+ import { useConfirmationDialog, useSnackbar } from "@webiny/app-admin";
4
+ const ForceUnlockButton = ({ canForceUnlock, lockedBy, entryTitle, onForceUnlock, onNavigateBack })=>{
5
+ const { showSnackbar } = useSnackbar();
6
+ const { showConfirmation } = useConfirmationDialog({
7
+ title: "Force unlock the entry",
8
+ message: /*#__PURE__*/ react.createElement("div", null, /*#__PURE__*/ react.createElement(Alert, {
9
+ type: "warning",
10
+ title: "Warning",
11
+ className: "mb-md"
12
+ }, /*#__PURE__*/ react.createElement("strong", null, lockedBy?.displayName || "Unknown user"), " is currently editing this record.", /*#__PURE__*/ react.createElement("br", null), "If you force unlock it, they could potentially lose their changes."), /*#__PURE__*/ react.createElement(Text, null, "You are about to forcefully unlock the ", /*#__PURE__*/ react.createElement("strong", null, entryTitle || "entry"), ". Are you sure you want to continue?"))
13
+ });
14
+ const onClick = useCallback(()=>{
15
+ showConfirmation(async ()=>{
16
+ const success = await onForceUnlock();
17
+ if (!success) return void showSnackbar("Failed to force unlock the entry.");
18
+ onNavigateBack();
19
+ });
20
+ }, [
21
+ onForceUnlock,
22
+ onNavigateBack
23
+ ]);
24
+ if (!canForceUnlock) return null;
25
+ return /*#__PURE__*/ react.createElement("div", {
26
+ className: "mt-md"
27
+ }, /*#__PURE__*/ react.createElement(Text, {
28
+ as: "div",
29
+ className: "mb-md"
30
+ }, "Because you have full access to the system, you can force unlock the record."), /*#__PURE__*/ react.createElement(Button, {
31
+ onClick: onClick,
32
+ text: "Unlock and go back"
33
+ }));
34
+ };
35
+ export { ForceUnlockButton };
36
+
37
+ //# sourceMappingURL=ForceUnlockButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/entryLocking/components/ForceUnlockButton.js","sources":["../../../../src/presentation/entryLocking/components/ForceUnlockButton.tsx"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport { Alert, Button, Text } from \"@webiny/admin-ui\";\nimport { useConfirmationDialog, useSnackbar } from \"@webiny/app-admin\";\nimport type { IRecordLockingIdentity } from \"~/types.js\";\n\ninterface ForceUnlockButtonProps {\n canForceUnlock: boolean;\n lockedBy: IRecordLockingIdentity | null;\n entryTitle?: string;\n onForceUnlock: () => Promise<boolean>;\n onNavigateBack: () => void;\n}\n\nexport const ForceUnlockButton = ({\n canForceUnlock,\n lockedBy,\n entryTitle,\n onForceUnlock,\n onNavigateBack\n}: ForceUnlockButtonProps) => {\n const { showSnackbar } = useSnackbar();\n const { showConfirmation } = useConfirmationDialog({\n title: \"Force unlock the entry\",\n message: (\n <div>\n <Alert type=\"warning\" title=\"Warning\" className={\"mb-md\"}>\n <strong>{lockedBy?.displayName || \"Unknown user\"}</strong> is currently editing\n this record.\n <br />\n If you force unlock it, they could potentially lose their changes.\n </Alert>\n <Text>\n You are about to forcefully unlock the <strong>{entryTitle || \"entry\"}</strong>.\n Are you sure you want to continue?\n </Text>\n </div>\n )\n });\n\n const onClick = useCallback(() => {\n showConfirmation(async () => {\n const success = await onForceUnlock();\n if (!success) {\n showSnackbar(\"Failed to force unlock the entry.\");\n return;\n }\n onNavigateBack();\n });\n }, [onForceUnlock, onNavigateBack]);\n\n if (!canForceUnlock) {\n return null;\n }\n\n return (\n <div className=\"mt-md\">\n <Text as={\"div\"} className={\"mb-md\"}>\n Because you have full access to the system, you can force unlock the record.\n </Text>\n <Button onClick={onClick} text={\"Unlock and go back\"} />\n </div>\n );\n};\n"],"names":["ForceUnlockButton","canForceUnlock","lockedBy","entryTitle","onForceUnlock","onNavigateBack","showSnackbar","useSnackbar","showConfirmation","useConfirmationDialog","Alert","Text","onClick","useCallback","success","Button"],"mappings":";;;AAaO,MAAMA,oBAAoB,CAAC,EAC9BC,cAAc,EACdC,QAAQ,EACRC,UAAU,EACVC,aAAa,EACbC,cAAc,EACO;IACrB,MAAM,EAAEC,YAAY,EAAE,GAAGC;IACzB,MAAM,EAAEC,gBAAgB,EAAE,GAAGC,sBAAsB;QAC/C,OAAO;QACP,SAAS,WAAT,GACI,oBAAC,2BACG,oBAACC,OAAKA;YAAC,MAAK;YAAU,OAAM;YAAU,WAAW;yBAC7C,oBAAC,gBAAQR,UAAU,eAAe,iBAAwB,oDAE1D,oBAAC,aAAK,qFAGV,oBAACS,MAAIA,MAAC,yDACqC,oBAAC,gBAAQR,cAAc,UAAiB;IAK/F;IAEA,MAAMS,UAAUC,YAAY;QACxBL,iBAAiB;YACb,MAAMM,UAAU,MAAMV;YACtB,IAAI,CAACU,SAAS,YACVR,aAAa;YAGjBD;QACJ;IACJ,GAAG;QAACD;QAAeC;KAAe;IAElC,IAAI,CAACJ,gBACD,OAAO;IAGX,OAAO,WAAP,GACI,oBAAC;QAAI,WAAU;qBACX,oBAACU,MAAIA;QAAC,IAAI;QAAO,WAAW;OAAS,+FAGrC,oBAACI,QAAMA;QAAC,SAASH;QAAS,MAAM;;AAG5C"}
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import type { IRecordLockingViewModel } from "../abstractions.js";
3
+ interface LockedEntryOverlayProps {
4
+ vm: IRecordLockingViewModel;
5
+ entryTitle?: string;
6
+ onForceUnlock: () => Promise<boolean>;
7
+ onNavigateBack: () => void;
8
+ }
9
+ export declare const LockedEntryOverlay: ({ vm, entryTitle, onForceUnlock, onNavigateBack }: LockedEntryOverlayProps) => React.JSX.Element;
10
+ export {};
@@ -0,0 +1,52 @@
1
+ import react from "react";
2
+ import { ReactComponent } from "@webiny/icons/lock.svg";
3
+ import { Grid, Heading, Icon, Text } from "@webiny/admin-ui";
4
+ import { ForceUnlockButton } from "./ForceUnlockButton.js";
5
+ const LockedEntryOverlay = ({ vm, entryTitle, onForceUnlock, onNavigateBack })=>{
6
+ const title = entryTitle ? `Record (${entryTitle}) is locked!` : "Record is locked!";
7
+ if (!vm.lockRecord?.lockedBy) return /*#__PURE__*/ react.createElement(Wrapper, null, /*#__PURE__*/ react.createElement(Heading, {
8
+ level: 4,
9
+ className: "mb-sm"
10
+ }, title), /*#__PURE__*/ react.createElement(Text, null, "This record is locked, but the system cannot find the user that created the record lock. A force-unlock is required to regain editing capabilities for this record."), /*#__PURE__*/ react.createElement(ForceUnlockButton, {
11
+ canForceUnlock: vm.canForceUnlock,
12
+ lockedBy: null,
13
+ entryTitle: entryTitle,
14
+ onForceUnlock: onForceUnlock,
15
+ onNavigateBack: onNavigateBack
16
+ }));
17
+ return /*#__PURE__*/ react.createElement(Wrapper, null, /*#__PURE__*/ react.createElement(Heading, {
18
+ level: 4,
19
+ className: "mb-sm"
20
+ }, title), /*#__PURE__*/ react.createElement(Text, null, "It is locked because ", /*#__PURE__*/ react.createElement("strong", null, vm.lockedByUserName), " is currently editing this record. You can either contact the user and ask them to unlock the record, or you can wait for the lock to expire."), /*#__PURE__*/ react.createElement(ForceUnlockButton, {
21
+ canForceUnlock: vm.canForceUnlock,
22
+ lockedBy: vm.lockRecord.lockedBy,
23
+ entryTitle: entryTitle,
24
+ onForceUnlock: onForceUnlock,
25
+ onNavigateBack: onNavigateBack
26
+ }));
27
+ };
28
+ const Wrapper = ({ children })=>/*#__PURE__*/ react.createElement("div", {
29
+ className: "w-5/12 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50"
30
+ }, /*#__PURE__*/ react.createElement("div", {
31
+ className: "flex p-lg border-sm border-neutral-dimmed-darker rounded-3xl bg-neutral-base"
32
+ }, /*#__PURE__*/ react.createElement(Grid, null, /*#__PURE__*/ react.createElement(Grid.Column, {
33
+ span: 3
34
+ }, /*#__PURE__*/ react.createElement("div", {
35
+ className: "h-full flex items-center justify-center bg-neutral-dimmed rounded-md p-lg"
36
+ }, /*#__PURE__*/ react.createElement(Icon, {
37
+ style: {
38
+ width: "64px",
39
+ height: "64px"
40
+ },
41
+ icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
42
+ label: "Locked Record",
43
+ color: "accent",
44
+ size: "lg"
45
+ }))), /*#__PURE__*/ react.createElement(Grid.Column, {
46
+ span: 9
47
+ }, /*#__PURE__*/ react.createElement("div", {
48
+ className: "flex flex-col justify-center"
49
+ }, children)))));
50
+ export { LockedEntryOverlay };
51
+
52
+ //# sourceMappingURL=LockedEntryOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentation/entryLocking/components/LockedEntryOverlay.js","sources":["../../../../src/presentation/entryLocking/components/LockedEntryOverlay.tsx"],"sourcesContent":["import React from \"react\";\nimport { ReactComponent as LockIcon } from \"@webiny/icons/lock.svg\";\nimport { Grid, Heading, Icon, Text } from \"@webiny/admin-ui\";\nimport { ForceUnlockButton } from \"./ForceUnlockButton.js\";\nimport type { IRecordLockingViewModel } from \"../abstractions.js\";\n\ninterface LockedEntryOverlayProps {\n vm: IRecordLockingViewModel;\n entryTitle?: string;\n onForceUnlock: () => Promise<boolean>;\n onNavigateBack: () => void;\n}\n\nexport const LockedEntryOverlay = ({\n vm,\n entryTitle,\n onForceUnlock,\n onNavigateBack\n}: LockedEntryOverlayProps) => {\n const title = entryTitle ? `Record (${entryTitle}) is locked!` : \"Record is locked!\";\n\n if (!vm.lockRecord?.lockedBy) {\n return (\n <Wrapper>\n <Heading level={4} className={\"mb-sm\"}>\n {title}\n </Heading>\n <Text>\n This record is locked, but the system cannot find the user that created the\n record lock. A force-unlock is required to regain editing capabilities for this\n record.\n </Text>\n <ForceUnlockButton\n canForceUnlock={vm.canForceUnlock}\n lockedBy={null}\n entryTitle={entryTitle}\n onForceUnlock={onForceUnlock}\n onNavigateBack={onNavigateBack}\n />\n </Wrapper>\n );\n }\n\n return (\n <Wrapper>\n <Heading level={4} className={\"mb-sm\"}>\n {title}\n </Heading>\n <Text>\n It is locked because <strong>{vm.lockedByUserName}</strong> is currently editing\n this record. You can either contact the user and ask them to unlock the record, or\n you can wait for the lock to expire.\n </Text>\n <ForceUnlockButton\n canForceUnlock={vm.canForceUnlock}\n lockedBy={vm.lockRecord.lockedBy}\n entryTitle={entryTitle}\n onForceUnlock={onForceUnlock}\n onNavigateBack={onNavigateBack}\n />\n </Wrapper>\n );\n};\n\nconst Wrapper = ({ children }: { children: React.ReactNode }) => {\n return (\n <div className=\"w-5/12 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50\">\n <div\n className={\n \"flex p-lg border-sm border-neutral-dimmed-darker rounded-3xl bg-neutral-base\"\n }\n >\n <Grid>\n <Grid.Column span={3}>\n <div className=\"h-full flex items-center justify-center bg-neutral-dimmed rounded-md p-lg\">\n <Icon\n style={{ width: \"64px\", height: \"64px\" }}\n icon={<LockIcon />}\n label={\"Locked Record\"}\n color={\"accent\"}\n size={\"lg\"}\n />\n </div>\n </Grid.Column>\n <Grid.Column span={9}>\n <div className={\"flex flex-col justify-center\"}>{children}</div>\n </Grid.Column>\n </Grid>\n </div>\n </div>\n );\n};\n"],"names":["LockedEntryOverlay","vm","entryTitle","onForceUnlock","onNavigateBack","title","Wrapper","Heading","Text","ForceUnlockButton","children","Grid","Icon","LockIcon"],"mappings":";;;;AAaO,MAAMA,qBAAqB,CAAC,EAC/BC,EAAE,EACFC,UAAU,EACVC,aAAa,EACbC,cAAc,EACQ;IACtB,MAAMC,QAAQH,aAAa,CAAC,QAAQ,EAAEA,WAAW,YAAY,CAAC,GAAG;IAEjE,IAAI,CAACD,GAAG,UAAU,EAAE,UAChB,OAAO,WAAP,GACI,oBAACK,SAAOA,MAAAA,WAAAA,GACJ,oBAACC,SAAOA;QAAC,OAAO;QAAG,WAAW;OACzBF,QAAAA,WAAAA,GAEL,oBAACG,MAAIA,MAAC,sLAKN,oBAACC,mBAAiBA;QACd,gBAAgBR,GAAG,cAAc;QACjC,UAAU;QACV,YAAYC;QACZ,eAAeC;QACf,gBAAgBC;;IAMhC,OAAO,WAAP,GACI,oBAACE,SAAOA,MAAAA,WAAAA,GACJ,oBAACC,SAAOA;QAAC,OAAO;QAAG,WAAW;OACzBF,QAAAA,WAAAA,GAEL,oBAACG,MAAIA,MAAC,uCACmB,oBAAC,gBAAQP,GAAG,gBAAgB,GAAU,gKAI/D,oBAACQ,mBAAiBA;QACd,gBAAgBR,GAAG,cAAc;QACjC,UAAUA,GAAG,UAAU,CAAC,QAAQ;QAChC,YAAYC;QACZ,eAAeC;QACf,gBAAgBC;;AAIhC;AAEA,MAAME,UAAU,CAAC,EAAEI,QAAQ,EAAiC,GACjD,WAAP,GACI,oBAAC;QAAI,WAAU;qBACX,oBAAC;QACG,WACI;qBAGJ,oBAACC,MAAIA,MAAAA,WAAAA,GACD,oBAACA,KAAK,MAAM;QAAC,MAAM;qBACf,oBAAC;QAAI,WAAU;qBACX,oBAACC,MAAIA;QACD,OAAO;YAAE,OAAO;YAAQ,QAAQ;QAAO;QACvC,oBAAM,oBAACC,gBAAQA;QACf,OAAO;QACP,OAAO;QACP,MAAM;wBAIlB,oBAACF,KAAK,MAAM;QAAC,MAAM;qBACf,oBAAC;QAAI,WAAW;OAAiCD"}