@webiny/app-record-locking 6.4.12-beta.4 → 6.5.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.
- package/RecordLockingModule.d.ts +2 -0
- package/RecordLockingModule.js +74 -0
- package/RecordLockingModule.js.map +1 -0
- package/{components/SecurityPermissions.js → SecurityPermissions.js} +1 -1
- package/SecurityPermissions.js.map +1 -0
- package/features/acquireLock/AcquireLockGateway.d.ts +12 -0
- package/features/acquireLock/AcquireLockGateway.js +43 -0
- package/features/acquireLock/AcquireLockGateway.js.map +1 -0
- package/features/acquireLock/AcquireLockUseCase.d.ts +10 -0
- package/features/acquireLock/AcquireLockUseCase.js +18 -0
- package/features/acquireLock/AcquireLockUseCase.js.map +1 -0
- package/features/acquireLock/abstractions.d.ts +19 -0
- package/features/acquireLock/abstractions.js +6 -0
- package/features/acquireLock/abstractions.js.map +1 -0
- package/features/acquireLock/feature.d.ts +3 -0
- package/features/acquireLock/feature.js +19 -0
- package/features/acquireLock/feature.js.map +1 -0
- package/features/checkLockStatus/CheckLockStatusGateway.d.ts +12 -0
- package/features/checkLockStatus/CheckLockStatusGateway.js +43 -0
- package/features/checkLockStatus/CheckLockStatusGateway.js.map +1 -0
- package/features/checkLockStatus/CheckLockStatusUseCase.d.ts +10 -0
- package/features/checkLockStatus/CheckLockStatusUseCase.js +18 -0
- package/features/checkLockStatus/CheckLockStatusUseCase.js.map +1 -0
- package/features/checkLockStatus/abstractions.d.ts +19 -0
- package/features/checkLockStatus/abstractions.js +6 -0
- package/features/checkLockStatus/abstractions.js.map +1 -0
- package/features/checkLockStatus/feature.d.ts +3 -0
- package/features/checkLockStatus/feature.js +19 -0
- package/features/checkLockStatus/feature.js.map +1 -0
- package/features/feature.d.ts +1 -0
- package/features/feature.js +19 -0
- package/features/feature.js.map +1 -0
- package/features/forceUnlock/ForceUnlockGateway.d.ts +12 -0
- package/features/forceUnlock/ForceUnlockGateway.js +44 -0
- package/features/forceUnlock/ForceUnlockGateway.js.map +1 -0
- package/features/forceUnlock/ForceUnlockUseCase.d.ts +10 -0
- package/features/forceUnlock/ForceUnlockUseCase.js +18 -0
- package/features/forceUnlock/ForceUnlockUseCase.js.map +1 -0
- package/features/forceUnlock/abstractions.d.ts +19 -0
- package/features/forceUnlock/abstractions.js +6 -0
- package/features/forceUnlock/abstractions.js.map +1 -0
- package/features/forceUnlock/feature.d.ts +3 -0
- package/features/forceUnlock/feature.js +19 -0
- package/features/forceUnlock/feature.js.map +1 -0
- package/{domain/graphql/fields.js → features/graphqlFields.js} +1 -1
- package/features/graphqlFields.js.map +1 -0
- package/features/listLockRecords/ListLockRecordsGateway.d.ts +12 -0
- package/features/listLockRecords/ListLockRecordsGateway.js +48 -0
- package/features/listLockRecords/ListLockRecordsGateway.js.map +1 -0
- package/features/listLockRecords/ListLockRecordsUseCase.d.ts +10 -0
- package/features/listLockRecords/ListLockRecordsUseCase.js +18 -0
- package/features/listLockRecords/ListLockRecordsUseCase.js.map +1 -0
- package/features/listLockRecords/abstractions.d.ts +22 -0
- package/features/listLockRecords/abstractions.js +6 -0
- package/features/listLockRecords/abstractions.js.map +1 -0
- package/features/listLockRecords/feature.d.ts +3 -0
- package/features/listLockRecords/feature.js +19 -0
- package/features/listLockRecords/feature.js.map +1 -0
- package/features/permissions/abstractions.d.ts +1 -1
- package/features/permissions/abstractions.js +1 -1
- package/features/permissions/abstractions.js.map +1 -1
- package/features/permissions/feature.d.ts +1 -1
- package/features/permissions/feature.js +1 -1
- package/features/permissions/feature.js.map +1 -1
- package/features/releaseLock/ReleaseLockGateway.d.ts +12 -0
- package/features/releaseLock/ReleaseLockGateway.js +44 -0
- package/features/releaseLock/ReleaseLockGateway.js.map +1 -0
- package/features/releaseLock/ReleaseLockUseCase.d.ts +10 -0
- package/features/releaseLock/ReleaseLockUseCase.js +18 -0
- package/features/releaseLock/ReleaseLockUseCase.js.map +1 -0
- package/features/releaseLock/abstractions.d.ts +19 -0
- package/features/releaseLock/abstractions.js +6 -0
- package/features/releaseLock/abstractions.js.map +1 -0
- package/features/releaseLock/feature.d.ts +3 -0
- package/features/releaseLock/feature.js +19 -0
- package/features/releaseLock/feature.js.map +1 -0
- package/index.d.ts +0 -5
- package/index.js +12 -13
- package/index.js.map +1 -1
- package/package.json +13 -17
- package/permissions/permissionsSchema.js.map +1 -0
- package/presentation/entryLocking/ContentEntryFormPresenterDecorator.d.ts +23 -0
- package/presentation/entryLocking/ContentEntryFormPresenterDecorator.js +64 -0
- package/presentation/entryLocking/ContentEntryFormPresenterDecorator.js.map +1 -0
- package/presentation/entryLocking/RecordLockingPresenter.d.ts +32 -0
- package/presentation/entryLocking/RecordLockingPresenter.js +164 -0
- package/presentation/entryLocking/RecordLockingPresenter.js.map +1 -0
- package/presentation/entryLocking/SingleEntryContentDecorator.d.ts +2 -0
- package/presentation/entryLocking/SingleEntryContentDecorator.js +72 -0
- package/presentation/entryLocking/SingleEntryContentDecorator.js.map +1 -0
- package/presentation/entryLocking/SingleEntryPresenterDecorator.d.ts +15 -0
- package/presentation/entryLocking/SingleEntryPresenterDecorator.js +40 -0
- package/presentation/entryLocking/SingleEntryPresenterDecorator.js.map +1 -0
- package/presentation/entryLocking/abstractions.d.ts +26 -0
- package/presentation/entryLocking/abstractions.js +5 -0
- package/presentation/entryLocking/abstractions.js.map +1 -0
- package/presentation/entryLocking/components/ForceUnlockButton.d.ts +11 -0
- package/presentation/entryLocking/components/ForceUnlockButton.js +37 -0
- package/presentation/entryLocking/components/ForceUnlockButton.js.map +1 -0
- package/presentation/entryLocking/components/LockedEntryOverlay.d.ts +10 -0
- package/presentation/entryLocking/components/LockedEntryOverlay.js +52 -0
- package/presentation/entryLocking/components/LockedEntryOverlay.js.map +1 -0
- package/presentation/entryLocking/components/RecordLockingGuard.d.ts +12 -0
- package/presentation/entryLocking/components/RecordLockingGuard.js +74 -0
- package/presentation/entryLocking/components/RecordLockingGuard.js.map +1 -0
- package/presentation/entryLocking/feature.d.ts +3 -0
- package/presentation/entryLocking/feature.js +21 -0
- package/presentation/entryLocking/feature.js.map +1 -0
- package/presentation/listLocking/ContentEntriesPresenterDecorator.d.ts +24 -0
- package/presentation/listLocking/ContentEntriesPresenterDecorator.js +67 -0
- package/presentation/listLocking/ContentEntriesPresenterDecorator.js.map +1 -0
- package/presentation/listLocking/ListLockRecordsPresenter.d.ts +17 -0
- package/presentation/listLocking/ListLockRecordsPresenter.js +52 -0
- package/presentation/listLocking/ListLockRecordsPresenter.js.map +1 -0
- package/presentation/listLocking/abstractions.d.ts +16 -0
- package/presentation/listLocking/abstractions.js +5 -0
- package/presentation/listLocking/abstractions.js.map +1 -0
- package/presentation/listLocking/components/ListLockRecordsSync.d.ts +3 -0
- package/presentation/listLocking/components/ListLockRecordsSync.js +26 -0
- package/presentation/listLocking/components/ListLockRecordsSync.js.map +1 -0
- package/presentation/listLocking/components/LockIndicatorCell.d.ts +2 -0
- package/presentation/listLocking/components/LockIndicatorCell.js +39 -0
- package/presentation/listLocking/components/LockIndicatorCell.js.map +1 -0
- package/presentation/listLocking/feature.d.ts +3 -0
- package/presentation/listLocking/feature.js +19 -0
- package/presentation/listLocking/feature.js.map +1 -0
- package/types.d.ts +1 -62
- package/components/HeadlessCmsActionsAcoCell.d.ts +0 -2
- package/components/HeadlessCmsActionsAcoCell.js +0 -38
- package/components/HeadlessCmsActionsAcoCell.js.map +0 -1
- package/components/HeadlessCmsContentEntry/ContentEntryGuard.d.ts +0 -9
- package/components/HeadlessCmsContentEntry/ContentEntryGuard.js +0 -34
- package/components/HeadlessCmsContentEntry/ContentEntryGuard.js.map +0 -1
- package/components/HeadlessCmsContentEntry/ContentEntryLocker.d.ts +0 -18
- package/components/HeadlessCmsContentEntry/ContentEntryLocker.js +0 -80
- package/components/HeadlessCmsContentEntry/ContentEntryLocker.js.map +0 -1
- package/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.d.ts +0 -2
- package/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.js +0 -44
- package/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.js.map +0 -1
- package/components/HeadlessCmsContentEntry/index.d.ts +0 -1
- package/components/HeadlessCmsContentEntry/index.js +0 -1
- package/components/LockedRecord/LockedRecord.d.ts +0 -6
- package/components/LockedRecord/LockedRecord.js +0 -54
- package/components/LockedRecord/LockedRecord.js.map +0 -1
- package/components/LockedRecord/LockedRecordForceUnlock.d.ts +0 -9
- package/components/LockedRecord/LockedRecordForceUnlock.js +0 -57
- package/components/LockedRecord/LockedRecordForceUnlock.js.map +0 -1
- package/components/LockedRecord/index.d.ts +0 -1
- package/components/LockedRecord/index.js +0 -1
- package/components/RecordLockingProvider.d.ts +0 -7
- package/components/RecordLockingProvider.js +0 -111
- package/components/RecordLockingProvider.js.map +0 -1
- package/components/SecurityPermissions.js.map +0 -1
- package/components/decorators/UseContentEntriesListHookDecorator.d.ts +0 -1
- package/components/decorators/UseContentEntriesListHookDecorator.js +0 -23
- package/components/decorators/UseContentEntriesListHookDecorator.js.map +0 -1
- package/components/decorators/UseRecordsDecorator.d.ts +0 -8
- package/components/decorators/UseRecordsDecorator.js +0 -16
- package/components/decorators/UseRecordsDecorator.js.map +0 -1
- package/components/decorators/UseSaveEntryDecorator.d.ts +0 -1
- package/components/decorators/UseSaveEntryDecorator.js +0 -41
- package/components/decorators/UseSaveEntryDecorator.js.map +0 -1
- package/domain/RecordLocking.d.ts +0 -28
- package/domain/RecordLocking.js +0 -259
- package/domain/RecordLocking.js.map +0 -1
- package/domain/RecordLockingClient.d.ts +0 -12
- package/domain/RecordLockingClient.js +0 -20
- package/domain/RecordLockingClient.js.map +0 -1
- package/domain/RecordLockingGetLockRecord.d.ts +0 -11
- package/domain/RecordLockingGetLockRecord.js +0 -19
- package/domain/RecordLockingGetLockRecord.js.map +0 -1
- package/domain/RecordLockingGetLockedEntryLockRecord.d.ts +0 -11
- package/domain/RecordLockingGetLockedEntryLockRecord.js +0 -18
- package/domain/RecordLockingGetLockedEntryLockRecord.js.map +0 -1
- package/domain/RecordLockingIsEntryLocked.d.ts +0 -11
- package/domain/RecordLockingIsEntryLocked.js +0 -20
- package/domain/RecordLockingIsEntryLocked.js.map +0 -1
- package/domain/RecordLockingListLockRecords.d.ts +0 -12
- package/domain/RecordLockingListLockRecords.js +0 -25
- package/domain/RecordLockingListLockRecords.js.map +0 -1
- package/domain/RecordLockingLockEntry.d.ts +0 -11
- package/domain/RecordLockingLockEntry.js +0 -12
- package/domain/RecordLockingLockEntry.js.map +0 -1
- package/domain/RecordLockingUnlockEntry.d.ts +0 -11
- package/domain/RecordLockingUnlockEntry.js +0 -18
- package/domain/RecordLockingUnlockEntry.js.map +0 -1
- package/domain/RecordLockingUpdateEntryLock.d.ts +0 -11
- package/domain/RecordLockingUpdateEntryLock.js +0 -18
- package/domain/RecordLockingUpdateEntryLock.js.map +0 -1
- package/domain/abstractions/IRecordLocking.d.ts +0 -25
- package/domain/abstractions/IRecordLocking.js +0 -0
- package/domain/abstractions/IRecordLockingClient.d.ts +0 -6
- package/domain/abstractions/IRecordLockingClient.js +0 -0
- package/domain/abstractions/IRecordLockingGetLockRecord.d.ts +0 -12
- package/domain/abstractions/IRecordLockingGetLockRecord.js +0 -0
- package/domain/abstractions/IRecordLockingGetLockedEntryLockRecord.d.ts +0 -12
- package/domain/abstractions/IRecordLockingGetLockedEntryLockRecord.js +0 -0
- package/domain/abstractions/IRecordLockingIsEntryLocked.d.ts +0 -8
- package/domain/abstractions/IRecordLockingIsEntryLocked.js +0 -0
- package/domain/abstractions/IRecordLockingListLockRecords.d.ts +0 -19
- package/domain/abstractions/IRecordLockingListLockRecords.js +0 -0
- package/domain/abstractions/IRecordLockingLockEntry.d.ts +0 -12
- package/domain/abstractions/IRecordLockingLockEntry.js +0 -0
- package/domain/abstractions/IRecordLockingUnlockEntry.d.ts +0 -13
- package/domain/abstractions/IRecordLockingUnlockEntry.js +0 -0
- package/domain/abstractions/IRecordLockingUpdateEntryLock.d.ts +0 -12
- package/domain/abstractions/IRecordLockingUpdateEntryLock.js +0 -0
- package/domain/graphql/fields.js.map +0 -1
- package/domain/graphql/getLockRecord.d.ts +0 -12
- package/domain/graphql/getLockRecord.js +0 -19
- package/domain/graphql/getLockRecord.js.map +0 -1
- package/domain/graphql/getLockedEntryLockRecord.d.ts +0 -12
- package/domain/graphql/getLockedEntryLockRecord.js +0 -19
- package/domain/graphql/getLockedEntryLockRecord.js.map +0 -1
- package/domain/graphql/isEntryLocked.d.ts +0 -12
- package/domain/graphql/isEntryLocked.js +0 -17
- package/domain/graphql/isEntryLocked.js.map +0 -1
- package/domain/graphql/listLockRecords.d.ts +0 -17
- package/domain/graphql/listLockRecords.js +0 -25
- package/domain/graphql/listLockRecords.js.map +0 -1
- package/domain/graphql/lockEntry.d.ts +0 -12
- package/domain/graphql/lockEntry.js +0 -19
- package/domain/graphql/lockEntry.js.map +0 -1
- package/domain/graphql/unlockEntry.d.ts +0 -12
- package/domain/graphql/unlockEntry.js +0 -19
- package/domain/graphql/unlockEntry.js.map +0 -1
- package/domain/graphql/updateEntryLock.d.ts +0 -12
- package/domain/graphql/updateEntryLock.js +0 -19
- package/domain/graphql/updateEntryLock.js.map +0 -1
- package/domain/permissionsSchema.js.map +0 -1
- package/domain/utils/createRecordLockingClient.d.ts +0 -3
- package/domain/utils/createRecordLockingClient.js +0 -11
- package/domain/utils/createRecordLockingClient.js.map +0 -1
- package/domain/utils/createRecordLockingError.d.ts +0 -6
- package/domain/utils/createRecordLockingError.js +0 -15
- package/domain/utils/createRecordLockingError.js.map +0 -1
- package/hooks/index.d.ts +0 -2
- package/hooks/index.js +0 -2
- package/hooks/usePermission.d.ts +0 -3
- package/hooks/usePermission.js +0 -19
- package/hooks/usePermission.js.map +0 -1
- package/hooks/useRecordLocking.d.ts +0 -2
- package/hooks/useRecordLocking.js +0 -11
- package/hooks/useRecordLocking.js.map +0 -1
- package/utils/createCacheKey.d.ts +0 -3
- package/utils/createCacheKey.js +0 -14
- package/utils/createCacheKey.js.map +0 -1
- /package/{components/SecurityPermissions.d.ts → SecurityPermissions.d.ts} +0 -0
- /package/{domain/graphql/fields.d.ts → features/graphqlFields.d.ts} +0 -0
- /package/{domain → permissions}/permissionsSchema.d.ts +0 -0
- /package/{domain → permissions}/permissionsSchema.js +0 -0
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import react, { useEffect, useState } from "react";
|
|
2
|
-
import { useRecordLocking } from "../../hooks/index.js";
|
|
3
|
-
import { LockedRecord } from "../LockedRecord/index.js";
|
|
4
|
-
import { OverlayLoader } from "@webiny/admin-ui";
|
|
5
|
-
const ContentEntryGuard = (props)=>{
|
|
6
|
-
const { loading, entry, model, children } = props;
|
|
7
|
-
const { fetchLockedEntryLockRecord } = useRecordLocking();
|
|
8
|
-
const [locked, setLocked] = useState(void 0);
|
|
9
|
-
useEffect(()=>{
|
|
10
|
-
if (!entry.id || loading || void 0 !== locked) return;
|
|
11
|
-
(async ()=>{
|
|
12
|
-
const result = await fetchLockedEntryLockRecord({
|
|
13
|
-
id: entry.id,
|
|
14
|
-
$lockingType: model.modelId
|
|
15
|
-
});
|
|
16
|
-
setLocked(result);
|
|
17
|
-
})();
|
|
18
|
-
}, [
|
|
19
|
-
entry.id,
|
|
20
|
-
loading
|
|
21
|
-
]);
|
|
22
|
-
if (void 0 === locked) return /*#__PURE__*/ react.createElement("div", {
|
|
23
|
-
className: "h-screen w-screen fixed top-0 left-0 z-20"
|
|
24
|
-
}, /*#__PURE__*/ react.createElement(OverlayLoader, {
|
|
25
|
-
text: "Checking record status..."
|
|
26
|
-
}));
|
|
27
|
-
else if (locked) return /*#__PURE__*/ react.createElement(LockedRecord, {
|
|
28
|
-
record: locked
|
|
29
|
-
});
|
|
30
|
-
return children;
|
|
31
|
-
};
|
|
32
|
-
export { ContentEntryGuard };
|
|
33
|
-
|
|
34
|
-
//# sourceMappingURL=ContentEntryGuard.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/HeadlessCmsContentEntry/ContentEntryGuard.js","sources":["../../../src/components/HeadlessCmsContentEntry/ContentEntryGuard.tsx"],"sourcesContent":["import React, { useEffect, useState } from \"react\";\nimport { useRecordLocking } from \"~/hooks/index.js\";\nimport { LockedRecord } from \"../LockedRecord/index.js\";\nimport type { IRecordLockingLockRecord } from \"~/types.js\";\nimport type { CmsContentEntry, CmsModel } from \"@webiny/app-headless-cms/types.js\";\nimport { OverlayLoader } from \"@webiny/admin-ui\";\n\nexport interface IContentEntryGuardProps {\n loading: boolean;\n entry: CmsContentEntry;\n model: CmsModel;\n children: React.ReactElement;\n}\n\nexport const ContentEntryGuard = (props: IContentEntryGuardProps) => {\n const { loading, entry, model, children } = props;\n const { fetchLockedEntryLockRecord } = useRecordLocking();\n\n const [locked, setLocked] = useState<IRecordLockingLockRecord | null | undefined>(undefined);\n\n useEffect(() => {\n if (!entry.id || loading || locked !== undefined) {\n return;\n }\n (async () => {\n const result = await fetchLockedEntryLockRecord({\n id: entry.id,\n $lockingType: model.modelId\n });\n setLocked(result);\n })();\n }, [entry.id, loading]);\n\n if (locked === undefined) {\n return (\n <div className={\"h-screen w-screen fixed top-0 left-0 z-20\"}>\n <OverlayLoader text={\"Checking record status...\"} />\n </div>\n );\n } else if (locked) {\n return <LockedRecord record={locked} />;\n }\n\n return children;\n};\n"],"names":["ContentEntryGuard","props","loading","entry","model","children","fetchLockedEntryLockRecord","useRecordLocking","locked","setLocked","useState","undefined","useEffect","result","OverlayLoader","LockedRecord"],"mappings":";;;;AAcO,MAAMA,oBAAoB,CAACC;IAC9B,MAAM,EAAEC,OAAO,EAAEC,KAAK,EAAEC,KAAK,EAAEC,QAAQ,EAAE,GAAGJ;IAC5C,MAAM,EAAEK,0BAA0B,EAAE,GAAGC;IAEvC,MAAM,CAACC,QAAQC,UAAU,GAAGC,SAAsDC;IAElFC,UAAU;QACN,IAAI,CAACT,MAAM,EAAE,IAAID,WAAWM,AAAWG,WAAXH,QACxB;QAEH;YACG,MAAMK,SAAS,MAAMP,2BAA2B;gBAC5C,IAAIH,MAAM,EAAE;gBACZ,cAAcC,MAAM,OAAO;YAC/B;YACAK,UAAUI;QACd;IACJ,GAAG;QAACV,MAAM,EAAE;QAAED;KAAQ;IAEtB,IAAIM,AAAWG,WAAXH,QACA,OAAO,WAAP,GACI,oBAAC;QAAI,WAAW;qBACZ,oBAACM,eAAaA;QAAC,MAAM;;SAG1B,IAAIN,QACP,OAAO,WAAP,GAAO,oBAACO,cAAYA;QAAC,QAAQP;;IAGjC,OAAOH;AACX"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { IRecordLockingIdentity, IRecordLockingLockRecord } from "../../types.js";
|
|
3
|
-
import type { IncomingGenericData } from "@webiny/app-websockets";
|
|
4
|
-
import type { CmsContentEntry, CmsModel } from "@webiny/app-headless-cms/types.js";
|
|
5
|
-
export interface IContentEntryLockerProps {
|
|
6
|
-
entry: CmsContentEntry;
|
|
7
|
-
model: CmsModel;
|
|
8
|
-
onEntryUnlocked: () => void;
|
|
9
|
-
onDisablePrompt: () => void;
|
|
10
|
-
children: React.ReactElement;
|
|
11
|
-
}
|
|
12
|
-
export interface IKickOutWebsocketsMessage extends IncomingGenericData {
|
|
13
|
-
data: {
|
|
14
|
-
record: IRecordLockingLockRecord;
|
|
15
|
-
user: IRecordLockingIdentity;
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
export declare const ContentEntryLocker: ({ onEntryUnlocked, onDisablePrompt, entry, model, children }: IContentEntryLockerProps) => React.JSX.Element;
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import react, { useEffect, useRef } from "react";
|
|
2
|
-
import { useRecordLocking } from "../../hooks/index.js";
|
|
3
|
-
import { useWebsockets } from "@webiny/app-websockets";
|
|
4
|
-
import { parseIdentifier } from "@webiny/utils";
|
|
5
|
-
import { useDialogs } from "@webiny/app-admin";
|
|
6
|
-
const autoUpdateTimeout = 20;
|
|
7
|
-
const ContentEntryLocker = ({ onEntryUnlocked, onDisablePrompt, entry, model, children })=>{
|
|
8
|
-
const { updateEntryLock, removeEntryLock } = useRecordLocking();
|
|
9
|
-
const websockets = useWebsockets();
|
|
10
|
-
const { showDialog } = useDialogs();
|
|
11
|
-
const entryLockerTimeout = useRef(null);
|
|
12
|
-
useEffect(()=>{
|
|
13
|
-
if (!entry.id) return;
|
|
14
|
-
const { id: entryId } = parseIdentifier(entry.id);
|
|
15
|
-
let onMessageSub = websockets.onMessage(`recordLocking.entry.kickOut.${entryId}`, async (incoming)=>{
|
|
16
|
-
const { user } = incoming.data;
|
|
17
|
-
onDisablePrompt();
|
|
18
|
-
removeEntryLock({
|
|
19
|
-
id: entryId,
|
|
20
|
-
$lockingType: model.modelId
|
|
21
|
-
});
|
|
22
|
-
showDialog({
|
|
23
|
-
title: "Entry was forcefully unlocked!",
|
|
24
|
-
content: /*#__PURE__*/ react.createElement(react.Fragment, null, "The entry you were editing was forcefully unlocked by", " ", /*#__PURE__*/ react.createElement("strong", null, user.displayName || "Unknown user"), ". Unfortunately, this means you lost the unsaved changes."),
|
|
25
|
-
acceptLabel: "Ok",
|
|
26
|
-
onClose: void 0,
|
|
27
|
-
cancelLabel: null
|
|
28
|
-
});
|
|
29
|
-
onEntryUnlocked();
|
|
30
|
-
});
|
|
31
|
-
return ()=>{
|
|
32
|
-
onMessageSub.off();
|
|
33
|
-
onMessageSub = null;
|
|
34
|
-
};
|
|
35
|
-
}, [
|
|
36
|
-
entry.id,
|
|
37
|
-
onEntryUnlocked,
|
|
38
|
-
model.modelId
|
|
39
|
-
]);
|
|
40
|
-
useEffect(()=>{
|
|
41
|
-
if (!entry.id) return;
|
|
42
|
-
if (entryLockerTimeout.current) return;
|
|
43
|
-
const updateLock = async ()=>{
|
|
44
|
-
const result = await updateEntryLock({
|
|
45
|
-
id: entry.id,
|
|
46
|
-
$lockingType: model.modelId
|
|
47
|
-
});
|
|
48
|
-
if (result.error) {
|
|
49
|
-
showDialog({
|
|
50
|
-
title: "There was an error while updating the entry lock.",
|
|
51
|
-
content: result.error.message,
|
|
52
|
-
acceptLabel: "Ok",
|
|
53
|
-
onClose: void 0,
|
|
54
|
-
cancelLabel: null
|
|
55
|
-
});
|
|
56
|
-
onEntryUnlocked();
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
createTimeout();
|
|
60
|
-
};
|
|
61
|
-
const createTimeout = ()=>{
|
|
62
|
-
entryLockerTimeout.current = window.setTimeout(()=>{
|
|
63
|
-
updateLock();
|
|
64
|
-
}, 1000 * autoUpdateTimeout);
|
|
65
|
-
};
|
|
66
|
-
updateLock();
|
|
67
|
-
return ()=>{
|
|
68
|
-
if (!entryLockerTimeout.current) return;
|
|
69
|
-
clearTimeout(entryLockerTimeout.current);
|
|
70
|
-
entryLockerTimeout.current = null;
|
|
71
|
-
};
|
|
72
|
-
}, [
|
|
73
|
-
entry.id,
|
|
74
|
-
onEntryUnlocked
|
|
75
|
-
]);
|
|
76
|
-
return /*#__PURE__*/ react.createElement(react.Fragment, null, children);
|
|
77
|
-
};
|
|
78
|
-
export { ContentEntryLocker };
|
|
79
|
-
|
|
80
|
-
//# sourceMappingURL=ContentEntryLocker.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/HeadlessCmsContentEntry/ContentEntryLocker.js","sources":["../../../src/components/HeadlessCmsContentEntry/ContentEntryLocker.tsx"],"sourcesContent":["import React, { useEffect, useRef } from \"react\";\nimport { useRecordLocking } from \"~/hooks/index.js\";\nimport type { IRecordLockingIdentity, IRecordLockingLockRecord } from \"~/types.js\";\nimport type { IncomingGenericData } from \"@webiny/app-websockets\";\nimport { useWebsockets } from \"@webiny/app-websockets\";\nimport { parseIdentifier } from \"@webiny/utils\";\nimport { useDialogs } from \"@webiny/app-admin\";\nimport type { CmsContentEntry, CmsModel } from \"@webiny/app-headless-cms/types.js\";\n\nconst autoUpdateTimeout = 20;\n\nexport interface IContentEntryLockerProps {\n entry: CmsContentEntry;\n model: CmsModel;\n onEntryUnlocked: () => void;\n onDisablePrompt: () => void;\n children: React.ReactElement;\n}\n\nexport interface IKickOutWebsocketsMessage extends IncomingGenericData {\n data: {\n record: IRecordLockingLockRecord;\n user: IRecordLockingIdentity;\n };\n}\n\nexport const ContentEntryLocker = ({\n onEntryUnlocked,\n onDisablePrompt,\n entry,\n model,\n children\n}: IContentEntryLockerProps) => {\n const { updateEntryLock, removeEntryLock } = useRecordLocking();\n const websockets = useWebsockets();\n const { showDialog } = useDialogs();\n\n const entryLockerTimeout = useRef<number | null>(null);\n\n useEffect(() => {\n if (!entry.id) {\n return;\n }\n const { id: entryId } = parseIdentifier(entry.id);\n\n let onMessageSub = websockets.onMessage<IKickOutWebsocketsMessage>(\n `recordLocking.entry.kickOut.${entryId}`,\n async incoming => {\n const { user } = incoming.data;\n onDisablePrompt();\n removeEntryLock({\n id: entryId,\n $lockingType: model.modelId\n });\n showDialog({\n title: \"Entry was forcefully unlocked!\",\n content: (\n <>\n The entry you were editing was forcefully unlocked by{\" \"}\n <strong>{user.displayName || \"Unknown user\"}</strong>. Unfortunately,\n this means you lost the unsaved changes.\n </>\n ),\n acceptLabel: \"Ok\",\n onClose: undefined,\n cancelLabel: null\n });\n onEntryUnlocked();\n }\n );\n\n return () => {\n onMessageSub.off();\n /**\n * Lets null subscriptions, just in case it...\n */\n // @ts-expect-error\n onMessageSub = null;\n };\n }, [entry.id, onEntryUnlocked, model.modelId]);\n\n useEffect(() => {\n if (!entry.id) {\n return;\n }\n\n if (entryLockerTimeout.current) {\n return;\n }\n\n const updateLock = async () => {\n const result = await updateEntryLock({\n id: entry.id,\n $lockingType: model.modelId\n });\n if (result.error) {\n showDialog({\n title: \"There was an error while updating the entry lock.\",\n content: result.error.message,\n acceptLabel: \"Ok\",\n onClose: undefined,\n cancelLabel: null\n });\n onEntryUnlocked();\n return;\n }\n createTimeout();\n };\n\n const createTimeout = () => {\n entryLockerTimeout.current = window.setTimeout(() => {\n updateLock();\n }, autoUpdateTimeout * 1000);\n };\n\n updateLock();\n return () => {\n if (!entryLockerTimeout.current) {\n return;\n }\n clearTimeout(entryLockerTimeout.current);\n entryLockerTimeout.current = null;\n };\n }, [entry.id, onEntryUnlocked]);\n\n return <>{children}</>;\n};\n"],"names":["autoUpdateTimeout","ContentEntryLocker","onEntryUnlocked","onDisablePrompt","entry","model","children","updateEntryLock","removeEntryLock","useRecordLocking","websockets","useWebsockets","showDialog","useDialogs","entryLockerTimeout","useRef","useEffect","entryId","parseIdentifier","onMessageSub","incoming","user","undefined","updateLock","result","createTimeout","window","clearTimeout"],"mappings":";;;;;AASA,MAAMA,oBAAoB;AAiBnB,MAAMC,qBAAqB,CAAC,EAC/BC,eAAe,EACfC,eAAe,EACfC,KAAK,EACLC,KAAK,EACLC,QAAQ,EACe;IACvB,MAAM,EAAEC,eAAe,EAAEC,eAAe,EAAE,GAAGC;IAC7C,MAAMC,aAAaC;IACnB,MAAM,EAAEC,UAAU,EAAE,GAAGC;IAEvB,MAAMC,qBAAqBC,OAAsB;IAEjDC,UAAU;QACN,IAAI,CAACZ,MAAM,EAAE,EACT;QAEJ,MAAM,EAAE,IAAIa,OAAO,EAAE,GAAGC,gBAAgBd,MAAM,EAAE;QAEhD,IAAIe,eAAeT,WAAW,SAAS,CACnC,CAAC,4BAA4B,EAAEO,SAAS,EACxC,OAAMG;YACF,MAAM,EAAEC,IAAI,EAAE,GAAGD,SAAS,IAAI;YAC9BjB;YACAK,gBAAgB;gBACZ,IAAIS;gBACJ,cAAcZ,MAAM,OAAO;YAC/B;YACAO,WAAW;gBACP,OAAO;gBACP,SAAS,WAAT,GACI,0CAAE,yDACwD,mBACtD,oBAAC,gBAAQS,KAAK,WAAW,IAAI,iBAAwB;gBAI7D,aAAa;gBACb,SAASC;gBACT,aAAa;YACjB;YACApB;QACJ;QAGJ,OAAO;YACHiB,aAAa,GAAG;YAKhBA,eAAe;QACnB;IACJ,GAAG;QAACf,MAAM,EAAE;QAAEF;QAAiBG,MAAM,OAAO;KAAC;IAE7CW,UAAU;QACN,IAAI,CAACZ,MAAM,EAAE,EACT;QAGJ,IAAIU,mBAAmB,OAAO,EAC1B;QAGJ,MAAMS,aAAa;YACf,MAAMC,SAAS,MAAMjB,gBAAgB;gBACjC,IAAIH,MAAM,EAAE;gBACZ,cAAcC,MAAM,OAAO;YAC/B;YACA,IAAImB,OAAO,KAAK,EAAE;gBACdZ,WAAW;oBACP,OAAO;oBACP,SAASY,OAAO,KAAK,CAAC,OAAO;oBAC7B,aAAa;oBACb,SAASF;oBACT,aAAa;gBACjB;gBACApB;gBACA;YACJ;YACAuB;QACJ;QAEA,MAAMA,gBAAgB;YAClBX,mBAAmB,OAAO,GAAGY,OAAO,UAAU,CAAC;gBAC3CH;YACJ,GAAGvB,AAAoB,OAApBA;QACP;QAEAuB;QACA,OAAO;YACH,IAAI,CAACT,mBAAmB,OAAO,EAC3B;YAEJa,aAAab,mBAAmB,OAAO;YACvCA,mBAAmB,OAAO,GAAG;QACjC;IACJ,GAAG;QAACV,MAAM,EAAE;QAAEF;KAAgB;IAE9B,OAAO,WAAP,GAAO,0CAAGI;AACd"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import react from "react";
|
|
2
|
-
import { useRouter } from "@webiny/app";
|
|
3
|
-
import { ContentEntryEditorConfig, ContentEntryListConfig } from "@webiny/app-headless-cms";
|
|
4
|
-
import { ContentEntryGuard } from "./ContentEntryGuard.js";
|
|
5
|
-
import { ContentEntryLocker } from "./ContentEntryLocker.js";
|
|
6
|
-
const { ContentEntry: ContentEntry, SingletonContentEntry: SingletonContentEntry } = ContentEntryEditorConfig;
|
|
7
|
-
const ContentEntryDecorator = ContentEntry.createDecorator((Original)=>function() {
|
|
8
|
-
const router = useRouter();
|
|
9
|
-
const { entry, contentModel, loading } = ContentEntry.useContentEntry();
|
|
10
|
-
const { navigateTo } = ContentEntryListConfig.ContentEntries.useContentEntriesList();
|
|
11
|
-
if (!entry?.id) return /*#__PURE__*/ react.createElement(Original, null);
|
|
12
|
-
const props = {
|
|
13
|
-
entry,
|
|
14
|
-
model: contentModel
|
|
15
|
-
};
|
|
16
|
-
return /*#__PURE__*/ react.createElement(ContentEntryGuard, {
|
|
17
|
-
...props,
|
|
18
|
-
loading: loading
|
|
19
|
-
}, /*#__PURE__*/ react.createElement(ContentEntryLocker, {
|
|
20
|
-
...props,
|
|
21
|
-
onDisablePrompt: ()=>router.unblockTransition(),
|
|
22
|
-
onEntryUnlocked: navigateTo
|
|
23
|
-
}, /*#__PURE__*/ react.createElement(Original, null)));
|
|
24
|
-
});
|
|
25
|
-
const SingletonContentEntryDecorator = SingletonContentEntry.createDecorator((Original)=>function() {
|
|
26
|
-
const router = useRouter();
|
|
27
|
-
const { entry, contentModel, loading } = SingletonContentEntry.useSingletonContentEntry();
|
|
28
|
-
const props = {
|
|
29
|
-
entry,
|
|
30
|
-
model: contentModel
|
|
31
|
-
};
|
|
32
|
-
return /*#__PURE__*/ react.createElement(ContentEntryGuard, {
|
|
33
|
-
...props,
|
|
34
|
-
loading: loading
|
|
35
|
-
}, /*#__PURE__*/ react.createElement(ContentEntryLocker, {
|
|
36
|
-
...props,
|
|
37
|
-
onDisablePrompt: ()=>router.unblockTransition(),
|
|
38
|
-
onEntryUnlocked: ()=>{}
|
|
39
|
-
}, /*#__PURE__*/ react.createElement(Original, null)));
|
|
40
|
-
});
|
|
41
|
-
const HeadlessCmsContentEntry = ()=>/*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(ContentEntryDecorator, null), /*#__PURE__*/ react.createElement(SingletonContentEntryDecorator, null));
|
|
42
|
-
export { HeadlessCmsContentEntry };
|
|
43
|
-
|
|
44
|
-
//# sourceMappingURL=HeadlessCmsContentEntry.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.js","sources":["../../../src/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.tsx"],"sourcesContent":["import React from \"react\";\nimport { useRouter } from \"@webiny/app\";\nimport { ContentEntryEditorConfig, ContentEntryListConfig } from \"@webiny/app-headless-cms\";\nimport { ContentEntryGuard } from \"./ContentEntryGuard.js\";\nimport { ContentEntryLocker } from \"./ContentEntryLocker.js\";\n\nconst { ContentEntry, SingletonContentEntry } = ContentEntryEditorConfig;\n\nconst ContentEntryDecorator = ContentEntry.createDecorator(Original => {\n return function RecordLockingContentEntry() {\n const router = useRouter();\n const { entry, contentModel, loading } = ContentEntry.useContentEntry();\n const { navigateTo } = ContentEntryListConfig.ContentEntries.useContentEntriesList();\n /**\n * New entry does not have ID yet.\n */\n if (!entry?.id) {\n return <Original />;\n }\n /**\n * Continue with existing entry.\n */\n const props = { entry, model: contentModel };\n\n return (\n <ContentEntryGuard {...props} loading={loading}>\n <ContentEntryLocker\n {...props}\n onDisablePrompt={() => router.unblockTransition()}\n onEntryUnlocked={navigateTo}\n >\n <Original />\n </ContentEntryLocker>\n </ContentEntryGuard>\n );\n };\n});\n\nconst SingletonContentEntryDecorator = SingletonContentEntry.createDecorator(Original => {\n return function RecordLockingSingletonContentEntry() {\n const router = useRouter();\n const { entry, contentModel, loading } = SingletonContentEntry.useSingletonContentEntry();\n\n const props = { entry, model: contentModel };\n\n return (\n <ContentEntryGuard {...props} loading={loading}>\n <ContentEntryLocker\n {...props}\n onDisablePrompt={() => router.unblockTransition()}\n onEntryUnlocked={() => {\n // There's nowhere to go, since singleton entry doesn't have a list view.\n }}\n >\n <Original />\n </ContentEntryLocker>\n </ContentEntryGuard>\n );\n };\n});\n\nexport const HeadlessCmsContentEntry = () => {\n return (\n <>\n <ContentEntryDecorator />\n <SingletonContentEntryDecorator />\n </>\n );\n};\n"],"names":["ContentEntry","SingletonContentEntry","ContentEntryEditorConfig","ContentEntryDecorator","Original","router","useRouter","entry","contentModel","loading","navigateTo","ContentEntryListConfig","props","ContentEntryGuard","ContentEntryLocker","SingletonContentEntryDecorator","HeadlessCmsContentEntry"],"mappings":";;;;;AAMA,MAAM,EAAEA,cAAAA,YAAY,EAAEC,uBAAAA,qBAAqB,EAAE,GAAGC;AAEhD,MAAMC,wBAAwBH,aAAa,eAAe,CAACI,CAAAA,WAChD;QACH,MAAMC,SAASC;QACf,MAAM,EAAEC,KAAK,EAAEC,YAAY,EAAEC,OAAO,EAAE,GAAGT,aAAa,eAAe;QACrE,MAAM,EAAEU,UAAU,EAAE,GAAGC,uBAAuB,cAAc,CAAC,qBAAqB;QAIlF,IAAI,CAACJ,OAAO,IACR,OAAO,WAAP,GAAO,oBAACH,UAAAA;QAKZ,MAAMQ,QAAQ;YAAEL;YAAO,OAAOC;QAAa;QAE3C,OAAO,WAAP,GACI,oBAACK,mBAAiBA;YAAE,GAAGD,KAAK;YAAE,SAASH;yBACnC,oBAACK,oBAAkBA;YACd,GAAGF,KAAK;YACT,iBAAiB,IAAMP,OAAO,iBAAiB;YAC/C,iBAAiBK;yBAEjB,oBAACN,UAAAA;IAIjB;AAGJ,MAAMW,iCAAiCd,sBAAsB,eAAe,CAACG,CAAAA,WAClE;QACH,MAAMC,SAASC;QACf,MAAM,EAAEC,KAAK,EAAEC,YAAY,EAAEC,OAAO,EAAE,GAAGR,sBAAsB,wBAAwB;QAEvF,MAAMW,QAAQ;YAAEL;YAAO,OAAOC;QAAa;QAE3C,OAAO,WAAP,GACI,oBAACK,mBAAiBA;YAAE,GAAGD,KAAK;YAAE,SAASH;yBACnC,oBAACK,oBAAkBA;YACd,GAAGF,KAAK;YACT,iBAAiB,IAAMP,OAAO,iBAAiB;YAC/C,iBAAiB,KAEjB;yBAEA,oBAACD,UAAAA;IAIjB;AAGG,MAAMY,0BAA0B,IAC5B,WAAP,GACI,wDACI,oBAACb,uBAAqBA,OAAAA,WAAAA,GACtB,oBAACY,gCAA8BA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./HeadlessCmsContentEntry.js";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./HeadlessCmsContentEntry.js";
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { IRecordLockingLockRecord } from "../../types.js";
|
|
3
|
-
export interface ILockedRecordProps {
|
|
4
|
-
record: IRecordLockingLockRecord;
|
|
5
|
-
}
|
|
6
|
-
export declare const LockedRecord: ({ record: lockRecordEntry }: ILockedRecordProps) => React.JSX.Element;
|
|
@@ -1,54 +0,0 @@
|
|
|
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 { useRecordLocking } from "../../hooks/index.js";
|
|
5
|
-
import { useContentEntry } from "@webiny/app-headless-cms";
|
|
6
|
-
import { LockedRecordForceUnlock } from "./LockedRecordForceUnlock.js";
|
|
7
|
-
const Wrapper = ({ children })=>/*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement("div", {
|
|
8
|
-
className: "w-5/12 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50"
|
|
9
|
-
}, /*#__PURE__*/ react.createElement("div", {
|
|
10
|
-
className: "flex p-lg border-sm border-neutral-dimmed-darker rounded-3xl bg-neutral-base"
|
|
11
|
-
}, /*#__PURE__*/ react.createElement(Grid, null, /*#__PURE__*/ react.createElement(Grid.Column, {
|
|
12
|
-
span: 3
|
|
13
|
-
}, /*#__PURE__*/ react.createElement("div", {
|
|
14
|
-
className: "h-full flex items-center justify-center bg-neutral-dimmed rounded-md p-lg"
|
|
15
|
-
}, /*#__PURE__*/ react.createElement(Icon, {
|
|
16
|
-
style: {
|
|
17
|
-
width: "64px",
|
|
18
|
-
height: "64px"
|
|
19
|
-
},
|
|
20
|
-
icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
|
|
21
|
-
label: "Locked Record",
|
|
22
|
-
color: "accent",
|
|
23
|
-
size: "lg"
|
|
24
|
-
}))), /*#__PURE__*/ react.createElement(Grid.Column, {
|
|
25
|
-
span: 9
|
|
26
|
-
}, /*#__PURE__*/ react.createElement("div", {
|
|
27
|
-
className: "flex flex-col justify-center"
|
|
28
|
-
}, children))))));
|
|
29
|
-
const Title = ()=>{
|
|
30
|
-
const { entry } = useContentEntry();
|
|
31
|
-
return /*#__PURE__*/ react.createElement(Heading, {
|
|
32
|
-
level: 4,
|
|
33
|
-
className: "mb-sm"
|
|
34
|
-
}, "Record (", entry.meta.title, ") is locked!");
|
|
35
|
-
};
|
|
36
|
-
const LockedRecord = ({ record: lockRecordEntry })=>{
|
|
37
|
-
const { getLockRecordEntry } = useRecordLocking();
|
|
38
|
-
const record = getLockRecordEntry(lockRecordEntry.id);
|
|
39
|
-
if (!record) return /*#__PURE__*/ react.createElement(Wrapper, null, /*#__PURE__*/ react.createElement(Text, null, "Could not find the lock record. Please refresh the Admin UI."));
|
|
40
|
-
else if (!lockRecordEntry?.lockedBy) return /*#__PURE__*/ react.createElement(Wrapper, null, /*#__PURE__*/ react.createElement(Title, null), /*#__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(LockedRecordForceUnlock, {
|
|
41
|
-
id: lockRecordEntry.id,
|
|
42
|
-
type: record.$lockingType,
|
|
43
|
-
title: record.meta?.title
|
|
44
|
-
}));
|
|
45
|
-
return /*#__PURE__*/ react.createElement(Wrapper, null, /*#__PURE__*/ react.createElement(Title, null), /*#__PURE__*/ react.createElement(Text, null, "It is locked because ", /*#__PURE__*/ react.createElement("strong", null, lockRecordEntry.lockedBy.displayName), " 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(LockedRecordForceUnlock, {
|
|
46
|
-
id: lockRecordEntry.id,
|
|
47
|
-
type: record.$lockingType,
|
|
48
|
-
lockedBy: lockRecordEntry.lockedBy,
|
|
49
|
-
title: record.meta?.title
|
|
50
|
-
}));
|
|
51
|
-
};
|
|
52
|
-
export { LockedRecord };
|
|
53
|
-
|
|
54
|
-
//# sourceMappingURL=LockedRecord.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/LockedRecord/LockedRecord.js","sources":["../../../src/components/LockedRecord/LockedRecord.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 { useRecordLocking } from \"~/hooks/index.js\";\nimport { useContentEntry } from \"@webiny/app-headless-cms\";\nimport { LockedRecordForceUnlock } from \"./LockedRecordForceUnlock.js\";\nimport type { IRecordLockingLockRecord } from \"~/types.js\";\n\ninterface IWrapperProps {\n children: React.ReactNode;\n}\n\nconst Wrapper = ({ children }: IWrapperProps) => {\n return (\n <>\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={{\n width: \"64px\",\n height: \"64px\"\n }}\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 {/*<div className=\"absolute inset-0 bg-neutral-dark/50 z-45\"></div>*/}\n </>\n );\n};\n\nconst Title = () => {\n const { entry } = useContentEntry();\n return (\n <Heading level={4} className={\"mb-sm\"}>\n Record ({entry.meta.title}) is locked!\n </Heading>\n );\n};\n\nexport interface ILockedRecordProps {\n record: IRecordLockingLockRecord;\n}\n\nexport const LockedRecord = ({ record: lockRecordEntry }: ILockedRecordProps) => {\n const { getLockRecordEntry } = useRecordLocking();\n\n const record = getLockRecordEntry(lockRecordEntry.id);\n\n if (!record) {\n return (\n <Wrapper>\n <Text>Could not find the lock record. Please refresh the Admin UI.</Text>\n </Wrapper>\n );\n } else if (!lockRecordEntry?.lockedBy) {\n return (\n <Wrapper>\n <Title />\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 <LockedRecordForceUnlock\n id={lockRecordEntry.id}\n type={record.$lockingType}\n title={record.meta?.title}\n />\n </Wrapper>\n );\n }\n return (\n <Wrapper>\n <Title />\n <Text>\n It is locked because <strong>{lockRecordEntry.lockedBy.displayName}</strong> is\n currently editing this record. You can either contact the user and ask them to\n unlock the record, or you can wait for the lock to expire.\n </Text>\n <LockedRecordForceUnlock\n id={lockRecordEntry.id}\n type={record.$lockingType}\n lockedBy={lockRecordEntry.lockedBy}\n title={record.meta?.title}\n />\n </Wrapper>\n );\n};\n"],"names":["Wrapper","children","Grid","Icon","LockIcon","Title","entry","useContentEntry","Heading","LockedRecord","lockRecordEntry","getLockRecordEntry","useRecordLocking","record","Text","LockedRecordForceUnlock"],"mappings":";;;;;;AAYA,MAAMA,UAAU,CAAC,EAAEC,QAAQ,EAAiB,GACjC,WAAP,GACI,wDACI,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;YACH,OAAO;YACP,QAAQ;QACZ;QACA,oBAAM,oBAACC,gBAAQA;QACf,OAAO;QACP,OAAO;QACP,MAAM;wBAIlB,oBAACF,KAAK,MAAM;QAAC,MAAM;qBACf,oBAAC;QAAI,WAAW;OAAiCD;AAU7E,MAAMI,QAAQ;IACV,MAAM,EAAEC,KAAK,EAAE,GAAGC;IAClB,OAAO,WAAP,GACI,oBAACC,SAAOA;QAAC,OAAO;QAAG,WAAW;OAAS,YAC1BF,MAAM,IAAI,CAAC,KAAK,EAAC;AAGtC;AAMO,MAAMG,eAAe,CAAC,EAAE,QAAQC,eAAe,EAAsB;IACxE,MAAM,EAAEC,kBAAkB,EAAE,GAAGC;IAE/B,MAAMC,SAASF,mBAAmBD,gBAAgB,EAAE;IAEpD,IAAI,CAACG,QACD,OAAO,WAAP,GACI,oBAACb,SAAOA,MAAAA,WAAAA,GACJ,oBAACc,MAAIA,MAAC;SAGX,IAAI,CAACJ,iBAAiB,UACzB,OAAO,WAAP,GACI,oBAACV,SAAOA,MAAAA,WAAAA,GACJ,oBAACK,OAAKA,OAAAA,WAAAA,GACN,oBAACS,MAAIA,MAAC,sLAKN,oBAACC,yBAAuBA;QACpB,IAAIL,gBAAgB,EAAE;QACtB,MAAMG,OAAO,YAAY;QACzB,OAAOA,OAAO,IAAI,EAAE;;IAKpC,OAAO,WAAP,GACI,oBAACb,SAAOA,MAAAA,WAAAA,GACJ,oBAACK,OAAKA,OAAAA,WAAAA,GACN,oBAACS,MAAIA,MAAC,uCACmB,oBAAC,gBAAQJ,gBAAgB,QAAQ,CAAC,WAAW,GAAU,gKAIhF,oBAACK,yBAAuBA;QACpB,IAAIL,gBAAgB,EAAE;QACtB,MAAMG,OAAO,YAAY;QACzB,UAAUH,gBAAgB,QAAQ;QAClC,OAAOG,OAAO,IAAI,EAAE;;AAIpC"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { IRecordLockingIdentity } from "../../types.js";
|
|
3
|
-
export interface ILockedRecordForceUnlockProps {
|
|
4
|
-
id: string;
|
|
5
|
-
type: string;
|
|
6
|
-
title: string;
|
|
7
|
-
lockedBy?: IRecordLockingIdentity;
|
|
8
|
-
}
|
|
9
|
-
export declare const LockedRecordForceUnlock: (props: ILockedRecordForceUnlockProps) => React.JSX.Element | null;
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import react, { useCallback, useEffect, useState } from "react";
|
|
2
|
-
import { Alert, Button, Text } from "@webiny/admin-ui";
|
|
3
|
-
import { useConfirmationDialog, useSnackbar } from "@webiny/app-admin";
|
|
4
|
-
import { useContentEntriesList } from "@webiny/app-headless-cms";
|
|
5
|
-
import { usePermission, useRecordLocking } from "../../hooks/index.js";
|
|
6
|
-
const ErrorMessage = (props)=>{
|
|
7
|
-
const { title, lockedBy } = props;
|
|
8
|
-
return /*#__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, title), " entry. Are you sure you want to continue?"));
|
|
13
|
-
};
|
|
14
|
-
const LockedRecordForceUnlock = (props)=>{
|
|
15
|
-
const { unlockEntryForce } = useRecordLocking();
|
|
16
|
-
const { navigateTo } = useContentEntriesList();
|
|
17
|
-
const { showConfirmation: showForceUnlockConfirmation } = useConfirmationDialog({
|
|
18
|
-
title: "Force unlock the entry",
|
|
19
|
-
message: /*#__PURE__*/ react.createElement(ErrorMessage, props)
|
|
20
|
-
});
|
|
21
|
-
const { showSnackbar } = useSnackbar();
|
|
22
|
-
const [error, setError] = useState();
|
|
23
|
-
useEffect(()=>{
|
|
24
|
-
if (!error?.message) return;
|
|
25
|
-
console.error(error);
|
|
26
|
-
showSnackbar(error.message);
|
|
27
|
-
}, [
|
|
28
|
-
error?.message
|
|
29
|
-
]);
|
|
30
|
-
const onClick = useCallback(()=>{
|
|
31
|
-
showForceUnlockConfirmation(async ()=>{
|
|
32
|
-
const result = await unlockEntryForce({
|
|
33
|
-
id: props.id,
|
|
34
|
-
$lockingType: props.type
|
|
35
|
-
});
|
|
36
|
-
if (!result.error) return void navigateTo();
|
|
37
|
-
setError(result.error);
|
|
38
|
-
});
|
|
39
|
-
}, [
|
|
40
|
-
props.id,
|
|
41
|
-
navigateTo
|
|
42
|
-
]);
|
|
43
|
-
const { canForceUnlock } = usePermission();
|
|
44
|
-
if (!canForceUnlock) return null;
|
|
45
|
-
return /*#__PURE__*/ react.createElement("div", {
|
|
46
|
-
className: "mt-md"
|
|
47
|
-
}, /*#__PURE__*/ react.createElement(Text, {
|
|
48
|
-
as: "div",
|
|
49
|
-
className: "mb-md"
|
|
50
|
-
}, "Because you have a full access to the system, you can force unlock the record."), /*#__PURE__*/ react.createElement(Button, {
|
|
51
|
-
onClick: onClick,
|
|
52
|
-
text: "Unlock and go back"
|
|
53
|
-
}));
|
|
54
|
-
};
|
|
55
|
-
export { LockedRecordForceUnlock };
|
|
56
|
-
|
|
57
|
-
//# sourceMappingURL=LockedRecordForceUnlock.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/LockedRecord/LockedRecordForceUnlock.js","sources":["../../../src/components/LockedRecord/LockedRecordForceUnlock.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useState } from \"react\";\nimport { Alert, Button, Text } from \"@webiny/admin-ui\";\nimport type { IRecordLockingError, IRecordLockingIdentity } from \"~/types.js\";\nimport { useConfirmationDialog, useSnackbar } from \"@webiny/app-admin\";\nimport { useContentEntriesList } from \"@webiny/app-headless-cms\";\nimport { useRecordLocking, usePermission } from \"~/hooks/index.js\";\n\nexport interface ILockedRecordForceUnlockProps {\n id: string;\n type: string;\n title: string;\n lockedBy?: IRecordLockingIdentity;\n}\n\nconst ErrorMessage = (props: ILockedRecordForceUnlockProps) => {\n const { title, lockedBy } = props;\n return (\n <div>\n <Alert type=\"warning\" title=\"Warning\" className={\"mb-md\"}>\n <strong>{lockedBy?.displayName || \"Unknown user\"}</strong> is currently editing this\n record.\n <br /> If you force unlock it, they could potentially lose their changes.\n </Alert>\n\n <Text>\n You are about to forcefully unlock the <strong>{title}</strong> entry. Are you sure\n you want to continue?\n </Text>\n </div>\n );\n};\n\nexport const LockedRecordForceUnlock = (props: ILockedRecordForceUnlockProps) => {\n const { unlockEntryForce } = useRecordLocking();\n\n const { navigateTo } = useContentEntriesList();\n const { showConfirmation: showForceUnlockConfirmation } = useConfirmationDialog({\n title: \"Force unlock the entry\",\n message: <ErrorMessage {...props} />\n });\n const { showSnackbar } = useSnackbar();\n\n const [error, setError] = useState<IRecordLockingError>();\n\n useEffect(() => {\n if (!error?.message) {\n return;\n }\n console.error(error);\n showSnackbar(error.message);\n }, [error?.message]);\n\n const onClick = useCallback(() => {\n showForceUnlockConfirmation(async () => {\n const result = await unlockEntryForce({\n id: props.id,\n $lockingType: props.type\n });\n if (!result.error) {\n navigateTo();\n return;\n }\n setError(result.error);\n });\n }, [props.id, navigateTo]);\n\n const { canForceUnlock } = usePermission();\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 a 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":["ErrorMessage","props","title","lockedBy","Alert","Text","LockedRecordForceUnlock","unlockEntryForce","useRecordLocking","navigateTo","useContentEntriesList","showForceUnlockConfirmation","useConfirmationDialog","showSnackbar","useSnackbar","error","setError","useState","useEffect","console","onClick","useCallback","result","canForceUnlock","usePermission","Button"],"mappings":";;;;;AAcA,MAAMA,eAAe,CAACC;IAClB,MAAM,EAAEC,KAAK,EAAEC,QAAQ,EAAE,GAAGF;IAC5B,OAAO,WAAP,GACI,oBAAC,2BACG,oBAACG,OAAKA;QAAC,MAAK;QAAU,OAAM;QAAU,WAAW;qBAC7C,oBAAC,gBAAQD,UAAU,eAAe,iBAAwB,oDAE1D,oBAAC,aAAK,sFAGV,oBAACE,MAAIA,MAAC,yDACqC,oBAAC,gBAAQH,QAAe;AAK/E;AAEO,MAAMI,0BAA0B,CAACL;IACpC,MAAM,EAAEM,gBAAgB,EAAE,GAAGC;IAE7B,MAAM,EAAEC,UAAU,EAAE,GAAGC;IACvB,MAAM,EAAE,kBAAkBC,2BAA2B,EAAE,GAAGC,sBAAsB;QAC5E,OAAO;QACP,SAAS,WAAT,GAAS,oBAACZ,cAAiBC;IAC/B;IACA,MAAM,EAAEY,YAAY,EAAE,GAAGC;IAEzB,MAAM,CAACC,OAAOC,SAAS,GAAGC;IAE1BC,UAAU;QACN,IAAI,CAACH,OAAO,SACR;QAEJI,QAAQ,KAAK,CAACJ;QACdF,aAAaE,MAAM,OAAO;IAC9B,GAAG;QAACA,OAAO;KAAQ;IAEnB,MAAMK,UAAUC,YAAY;QACxBV,4BAA4B;YACxB,MAAMW,SAAS,MAAMf,iBAAiB;gBAClC,IAAIN,MAAM,EAAE;gBACZ,cAAcA,MAAM,IAAI;YAC5B;YACA,IAAI,CAACqB,OAAO,KAAK,EAAE,YACfb;YAGJO,SAASM,OAAO,KAAK;QACzB;IACJ,GAAG;QAACrB,MAAM,EAAE;QAAEQ;KAAW;IAEzB,MAAM,EAAEc,cAAc,EAAE,GAAGC;IAC3B,IAAI,CAACD,gBACD,OAAO;IAGX,OAAO,WAAP,GACI,oBAAC;QAAI,WAAU;qBACX,oBAAClB,MAAIA;QAAC,IAAI;QAAO,WAAW;OAAS,iGAGrC,oBAACoB,QAAMA;QAAC,SAASL;QAAS,MAAM;;AAG5C"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./LockedRecord.js";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./LockedRecord.js";
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { IPossiblyRecordLockingRecord, IRecordLockingContext } from "../types.js";
|
|
3
|
-
export interface IRecordLockingProviderProps {
|
|
4
|
-
children: React.ReactNode;
|
|
5
|
-
}
|
|
6
|
-
export declare const RecordLockingContext: React.Context<IRecordLockingContext<IPossiblyRecordLockingRecord>>;
|
|
7
|
-
export declare const RecordLockingProvider: (props: IRecordLockingProviderProps) => React.JSX.Element;
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import react, { useCallback, useMemo, useState } from "react";
|
|
2
|
-
import { useApolloClient } from "@apollo/react-hooks";
|
|
3
|
-
import { createRecordLocking } from "../domain/RecordLocking.js";
|
|
4
|
-
import { useStateIfMounted } from "@webiny/app-admin";
|
|
5
|
-
const RecordLockingContext = /*#__PURE__*/ react.createContext({});
|
|
6
|
-
const isSameArray = (existingRecords, newRecords)=>{
|
|
7
|
-
if (existingRecords.length !== newRecords.length) return false;
|
|
8
|
-
return existingRecords.every((record, index)=>{
|
|
9
|
-
const newRecord = newRecords[index];
|
|
10
|
-
if (!newRecord) return false;
|
|
11
|
-
return newRecord.id === record.id && newRecord.savedOn === record.savedOn;
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
|
-
const getData = (records)=>records.map((record)=>({
|
|
15
|
-
id: record.id,
|
|
16
|
-
savedOn: record.savedOn
|
|
17
|
-
}));
|
|
18
|
-
const RecordLockingProvider = (props)=>{
|
|
19
|
-
const client = useApolloClient();
|
|
20
|
-
const [loading, setLoading] = useState(false);
|
|
21
|
-
const recordLocking = useMemo(()=>createRecordLocking({
|
|
22
|
-
client,
|
|
23
|
-
setLoading
|
|
24
|
-
}), []);
|
|
25
|
-
const [error, setError] = useStateIfMounted(null);
|
|
26
|
-
const [records, setRecords] = useStateIfMounted([]);
|
|
27
|
-
const setRecordsIfNeeded = useCallback((newRecords)=>{
|
|
28
|
-
const sameArray = isSameArray(getData(records), getData(newRecords));
|
|
29
|
-
if (sameArray) return;
|
|
30
|
-
setRecords(newRecords);
|
|
31
|
-
}, [
|
|
32
|
-
records
|
|
33
|
-
]);
|
|
34
|
-
const value = {
|
|
35
|
-
async updateEntryLock (params) {
|
|
36
|
-
const result = await recordLocking.updateEntryLock(params);
|
|
37
|
-
if (result.error) {
|
|
38
|
-
setError(result.error);
|
|
39
|
-
return result;
|
|
40
|
-
}
|
|
41
|
-
const target = result.data;
|
|
42
|
-
if (!target?.id) {
|
|
43
|
-
const error = {
|
|
44
|
-
message: "No data returned from server.",
|
|
45
|
-
code: "NO_DATA"
|
|
46
|
-
};
|
|
47
|
-
setError(error);
|
|
48
|
-
return {
|
|
49
|
-
error,
|
|
50
|
-
data: null
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
setRecords((prev)=>prev.map((item)=>{
|
|
54
|
-
if (item.entryId === target.id) return {
|
|
55
|
-
...item,
|
|
56
|
-
$locked: result.data
|
|
57
|
-
};
|
|
58
|
-
return item;
|
|
59
|
-
}));
|
|
60
|
-
return result;
|
|
61
|
-
},
|
|
62
|
-
async unlockEntry (params) {
|
|
63
|
-
return await recordLocking.unlockEntry(params);
|
|
64
|
-
},
|
|
65
|
-
async unlockEntryForce (params) {
|
|
66
|
-
return await recordLocking.unlockEntry(params, true);
|
|
67
|
-
},
|
|
68
|
-
isLockExpired (input) {
|
|
69
|
-
return recordLocking.isLockExpired(input);
|
|
70
|
-
},
|
|
71
|
-
isRecordLocked (record) {
|
|
72
|
-
if (!record) return false;
|
|
73
|
-
return recordLocking.isRecordLocked(record);
|
|
74
|
-
},
|
|
75
|
-
getLockRecordEntry (id) {
|
|
76
|
-
return recordLocking.getLockRecordEntry(id);
|
|
77
|
-
},
|
|
78
|
-
removeEntryLock (params) {
|
|
79
|
-
return recordLocking.removeEntryLock(params);
|
|
80
|
-
},
|
|
81
|
-
async fetchLockRecord (params) {
|
|
82
|
-
try {
|
|
83
|
-
return await recordLocking.fetchLockRecord(params);
|
|
84
|
-
} catch (ex) {
|
|
85
|
-
return {
|
|
86
|
-
data: null,
|
|
87
|
-
error: ex
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
async fetchLockedEntryLockRecord (params) {
|
|
92
|
-
return recordLocking.fetchLockedEntryLockRecord(params);
|
|
93
|
-
},
|
|
94
|
-
async setRecords (folderId, type, newRecords) {
|
|
95
|
-
setRecordsIfNeeded(newRecords);
|
|
96
|
-
const result = await recordLocking.setRecords(folderId, type, newRecords);
|
|
97
|
-
if (!result) return;
|
|
98
|
-
setRecords(result);
|
|
99
|
-
},
|
|
100
|
-
error,
|
|
101
|
-
records,
|
|
102
|
-
loading
|
|
103
|
-
};
|
|
104
|
-
return /*#__PURE__*/ react.createElement(RecordLockingContext.Provider, {
|
|
105
|
-
...props,
|
|
106
|
-
value: value
|
|
107
|
-
});
|
|
108
|
-
};
|
|
109
|
-
export { RecordLockingContext, RecordLockingProvider };
|
|
110
|
-
|
|
111
|
-
//# sourceMappingURL=RecordLockingProvider.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/RecordLockingProvider.js","sources":["../../src/components/RecordLockingProvider.tsx"],"sourcesContent":["import React, { useCallback, useMemo, useState } from \"react\";\nimport { useApolloClient } from \"@apollo/react-hooks\";\nimport { createRecordLocking } from \"~/domain/RecordLocking.js\";\nimport type {\n IFetchLockedEntryLockRecordParams,\n IFetchLockRecordParams,\n IPossiblyRecordLockingRecord,\n IRecordLockingContext,\n IRecordLockingError,\n IUnlockEntryParams,\n IUpdateEntryLockParams\n} from \"~/types.js\";\nimport { useStateIfMounted } from \"@webiny/app-admin\";\n\nexport interface IRecordLockingProviderProps {\n children: React.ReactNode;\n}\n\nexport const RecordLockingContext = React.createContext({} as unknown as IRecordLockingContext);\n\nconst isSameArray = (\n existingRecords: Pick<IPossiblyRecordLockingRecord, \"id\" | \"savedOn\">[],\n newRecords: Pick<IPossiblyRecordLockingRecord, \"id\" | \"savedOn\">[]\n): boolean => {\n if (existingRecords.length !== newRecords.length) {\n return false;\n }\n return existingRecords.every((record, index) => {\n const newRecord = newRecords[index];\n if (!newRecord) {\n return false;\n }\n\n return newRecord.id === record.id && newRecord.savedOn === record.savedOn;\n });\n};\n\nconst getData = (records: IPossiblyRecordLockingRecord[]) => {\n return records.map(record => ({\n id: record.id,\n savedOn: record.savedOn\n }));\n};\n\nexport const RecordLockingProvider = (props: IRecordLockingProviderProps) => {\n const client = useApolloClient();\n\n const [loading, setLoading] = useState(false);\n\n const recordLocking = useMemo(() => {\n return createRecordLocking({\n client,\n setLoading\n });\n }, []);\n\n const [error, setError] = useStateIfMounted<IRecordLockingError | null>(null);\n\n const [records, setRecords] = useStateIfMounted<IPossiblyRecordLockingRecord[]>([]);\n\n const setRecordsIfNeeded = useCallback(\n (newRecords: IPossiblyRecordLockingRecord[]) => {\n const sameArray = isSameArray(getData(records), getData(newRecords));\n if (sameArray) {\n return;\n }\n setRecords(newRecords);\n },\n [records]\n );\n\n const value: IRecordLockingContext = {\n async updateEntryLock(params: IUpdateEntryLockParams) {\n const result = await recordLocking.updateEntryLock(params);\n if (result.error) {\n setError(result.error);\n return result;\n }\n const target = result.data;\n if (!target?.id) {\n const error = {\n message: \"No data returned from server.\",\n code: \"NO_DATA\"\n };\n setError(error);\n return {\n error,\n data: null\n };\n }\n\n setRecords(prev => {\n return prev.map(item => {\n if (item.entryId === target.id) {\n return {\n ...item,\n $locked: result.data\n };\n }\n return item;\n });\n });\n return result;\n },\n async unlockEntry(params: IUnlockEntryParams) {\n return await recordLocking.unlockEntry(params);\n },\n async unlockEntryForce(params: IUnlockEntryParams) {\n return await recordLocking.unlockEntry(params, true);\n },\n isLockExpired(input: Date | string): boolean {\n return recordLocking.isLockExpired(input);\n },\n isRecordLocked(record) {\n if (!record) {\n return false;\n }\n return recordLocking.isRecordLocked(record);\n },\n getLockRecordEntry(id: string) {\n return recordLocking.getLockRecordEntry(id);\n },\n removeEntryLock(params: IUnlockEntryParams) {\n return recordLocking.removeEntryLock(params);\n },\n async fetchLockRecord(params: IFetchLockRecordParams) {\n try {\n return await recordLocking.fetchLockRecord(params);\n } catch (ex) {\n return {\n data: null,\n error: ex\n };\n }\n },\n async fetchLockedEntryLockRecord(params: IFetchLockedEntryLockRecordParams) {\n return recordLocking.fetchLockedEntryLockRecord(params);\n },\n async setRecords(folderId, type, newRecords) {\n setRecordsIfNeeded(newRecords);\n\n const result = await recordLocking.setRecords(folderId, type, newRecords);\n if (!result) {\n return;\n }\n setRecords(result);\n },\n error,\n records,\n loading\n };\n\n return <RecordLockingContext.Provider {...props} value={value} />;\n};\n"],"names":["RecordLockingContext","React","isSameArray","existingRecords","newRecords","record","index","newRecord","getData","records","RecordLockingProvider","props","client","useApolloClient","loading","setLoading","useState","recordLocking","useMemo","createRecordLocking","error","setError","useStateIfMounted","setRecords","setRecordsIfNeeded","useCallback","sameArray","value","params","result","target","prev","item","input","id","ex","folderId","type"],"mappings":";;;;AAkBO,MAAMA,uBAAuB,WAAHA,GAAGC,MAAAA,aAAmB,CAAC,CAAC;AAEzD,MAAMC,cAAc,CAChBC,iBACAC;IAEA,IAAID,gBAAgB,MAAM,KAAKC,WAAW,MAAM,EAC5C,OAAO;IAEX,OAAOD,gBAAgB,KAAK,CAAC,CAACE,QAAQC;QAClC,MAAMC,YAAYH,UAAU,CAACE,MAAM;QACnC,IAAI,CAACC,WACD,OAAO;QAGX,OAAOA,UAAU,EAAE,KAAKF,OAAO,EAAE,IAAIE,UAAU,OAAO,KAAKF,OAAO,OAAO;IAC7E;AACJ;AAEA,MAAMG,UAAU,CAACC,UACNA,QAAQ,GAAG,CAACJ,CAAAA,SAAW;YAC1B,IAAIA,OAAO,EAAE;YACb,SAASA,OAAO,OAAO;QAC3B;AAGG,MAAMK,wBAAwB,CAACC;IAClC,MAAMC,SAASC;IAEf,MAAM,CAACC,SAASC,WAAW,GAAGC,SAAS;IAEvC,MAAMC,gBAAgBC,QAAQ,IACnBC,oBAAoB;YACvBP;YACAG;QACJ,IACD,EAAE;IAEL,MAAM,CAACK,OAAOC,SAAS,GAAGC,kBAA8C;IAExE,MAAM,CAACb,SAASc,WAAW,GAAGD,kBAAkD,EAAE;IAElF,MAAME,qBAAqBC,YACvB,CAACrB;QACG,MAAMsB,YAAYxB,YAAYM,QAAQC,UAAUD,QAAQJ;QACxD,IAAIsB,WACA;QAEJH,WAAWnB;IACf,GACA;QAACK;KAAQ;IAGb,MAAMkB,QAA+B;QACjC,MAAM,iBAAgBC,MAA8B;YAChD,MAAMC,SAAS,MAAMZ,cAAc,eAAe,CAACW;YACnD,IAAIC,OAAO,KAAK,EAAE;gBACdR,SAASQ,OAAO,KAAK;gBACrB,OAAOA;YACX;YACA,MAAMC,SAASD,OAAO,IAAI;YAC1B,IAAI,CAACC,QAAQ,IAAI;gBACb,MAAMV,QAAQ;oBACV,SAAS;oBACT,MAAM;gBACV;gBACAC,SAASD;gBACT,OAAO;oBACHA;oBACA,MAAM;gBACV;YACJ;YAEAG,WAAWQ,CAAAA,OACAA,KAAK,GAAG,CAACC,CAAAA;oBACZ,IAAIA,KAAK,OAAO,KAAKF,OAAO,EAAE,EAC1B,OAAO;wBACH,GAAGE,IAAI;wBACP,SAASH,OAAO,IAAI;oBACxB;oBAEJ,OAAOG;gBACX;YAEJ,OAAOH;QACX;QACA,MAAM,aAAYD,MAA0B;YACxC,OAAO,MAAMX,cAAc,WAAW,CAACW;QAC3C;QACA,MAAM,kBAAiBA,MAA0B;YAC7C,OAAO,MAAMX,cAAc,WAAW,CAACW,QAAQ;QACnD;QACA,eAAcK,KAAoB;YAC9B,OAAOhB,cAAc,aAAa,CAACgB;QACvC;QACA,gBAAe5B,MAAM;YACjB,IAAI,CAACA,QACD,OAAO;YAEX,OAAOY,cAAc,cAAc,CAACZ;QACxC;QACA,oBAAmB6B,EAAU;YACzB,OAAOjB,cAAc,kBAAkB,CAACiB;QAC5C;QACA,iBAAgBN,MAA0B;YACtC,OAAOX,cAAc,eAAe,CAACW;QACzC;QACA,MAAM,iBAAgBA,MAA8B;YAChD,IAAI;gBACA,OAAO,MAAMX,cAAc,eAAe,CAACW;YAC/C,EAAE,OAAOO,IAAI;gBACT,OAAO;oBACH,MAAM;oBACN,OAAOA;gBACX;YACJ;QACJ;QACA,MAAM,4BAA2BP,MAAyC;YACtE,OAAOX,cAAc,0BAA0B,CAACW;QACpD;QACA,MAAM,YAAWQ,QAAQ,EAAEC,IAAI,EAAEjC,UAAU;YACvCoB,mBAAmBpB;YAEnB,MAAMyB,SAAS,MAAMZ,cAAc,UAAU,CAACmB,UAAUC,MAAMjC;YAC9D,IAAI,CAACyB,QACD;YAEJN,WAAWM;QACf;QACAT;QACAX;QACAK;IACJ;IAEA,OAAO,WAAP,GAAO,oBAACd,qBAAqB,QAAQ;QAAE,GAAGW,KAAK;QAAE,OAAOgB;;AAC5D"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/SecurityPermissions.js","sources":["../../src/components/SecurityPermissions.tsx"],"sourcesContent":["import React from \"react\";\nimport { AdminConfig } from \"@webiny/app-admin\";\nimport { ReactComponent as LockIcon } from \"@webiny/icons/lock.svg\";\nimport { RECORD_LOCKING_PERMISSIONS_SCHEMA } from \"~/domain/permissionsSchema.js\";\n\nconst { Security } = AdminConfig;\n\nexport const SecurityPermissions = () => {\n return (\n <AdminConfig>\n <Security.Permissions\n name=\"record-locking\"\n title=\"Record Locking\"\n description=\"Manage Record Locking permissions.\"\n icon={<LockIcon />}\n schema={RECORD_LOCKING_PERMISSIONS_SCHEMA}\n />\n </AdminConfig>\n );\n};\n"],"names":["Security","AdminConfig","SecurityPermissions","LockIcon","RECORD_LOCKING_PERMISSIONS_SCHEMA"],"mappings":";;;;AAKA,MAAM,EAAEA,UAAAA,QAAQ,EAAE,GAAGC;AAEd,MAAMC,sBAAsB,IACxB,WAAP,GACI,oBAACD,aAAWA,MAAAA,WAAAA,GACR,oBAACD,SAAS,WAAW;QACjB,MAAK;QACL,OAAM;QACN,aAAY;QACZ,oBAAM,oBAACG,gBAAQA;QACf,QAAQC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const UseContentEntriesListHookDecorator: () => React.JSX.Element;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
import { ContentEntryListConfig } from "@webiny/app-headless-cms";
|
|
3
|
-
import { useRecordLocking } from "../../hooks/index.js";
|
|
4
|
-
const UseContentEntriesListHookDecorator = ContentEntryListConfig.ContentEntries.useContentEntriesList.createDecorator((originalHook)=>function() {
|
|
5
|
-
const value = originalHook();
|
|
6
|
-
const recordLocking = useRecordLocking();
|
|
7
|
-
useEffect(()=>{
|
|
8
|
-
if (!value.records) return;
|
|
9
|
-
recordLocking.setRecords(value.folderId, value.modelId, value.records);
|
|
10
|
-
}, [
|
|
11
|
-
value.folderId,
|
|
12
|
-
value.modelId,
|
|
13
|
-
value.records,
|
|
14
|
-
recordLocking
|
|
15
|
-
]);
|
|
16
|
-
return {
|
|
17
|
-
...value,
|
|
18
|
-
records: recordLocking.records
|
|
19
|
-
};
|
|
20
|
-
});
|
|
21
|
-
export { UseContentEntriesListHookDecorator };
|
|
22
|
-
|
|
23
|
-
//# sourceMappingURL=UseContentEntriesListHookDecorator.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/decorators/UseContentEntriesListHookDecorator.js","sources":["../../../src/components/decorators/UseContentEntriesListHookDecorator.ts"],"sourcesContent":["import { useEffect } from \"react\";\nimport { ContentEntryListConfig } from \"@webiny/app-headless-cms\";\nimport { useRecordLocking } from \"~/hooks/index.js\";\nimport type { IPossiblyRecordLockingRecord } from \"~/types.js\";\n\nexport const UseContentEntriesListHookDecorator =\n ContentEntryListConfig.ContentEntries.useContentEntriesList.createDecorator(originalHook => {\n return function RecordLockingUseContentEntriesList() {\n const value = originalHook();\n const recordLocking = useRecordLocking();\n\n useEffect(() => {\n if (!value.records) {\n return;\n }\n recordLocking.setRecords(\n value.folderId,\n value.modelId,\n // TODO determine if this is correct\n value.records as IPossiblyRecordLockingRecord[]\n );\n }, [value.folderId, value.modelId, value.records, recordLocking]);\n\n return {\n ...value,\n records: recordLocking.records\n };\n };\n });\n"],"names":["UseContentEntriesListHookDecorator","ContentEntryListConfig","originalHook","value","recordLocking","useRecordLocking","useEffect"],"mappings":";;;AAKO,MAAMA,qCACTC,uBAAuB,cAAc,CAAC,qBAAqB,CAAC,eAAe,CAACC,CAAAA,eACjE;QACH,MAAMC,QAAQD;QACd,MAAME,gBAAgBC;QAEtBC,UAAU;YACN,IAAI,CAACH,MAAM,OAAO,EACd;YAEJC,cAAc,UAAU,CACpBD,MAAM,QAAQ,EACdA,MAAM,OAAO,EAEbA,MAAM,OAAO;QAErB,GAAG;YAACA,MAAM,QAAQ;YAAEA,MAAM,OAAO;YAAEA,MAAM,OAAO;YAAEC;SAAc;QAEhE,OAAO;YACH,GAAGD,KAAK;YACR,SAASC,cAAc,OAAO;QAClC;IACJ"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* When record locking mechanism is checking for records equality, it compares record `id` and `savedOn`.
|
|
3
|
-
* When you're updating ACO cache, you're just passing the new content entry value(s), and sometimes you might
|
|
4
|
-
* be doing it without the `savedOn`, and that causes record locking to keep its old state.
|
|
5
|
-
*
|
|
6
|
-
* This decorator ensures that calls to `updateRecordInCache` always include a `savedOn` timestamp.
|
|
7
|
-
*/
|
|
8
|
-
export declare const UseRecordsDecorator: () => React.JSX.Element;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { useRecords } from "@webiny/app-aco";
|
|
2
|
-
const UseRecordsDecorator = useRecords.createDecorator((baseHook)=>(folderId)=>{
|
|
3
|
-
const hook = baseHook(folderId);
|
|
4
|
-
return {
|
|
5
|
-
...hook,
|
|
6
|
-
updateRecordInCache (record) {
|
|
7
|
-
hook.updateRecordInCache({
|
|
8
|
-
...record,
|
|
9
|
-
savedOn: new Date().toISOString()
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
});
|
|
14
|
-
export { UseRecordsDecorator };
|
|
15
|
-
|
|
16
|
-
//# sourceMappingURL=UseRecordsDecorator.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"components/decorators/UseRecordsDecorator.js","sources":["../../../src/components/decorators/UseRecordsDecorator.tsx"],"sourcesContent":["import { useRecords } from \"@webiny/app-aco\";\n\n/**\n * When record locking mechanism is checking for records equality, it compares record `id` and `savedOn`.\n * When you're updating ACO cache, you're just passing the new content entry value(s), and sometimes you might\n * be doing it without the `savedOn`, and that causes record locking to keep its old state.\n *\n * This decorator ensures that calls to `updateRecordInCache` always include a `savedOn` timestamp.\n */\nexport const UseRecordsDecorator = useRecords.createDecorator(baseHook => {\n return (folderId?: string) => {\n const hook = baseHook(folderId);\n\n return {\n ...hook,\n updateRecordInCache(record: any) {\n hook.updateRecordInCache({\n ...record,\n savedOn: new Date().toISOString()\n });\n }\n };\n };\n});\n"],"names":["UseRecordsDecorator","useRecords","baseHook","folderId","hook","record","Date"],"mappings":";AASO,MAAMA,sBAAsBC,WAAW,eAAe,CAACC,CAAAA,WACnD,CAACC;QACJ,MAAMC,OAAOF,SAASC;QAEtB,OAAO;YACH,GAAGC,IAAI;YACP,qBAAoBC,MAAW;gBAC3BD,KAAK,mBAAmB,CAAC;oBACrB,GAAGC,MAAM;oBACT,SAAS,IAAIC,OAAO,WAAW;gBACnC;YACJ;QACJ;IACJ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const UseSaveEntryDecorator: () => React.JSX.Element;
|