@webiny/app-record-locking 6.3.0-beta.4 → 6.4.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/HeadlessCmsActionsAcoCell.js +29 -51
- package/components/HeadlessCmsActionsAcoCell.js.map +1 -1
- package/components/HeadlessCmsContentEntry/ContentEntryGuard.js +26 -34
- package/components/HeadlessCmsContentEntry/ContentEntryGuard.js.map +1 -1
- package/components/HeadlessCmsContentEntry/ContentEntryLocker.js +70 -89
- package/components/HeadlessCmsContentEntry/ContentEntryLocker.js.map +1 -1
- package/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.js +38 -62
- package/components/HeadlessCmsContentEntry/HeadlessCmsContentEntry.js.map +1 -1
- package/components/HeadlessCmsContentEntry/index.js +0 -2
- package/components/LockedRecord/LockedRecord.js +45 -57
- package/components/LockedRecord/LockedRecord.js.map +1 -1
- package/components/LockedRecord/LockedRecordForceUnlock.js +49 -63
- package/components/LockedRecord/LockedRecordForceUnlock.js.map +1 -1
- package/components/LockedRecord/index.js +0 -2
- package/components/RecordLockingProvider.js +103 -117
- package/components/RecordLockingProvider.js.map +1 -1
- package/components/SecurityPermissions.js +11 -14
- package/components/SecurityPermissions.js.map +1 -1
- package/components/decorators/UseContentEntriesListHookDecorator.js +18 -18
- package/components/decorators/UseContentEntriesListHookDecorator.js.map +1 -1
- package/components/decorators/UseRecordsDecorator.js +13 -22
- package/components/decorators/UseRecordsDecorator.js.map +1 -1
- package/components/decorators/UseSaveEntryDecorator.js +35 -49
- package/components/decorators/UseSaveEntryDecorator.js.map +1 -1
- package/domain/RecordLocking.js +229 -291
- package/domain/RecordLocking.js.map +1 -1
- package/domain/RecordLockingClient.js +17 -16
- package/domain/RecordLockingClient.js.map +1 -1
- package/domain/RecordLockingGetLockRecord.js +13 -15
- package/domain/RecordLockingGetLockRecord.js.map +1 -1
- package/domain/RecordLockingGetLockedEntryLockRecord.js +12 -13
- package/domain/RecordLockingGetLockedEntryLockRecord.js.map +1 -1
- package/domain/RecordLockingIsEntryLocked.js +15 -14
- package/domain/RecordLockingIsEntryLocked.js.map +1 -1
- package/domain/RecordLockingListLockRecords.js +18 -24
- package/domain/RecordLockingListLockRecords.js.map +1 -1
- package/domain/RecordLockingLockEntry.js +8 -9
- package/domain/RecordLockingLockEntry.js.map +1 -1
- package/domain/RecordLockingUnlockEntry.js +12 -13
- package/domain/RecordLockingUnlockEntry.js.map +1 -1
- package/domain/RecordLockingUpdateEntryLock.js +12 -13
- package/domain/RecordLockingUpdateEntryLock.js.map +1 -1
- package/domain/abstractions/IRecordLocking.js +0 -3
- package/domain/abstractions/IRecordLockingClient.js +0 -3
- package/domain/abstractions/IRecordLockingGetLockRecord.js +0 -3
- package/domain/abstractions/IRecordLockingGetLockedEntryLockRecord.js +0 -3
- package/domain/abstractions/IRecordLockingIsEntryLocked.js +0 -3
- package/domain/abstractions/IRecordLockingListLockRecords.js +0 -3
- package/domain/abstractions/IRecordLockingLockEntry.js +0 -3
- package/domain/abstractions/IRecordLockingUnlockEntry.js +0 -3
- package/domain/abstractions/IRecordLockingUpdateEntryLock.js +0 -3
- package/domain/graphql/fields.js +3 -2
- package/domain/graphql/fields.js.map +1 -1
- package/domain/graphql/getLockRecord.js +3 -2
- package/domain/graphql/getLockRecord.js.map +1 -1
- package/domain/graphql/getLockedEntryLockRecord.js +3 -2
- package/domain/graphql/getLockedEntryLockRecord.js.map +1 -1
- package/domain/graphql/isEntryLocked.js +3 -2
- package/domain/graphql/isEntryLocked.js.map +1 -1
- package/domain/graphql/listLockRecords.js +4 -5
- package/domain/graphql/listLockRecords.js.map +1 -1
- package/domain/graphql/lockEntry.js +3 -4
- package/domain/graphql/lockEntry.js.map +1 -1
- package/domain/graphql/unlockEntry.js +3 -2
- package/domain/graphql/unlockEntry.js.map +1 -1
- package/domain/graphql/updateEntryLock.js +3 -2
- package/domain/graphql/updateEntryLock.js.map +1 -1
- package/domain/permissionsSchema.js +6 -5
- package/domain/permissionsSchema.js.map +1 -1
- package/domain/utils/createRecordLockingClient.js +5 -6
- package/domain/utils/createRecordLockingClient.js.map +1 -1
- package/domain/utils/createRecordLockingError.js +10 -11
- package/domain/utils/createRecordLockingError.js.map +1 -1
- package/features/permissions/abstractions.js +2 -1
- package/features/permissions/abstractions.js.map +1 -1
- package/features/permissions/feature.js +2 -1
- package/features/permissions/feature.js.map +1 -1
- package/hooks/index.js +0 -2
- package/hooks/usePermission.js +14 -15
- package/hooks/usePermission.js.map +1 -1
- package/hooks/useRecordLocking.js +5 -6
- package/hooks/useRecordLocking.js.map +1 -1
- package/index.js +15 -21
- package/index.js.map +1 -1
- package/package.json +12 -12
- package/types.js +0 -3
- package/utils/createCacheKey.js +9 -10
- package/utils/createCacheKey.js.map +1 -1
- package/components/HeadlessCmsContentEntry/index.js.map +0 -1
- package/components/LockedRecord/index.js.map +0 -1
- package/domain/abstractions/IRecordLocking.js.map +0 -1
- package/domain/abstractions/IRecordLockingClient.js.map +0 -1
- package/domain/abstractions/IRecordLockingGetLockRecord.js.map +0 -1
- package/domain/abstractions/IRecordLockingGetLockedEntryLockRecord.js.map +0 -1
- package/domain/abstractions/IRecordLockingIsEntryLocked.js.map +0 -1
- package/domain/abstractions/IRecordLockingListLockRecords.js.map +0 -1
- package/domain/abstractions/IRecordLockingLockEntry.js.map +0 -1
- package/domain/abstractions/IRecordLockingUnlockEntry.js.map +0 -1
- package/domain/abstractions/IRecordLockingUpdateEntryLock.js.map +0 -1
- package/hooks/index.js.map +0 -1
- package/types.js.map +0 -1
|
@@ -1,66 +1,54 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { ReactComponent
|
|
1
|
+
import react from "react";
|
|
2
|
+
import { ReactComponent } from "@webiny/icons/lock.svg";
|
|
3
3
|
import { Grid, Heading, Icon, Text } from "@webiny/admin-ui";
|
|
4
4
|
import { useRecordLocking } from "../../hooks/index.js";
|
|
5
5
|
import { useContentEntry } from "@webiny/app-headless-cms";
|
|
6
6
|
import { LockedRecordForceUnlock } from "./LockedRecordForceUnlock.js";
|
|
7
|
-
const Wrapper = ({
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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!");
|
|
32
35
|
};
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
} = useRecordLocking();
|
|
48
|
-
const record = getLockRecordEntry(lockRecordEntry.id);
|
|
49
|
-
if (!record) {
|
|
50
|
-
return /*#__PURE__*/React.createElement(Wrapper, null, /*#__PURE__*/React.createElement(Text, null, "Could not find the lock record. Please refresh the Admin UI."));
|
|
51
|
-
} else if (!lockRecordEntry?.lockedBy) {
|
|
52
|
-
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, {
|
|
53
|
-
id: lockRecordEntry.id,
|
|
54
|
-
type: record.$lockingType,
|
|
55
|
-
title: record.meta?.title
|
|
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
|
+
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
|
|
56
50
|
}));
|
|
57
|
-
}
|
|
58
|
-
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, {
|
|
59
|
-
id: lockRecordEntry.id,
|
|
60
|
-
type: record.$lockingType,
|
|
61
|
-
lockedBy: lockRecordEntry.lockedBy,
|
|
62
|
-
title: record.meta?.title
|
|
63
|
-
}));
|
|
64
51
|
};
|
|
52
|
+
export { LockedRecord };
|
|
65
53
|
|
|
66
54
|
//# sourceMappingURL=LockedRecord.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
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;IAGX,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,71 +1,57 @@
|
|
|
1
|
-
import
|
|
1
|
+
import react, { useCallback, useEffect, useState } from "react";
|
|
2
2
|
import { Alert, Button, Text } from "@webiny/admin-ui";
|
|
3
3
|
import { useConfirmationDialog, useSnackbar } from "@webiny/app-admin";
|
|
4
4
|
import { useContentEntriesList } from "@webiny/app-headless-cms";
|
|
5
|
-
import {
|
|
6
|
-
const ErrorMessage = props
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
title: "Warning",
|
|
14
|
-
className: "mb-md"
|
|
15
|
-
}, /*#__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?"));
|
|
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?"));
|
|
16
13
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} = useContentEntriesList();
|
|
24
|
-
const {
|
|
25
|
-
showConfirmation: showForceUnlockConfirmation
|
|
26
|
-
} = useConfirmationDialog({
|
|
27
|
-
title: "Force unlock the entry",
|
|
28
|
-
message: /*#__PURE__*/React.createElement(ErrorMessage, props)
|
|
29
|
-
});
|
|
30
|
-
const {
|
|
31
|
-
showSnackbar
|
|
32
|
-
} = useSnackbar();
|
|
33
|
-
const [error, setError] = useState();
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
if (!error?.message) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
console.error(error);
|
|
39
|
-
showSnackbar(error.message);
|
|
40
|
-
}, [error?.message]);
|
|
41
|
-
const onClick = useCallback(() => {
|
|
42
|
-
showForceUnlockConfirmation(async () => {
|
|
43
|
-
const result = await unlockEntryForce({
|
|
44
|
-
id: props.id,
|
|
45
|
-
$lockingType: props.type
|
|
46
|
-
});
|
|
47
|
-
if (!result.error) {
|
|
48
|
-
navigateTo();
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
setError(result.error);
|
|
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)
|
|
52
20
|
});
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
+
}));
|
|
69
54
|
};
|
|
55
|
+
export { LockedRecordForceUnlock };
|
|
70
56
|
|
|
71
57
|
//# sourceMappingURL=LockedRecordForceUnlock.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
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,125 +1,111 @@
|
|
|
1
|
-
import
|
|
1
|
+
import react, { useCallback, useMemo, useState } from "react";
|
|
2
2
|
import { useApolloClient } from "@apollo/react-hooks";
|
|
3
3
|
import { createRecordLocking } from "../domain/RecordLocking.js";
|
|
4
4
|
import { useStateIfMounted } from "@webiny/app-admin";
|
|
5
|
-
|
|
6
|
-
const isSameArray = (existingRecords, newRecords)
|
|
7
|
-
|
|
8
|
-
return
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
return newRecord.id === record.id && newRecord.savedOn === record.savedOn;
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
const getData = records => {
|
|
19
|
-
return records.map(record => ({
|
|
20
|
-
id: record.id,
|
|
21
|
-
savedOn: record.savedOn
|
|
22
|
-
}));
|
|
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
|
+
});
|
|
23
13
|
};
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
31
107
|
});
|
|
32
|
-
}, []);
|
|
33
|
-
const [error, setError] = useStateIfMounted(null);
|
|
34
|
-
const [records, setRecords] = useStateIfMounted([]);
|
|
35
|
-
const setRecordsIfNeeded = useCallback(newRecords => {
|
|
36
|
-
const sameArray = isSameArray(getData(records), getData(newRecords));
|
|
37
|
-
if (sameArray) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
setRecords(newRecords);
|
|
41
|
-
}, [records]);
|
|
42
|
-
const value = {
|
|
43
|
-
async updateEntryLock(params) {
|
|
44
|
-
const result = await recordLocking.updateEntryLock(params);
|
|
45
|
-
if (result.error) {
|
|
46
|
-
setError(result.error);
|
|
47
|
-
return result;
|
|
48
|
-
}
|
|
49
|
-
const target = result.data;
|
|
50
|
-
if (!target?.id) {
|
|
51
|
-
const error = {
|
|
52
|
-
message: "No data returned from server.",
|
|
53
|
-
code: "NO_DATA"
|
|
54
|
-
};
|
|
55
|
-
setError(error);
|
|
56
|
-
return {
|
|
57
|
-
error,
|
|
58
|
-
data: null
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
setRecords(prev => {
|
|
62
|
-
return prev.map(item => {
|
|
63
|
-
if (item.entryId === target.id) {
|
|
64
|
-
return {
|
|
65
|
-
...item,
|
|
66
|
-
$locked: result.data
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
return item;
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
return result;
|
|
73
|
-
},
|
|
74
|
-
async unlockEntry(params) {
|
|
75
|
-
return await recordLocking.unlockEntry(params);
|
|
76
|
-
},
|
|
77
|
-
async unlockEntryForce(params) {
|
|
78
|
-
return await recordLocking.unlockEntry(params, true);
|
|
79
|
-
},
|
|
80
|
-
isLockExpired(input) {
|
|
81
|
-
return recordLocking.isLockExpired(input);
|
|
82
|
-
},
|
|
83
|
-
isRecordLocked(record) {
|
|
84
|
-
if (!record) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
return recordLocking.isRecordLocked(record);
|
|
88
|
-
},
|
|
89
|
-
getLockRecordEntry(id) {
|
|
90
|
-
return recordLocking.getLockRecordEntry(id);
|
|
91
|
-
},
|
|
92
|
-
removeEntryLock(params) {
|
|
93
|
-
return recordLocking.removeEntryLock(params);
|
|
94
|
-
},
|
|
95
|
-
async fetchLockRecord(params) {
|
|
96
|
-
try {
|
|
97
|
-
return await recordLocking.fetchLockRecord(params);
|
|
98
|
-
} catch (ex) {
|
|
99
|
-
return {
|
|
100
|
-
data: null,
|
|
101
|
-
error: ex
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
async fetchLockedEntryLockRecord(params) {
|
|
106
|
-
return recordLocking.fetchLockedEntryLockRecord(params);
|
|
107
|
-
},
|
|
108
|
-
async setRecords(folderId, type, newRecords) {
|
|
109
|
-
setRecordsIfNeeded(newRecords);
|
|
110
|
-
const result = await recordLocking.setRecords(folderId, type, newRecords);
|
|
111
|
-
if (!result) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
setRecords(result);
|
|
115
|
-
},
|
|
116
|
-
error,
|
|
117
|
-
records,
|
|
118
|
-
loading
|
|
119
|
-
};
|
|
120
|
-
return /*#__PURE__*/React.createElement(RecordLockingContext.Provider, Object.assign({}, props, {
|
|
121
|
-
value: value
|
|
122
|
-
}));
|
|
123
108
|
};
|
|
109
|
+
export { RecordLockingContext, RecordLockingProvider };
|
|
124
110
|
|
|
125
111
|
//# sourceMappingURL=RecordLockingProvider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
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":"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"}
|