@strapi/content-manager 5.60.0 → 5.61.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/constants/customOrder.js +14 -0
- package/dist/admin/constants/customOrder.js.map +1 -0
- package/dist/admin/constants/customOrder.mjs +10 -0
- package/dist/admin/constants/customOrder.mjs.map +1 -0
- package/dist/admin/hooks/useDocument.js +22 -11
- package/dist/admin/hooks/useDocument.js.map +1 -1
- package/dist/admin/hooks/useDocument.mjs +22 -11
- package/dist/admin/hooks/useDocument.mjs.map +1 -1
- package/dist/admin/hooks/useDocumentLayout.js.map +1 -1
- package/dist/admin/hooks/useDocumentLayout.mjs.map +1 -1
- package/dist/admin/hooks/useHasBeenNearViewport.js +70 -0
- package/dist/admin/hooks/useHasBeenNearViewport.js.map +1 -0
- package/dist/admin/hooks/useHasBeenNearViewport.mjs +46 -0
- package/dist/admin/hooks/useHasBeenNearViewport.mjs.map +1 -0
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.js +102 -32
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.mjs +104 -35
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.js +20 -17
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.mjs +20 -17
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js +15 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs +17 -3
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withStrapiSchema.js +21 -0
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withStrapiSchema.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withStrapiSchema.mjs +22 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withStrapiSchema.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js +4 -7
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs +4 -7
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js +46 -10
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs +47 -11
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormLayout.js +201 -51
- package/dist/admin/pages/EditView/components/FormLayout.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormLayout.mjs +202 -53
- package/dist/admin/pages/EditView/components/FormLayout.mjs.map +1 -1
- package/dist/admin/pages/ListConfiguration/components/Settings.js +31 -2
- package/dist/admin/pages/ListConfiguration/components/Settings.js.map +1 -1
- package/dist/admin/pages/ListConfiguration/components/Settings.mjs +31 -2
- package/dist/admin/pages/ListConfiguration/components/Settings.mjs.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.js +196 -132
- package/dist/admin/pages/ListView/ListViewPage.js.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.mjs +196 -132
- package/dist/admin/pages/ListView/ListViewPage.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/CustomOrder.js +571 -0
- package/dist/admin/pages/ListView/components/CustomOrder.js.map +1 -0
- package/dist/admin/pages/ListView/components/CustomOrder.mjs +546 -0
- package/dist/admin/pages/ListView/components/CustomOrder.mjs.map +1 -0
- package/dist/admin/pages/ListView/components/TableActions.js +4 -1
- package/dist/admin/pages/ListView/components/TableActions.js.map +1 -1
- package/dist/admin/pages/ListView/components/TableActions.mjs +4 -1
- package/dist/admin/pages/ListView/components/TableActions.mjs.map +1 -1
- package/dist/admin/services/documents.js +22 -1
- package/dist/admin/services/documents.js.map +1 -1
- package/dist/admin/services/documents.mjs +21 -2
- package/dist/admin/services/documents.mjs.map +1 -1
- package/dist/admin/src/constants/customOrder.d.ts +8 -0
- package/dist/admin/src/exports.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +4 -0
- package/dist/admin/src/hooks/useDocumentLayout.d.ts +6 -2
- package/dist/admin/src/hooks/useHasBeenNearViewport.d.ts +13 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.d.ts +13 -1
- package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +11 -1
- package/dist/admin/src/pages/ListView/components/CustomOrder.d.ts +72 -0
- package/dist/admin/src/services/documents.d.ts +10 -2
- package/dist/admin/translations/en.json.js +9 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +9 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/server/audit-logs.js +36 -0
- package/dist/server/audit-logs.js.map +1 -0
- package/dist/server/audit-logs.mjs +33 -0
- package/dist/server/audit-logs.mjs.map +1 -0
- package/dist/server/bootstrap.js +8 -0
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/server/bootstrap.mjs +8 -0
- package/dist/server/bootstrap.mjs.map +1 -1
- package/dist/server/controllers/collection-types.js +8 -0
- package/dist/server/controllers/collection-types.js.map +1 -1
- package/dist/server/controllers/collection-types.mjs +8 -0
- package/dist/server/controllers/collection-types.mjs.map +1 -1
- package/dist/server/controllers/content-types.js +15 -0
- package/dist/server/controllers/content-types.js.map +1 -1
- package/dist/server/controllers/content-types.mjs +16 -1
- package/dist/server/controllers/content-types.mjs.map +1 -1
- package/dist/server/controllers/index.js +3 -1
- package/dist/server/controllers/index.js.map +1 -1
- package/dist/server/controllers/index.mjs +2 -0
- package/dist/server/controllers/index.mjs.map +1 -1
- package/dist/server/controllers/relations.js +5 -1
- package/dist/server/controllers/relations.js.map +1 -1
- package/dist/server/controllers/relations.mjs +5 -1
- package/dist/server/controllers/relations.mjs.map +1 -1
- package/dist/server/controllers/single-types.js +10 -1
- package/dist/server/controllers/single-types.js.map +1 -1
- package/dist/server/controllers/single-types.mjs +10 -1
- package/dist/server/controllers/single-types.mjs.map +1 -1
- package/dist/server/controllers/validation/model-configuration.js +2 -1
- package/dist/server/controllers/validation/model-configuration.js.map +1 -1
- package/dist/server/controllers/validation/model-configuration.mjs +2 -1
- package/dist/server/controllers/validation/model-configuration.mjs.map +1 -1
- package/dist/server/custom-order/constants.js +21 -0
- package/dist/server/custom-order/constants.js.map +1 -0
- package/dist/server/custom-order/constants.mjs +17 -0
- package/dist/server/custom-order/constants.mjs.map +1 -0
- package/dist/server/custom-order/controllers/custom-order.js +77 -0
- package/dist/server/custom-order/controllers/custom-order.js.map +1 -0
- package/dist/server/custom-order/controllers/custom-order.mjs +75 -0
- package/dist/server/custom-order/controllers/custom-order.mjs.map +1 -0
- package/dist/server/custom-order/controllers/index.js +10 -0
- package/dist/server/custom-order/controllers/index.js.map +1 -0
- package/dist/server/custom-order/controllers/index.mjs +8 -0
- package/dist/server/custom-order/controllers/index.mjs.map +1 -0
- package/dist/server/custom-order/index.js +71 -0
- package/dist/server/custom-order/index.js.map +1 -0
- package/dist/server/custom-order/index.mjs +69 -0
- package/dist/server/custom-order/index.mjs.map +1 -0
- package/dist/server/custom-order/routes/custom-order.js +38 -0
- package/dist/server/custom-order/routes/custom-order.js.map +1 -0
- package/dist/server/custom-order/routes/custom-order.mjs +36 -0
- package/dist/server/custom-order/routes/custom-order.mjs.map +1 -0
- package/dist/server/custom-order/routes/index.js +13 -0
- package/dist/server/custom-order/routes/index.js.map +1 -0
- package/dist/server/custom-order/routes/index.mjs +11 -0
- package/dist/server/custom-order/routes/index.mjs.map +1 -0
- package/dist/server/custom-order/services/custom-order.js +286 -0
- package/dist/server/custom-order/services/custom-order.js.map +1 -0
- package/dist/server/custom-order/services/custom-order.mjs +284 -0
- package/dist/server/custom-order/services/custom-order.mjs.map +1 -0
- package/dist/server/custom-order/services/document-middleware.js +83 -0
- package/dist/server/custom-order/services/document-middleware.js.map +1 -0
- package/dist/server/custom-order/services/document-middleware.mjs +81 -0
- package/dist/server/custom-order/services/document-middleware.mjs.map +1 -0
- package/dist/server/custom-order/services/index.js +10 -0
- package/dist/server/custom-order/services/index.js.map +1 -0
- package/dist/server/custom-order/services/index.mjs +8 -0
- package/dist/server/custom-order/services/index.mjs.map +1 -0
- package/dist/server/custom-order/services/utils.js +152 -0
- package/dist/server/custom-order/services/utils.js.map +1 -0
- package/dist/server/custom-order/services/utils.mjs +148 -0
- package/dist/server/custom-order/services/utils.mjs.map +1 -0
- package/dist/server/custom-order/utils.js +13 -0
- package/dist/server/custom-order/utils.js.map +1 -0
- package/dist/server/custom-order/utils.mjs +10 -0
- package/dist/server/custom-order/utils.mjs.map +1 -0
- package/dist/server/history/constants.js +2 -1
- package/dist/server/history/constants.js.map +1 -1
- package/dist/server/history/constants.mjs +2 -1
- package/dist/server/history/constants.mjs.map +1 -1
- package/dist/server/history/controllers/history-version.js +6 -2
- package/dist/server/history/controllers/history-version.js.map +1 -1
- package/dist/server/history/controllers/history-version.mjs +6 -2
- package/dist/server/history/controllers/history-version.mjs.map +1 -1
- package/dist/server/history/services/history.js +23 -6
- package/dist/server/history/services/history.js.map +1 -1
- package/dist/server/history/services/history.mjs +24 -7
- package/dist/server/history/services/history.mjs.map +1 -1
- package/dist/server/history/services/lifecycles.js +2 -16
- package/dist/server/history/services/lifecycles.js.map +1 -1
- package/dist/server/history/services/lifecycles.mjs +2 -16
- package/dist/server/history/services/lifecycles.mjs.map +1 -1
- package/dist/server/register.js +4 -0
- package/dist/server/register.js.map +1 -1
- package/dist/server/register.mjs +4 -0
- package/dist/server/register.mjs.map +1 -1
- package/dist/server/routes/index.js +3 -1
- package/dist/server/routes/index.js.map +1 -1
- package/dist/server/routes/index.mjs +2 -0
- package/dist/server/routes/index.mjs.map +1 -1
- package/dist/server/services/content-types.js +2 -2
- package/dist/server/services/content-types.js.map +1 -1
- package/dist/server/services/content-types.mjs +2 -2
- package/dist/server/services/content-types.mjs.map +1 -1
- package/dist/server/services/document-manager.js +13 -0
- package/dist/server/services/document-manager.js.map +1 -1
- package/dist/server/services/document-manager.mjs +14 -1
- package/dist/server/services/document-manager.mjs.map +1 -1
- package/dist/server/services/index.js +3 -1
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/index.mjs +2 -0
- package/dist/server/services/index.mjs.map +1 -1
- package/dist/server/services/utils/configuration/settings.js +2 -1
- package/dist/server/services/utils/configuration/settings.js.map +1 -1
- package/dist/server/services/utils/configuration/settings.mjs +2 -1
- package/dist/server/services/utils/configuration/settings.mjs.map +1 -1
- package/dist/server/src/audit-logs.d.ts +40 -0
- package/dist/server/src/audit-logs.d.ts.map +1 -0
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/content-types.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +21 -3
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts +19 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/single-types.d.ts +1 -1
- package/dist/server/src/controllers/single-types.d.ts.map +1 -1
- package/dist/server/src/custom-order/constants.d.ts +18 -0
- package/dist/server/src/custom-order/constants.d.ts.map +1 -0
- package/dist/server/src/custom-order/controllers/custom-order.d.ts +8 -0
- package/dist/server/src/custom-order/controllers/custom-order.d.ts.map +1 -0
- package/dist/server/src/custom-order/controllers/index.d.ts +3 -0
- package/dist/server/src/custom-order/controllers/index.d.ts.map +1 -0
- package/dist/server/src/custom-order/index.d.ts +8 -0
- package/dist/server/src/custom-order/index.d.ts.map +1 -0
- package/dist/server/src/custom-order/routes/custom-order.d.ts +4 -0
- package/dist/server/src/custom-order/routes/custom-order.d.ts.map +1 -0
- package/dist/server/src/custom-order/routes/index.d.ts +10 -0
- package/dist/server/src/custom-order/routes/index.d.ts.map +1 -0
- package/dist/server/src/custom-order/services/custom-order.d.ts +43 -0
- package/dist/server/src/custom-order/services/custom-order.d.ts.map +1 -0
- package/dist/server/src/custom-order/services/document-middleware.d.ts +16 -0
- package/dist/server/src/custom-order/services/document-middleware.d.ts.map +1 -0
- package/dist/server/src/custom-order/services/index.d.ts +24 -0
- package/dist/server/src/custom-order/services/index.d.ts.map +1 -0
- package/dist/server/src/custom-order/services/utils.d.ts +34 -0
- package/dist/server/src/custom-order/services/utils.d.ts.map +1 -0
- package/dist/server/src/custom-order/utils.d.ts +6 -0
- package/dist/server/src/custom-order/utils.d.ts.map +1 -0
- package/dist/server/src/history/constants.d.ts.map +1 -1
- package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +22 -6
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/register.d.ts.map +1 -1
- package/dist/server/src/routes/index.d.ts.map +1 -1
- package/dist/server/src/services/content-types.d.ts +1 -3
- package/dist/server/src/services/content-types.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +1 -3
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/utils/configuration/settings.d.ts.map +1 -1
- package/dist/shared/contracts/content-types.d.ts +5 -0
- package/dist/shared/contracts/content-types.d.ts.map +1 -1
- package/dist/shared/contracts/custom-order.d.ts +33 -0
- package/dist/shared/contracts/custom-order.d.ts.map +1 -0
- package/dist/shared/contracts/custom-order.js +3 -0
- package/dist/shared/contracts/custom-order.js.map +1 -0
- package/dist/shared/contracts/custom-order.mjs +2 -0
- package/dist/shared/contracts/custom-order.mjs.map +1 -0
- package/dist/shared/contracts/history-versions.d.ts +0 -1
- package/dist/shared/contracts/history-versions.d.ts.map +1 -1
- package/dist/shared/contracts/index.d.ts +1 -0
- package/dist/shared/contracts/index.d.ts.map +1 -1
- package/dist/shared/contracts/index.js +2 -0
- package/dist/shared/contracts/index.js.map +1 -1
- package/dist/shared/contracts/index.mjs +2 -0
- package/dist/shared/contracts/index.mjs.map +1 -1
- package/package.json +8 -8
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var constants = require('../constants.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Works out how to place a document right before or after an anchor document.
|
|
7
|
+
*
|
|
8
|
+
* Positions are unique integers that may have gaps. Only the documents sitting between
|
|
9
|
+
* the moved document and the anchor are shifted, by one, towards the slot the moved
|
|
10
|
+
* document leaves behind.
|
|
11
|
+
*
|
|
12
|
+
* @returns null when the document is already in place.
|
|
13
|
+
*/ const computeMove = ({ from, anchor, placement })=>{
|
|
14
|
+
if (from === anchor) {
|
|
15
|
+
// Two documents should never share a position. If it happens anyway (e.g. concurrent
|
|
16
|
+
// writes), open a slot next to the anchor instead of relying on the slot left behind.
|
|
17
|
+
return placement === 'before' ? {
|
|
18
|
+
position: anchor,
|
|
19
|
+
shift: {
|
|
20
|
+
from: anchor,
|
|
21
|
+
to: null,
|
|
22
|
+
by: 1
|
|
23
|
+
}
|
|
24
|
+
} : {
|
|
25
|
+
position: anchor + 1,
|
|
26
|
+
shift: {
|
|
27
|
+
from: anchor + 1,
|
|
28
|
+
to: null,
|
|
29
|
+
by: 1
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const movingDown = from < anchor;
|
|
34
|
+
if (placement === 'before') {
|
|
35
|
+
if (movingDown) {
|
|
36
|
+
const position = anchor - 1;
|
|
37
|
+
return from === position ? null : {
|
|
38
|
+
position,
|
|
39
|
+
shift: {
|
|
40
|
+
from: from + 1,
|
|
41
|
+
to: position,
|
|
42
|
+
by: -1
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
position: anchor,
|
|
48
|
+
shift: {
|
|
49
|
+
from: anchor,
|
|
50
|
+
to: from - 1,
|
|
51
|
+
by: 1
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (movingDown) {
|
|
56
|
+
return {
|
|
57
|
+
position: anchor,
|
|
58
|
+
shift: {
|
|
59
|
+
from: from + 1,
|
|
60
|
+
to: anchor,
|
|
61
|
+
by: -1
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const position = anchor + 1;
|
|
66
|
+
return from === position ? null : {
|
|
67
|
+
position,
|
|
68
|
+
shift: {
|
|
69
|
+
from: position,
|
|
70
|
+
to: from - 1,
|
|
71
|
+
by: 1
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Whether a Document Service `sort` param is absent or empty.
|
|
77
|
+
*/ const isEmptySort = (sort)=>{
|
|
78
|
+
if (sort === undefined || sort === null || sort === '') {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
if (Array.isArray(sort)) {
|
|
82
|
+
return sort.length === 0;
|
|
83
|
+
}
|
|
84
|
+
if (typeof sort === 'object') {
|
|
85
|
+
return Object.keys(sort).length === 0;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
};
|
|
89
|
+
const parseSortEntry = (entry)=>{
|
|
90
|
+
if (typeof entry === 'string') {
|
|
91
|
+
const [field, direction] = entry.trim().split(':');
|
|
92
|
+
return field ? {
|
|
93
|
+
field,
|
|
94
|
+
direction: toDirection(direction)
|
|
95
|
+
} : null;
|
|
96
|
+
}
|
|
97
|
+
if (entry && typeof entry === 'object') {
|
|
98
|
+
const fields = Object.keys(entry);
|
|
99
|
+
const field = fields[fields.length - 1];
|
|
100
|
+
return field ? {
|
|
101
|
+
field,
|
|
102
|
+
direction: toDirection(entry[field])
|
|
103
|
+
} : null;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
};
|
|
107
|
+
const toDirection = (value)=>typeof value === 'string' && value.toLowerCase() === 'desc' ? 'desc' : 'asc';
|
|
108
|
+
/**
|
|
109
|
+
* Completes a sort that ends on the position with the `id` of the row.
|
|
110
|
+
*
|
|
111
|
+
* Positions alone don't make a total order: every row of a document shares its position,
|
|
112
|
+
* rows written outside of the Document Service have none, and without a tie-breaker each
|
|
113
|
+
* database would place those rows differently, and not always on the same page. Among
|
|
114
|
+
* equals the most recent row comes first, like new entries do.
|
|
115
|
+
*
|
|
116
|
+
* @returns the same `sort` when it does not end on the position.
|
|
117
|
+
*/ const toSortEntries = (sort)=>{
|
|
118
|
+
if (typeof sort === 'string') {
|
|
119
|
+
return sort.split(',');
|
|
120
|
+
}
|
|
121
|
+
return Array.isArray(sort) ? sort : [
|
|
122
|
+
sort
|
|
123
|
+
];
|
|
124
|
+
};
|
|
125
|
+
const withTieBreaker = (sort)=>{
|
|
126
|
+
const entries = toSortEntries(sort);
|
|
127
|
+
const last = parseSortEntry(entries[entries.length - 1]);
|
|
128
|
+
if (!last || last.field !== constants.POSITION_ATTRIBUTE) {
|
|
129
|
+
return sort;
|
|
130
|
+
}
|
|
131
|
+
const tieBreaker = last.direction === 'asc' ? 'desc' : 'asc';
|
|
132
|
+
if (typeof sort === 'string') {
|
|
133
|
+
return `${sort},id:${tieBreaker}`;
|
|
134
|
+
}
|
|
135
|
+
if (Array.isArray(sort)) {
|
|
136
|
+
return [
|
|
137
|
+
...sort,
|
|
138
|
+
typeof entries[entries.length - 1] === 'string' ? `id:${tieBreaker}` : {
|
|
139
|
+
id: tieBreaker
|
|
140
|
+
}
|
|
141
|
+
];
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
...sort,
|
|
145
|
+
id: tieBreaker
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
exports.computeMove = computeMove;
|
|
150
|
+
exports.isEmptySort = isEmptySort;
|
|
151
|
+
exports.withTieBreaker = withTieBreaker;
|
|
152
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../../server/src/custom-order/services/utils.ts"],"sourcesContent":["import { POSITION_ATTRIBUTE } from '../constants';\n\nexport type Placement = 'before' | 'after';\n\nexport interface MovePlan {\n /** New position of the moved document. */\n position: number;\n /**\n * Positions to shift to make room, bounds included. `to: null` means every position\n * from `from` upwards.\n */\n shift: { from: number; to: number | null; by: 1 | -1 } | null;\n}\n\n/**\n * Works out how to place a document right before or after an anchor document.\n *\n * Positions are unique integers that may have gaps. Only the documents sitting between\n * the moved document and the anchor are shifted, by one, towards the slot the moved\n * document leaves behind.\n *\n * @returns null when the document is already in place.\n */\nexport const computeMove = ({\n from,\n anchor,\n placement,\n}: {\n from: number;\n anchor: number;\n placement: Placement;\n}): MovePlan | null => {\n if (from === anchor) {\n // Two documents should never share a position. If it happens anyway (e.g. concurrent\n // writes), open a slot next to the anchor instead of relying on the slot left behind.\n return placement === 'before'\n ? { position: anchor, shift: { from: anchor, to: null, by: 1 } }\n : { position: anchor + 1, shift: { from: anchor + 1, to: null, by: 1 } };\n }\n\n const movingDown = from < anchor;\n\n if (placement === 'before') {\n if (movingDown) {\n const position = anchor - 1;\n\n return from === position\n ? null\n : { position, shift: { from: from + 1, to: position, by: -1 } };\n }\n\n return { position: anchor, shift: { from: anchor, to: from - 1, by: 1 } };\n }\n\n if (movingDown) {\n return { position: anchor, shift: { from: from + 1, to: anchor, by: -1 } };\n }\n\n const position = anchor + 1;\n\n return from === position ? null : { position, shift: { from: position, to: from - 1, by: 1 } };\n};\n\n/**\n * Whether a Document Service `sort` param is absent or empty.\n */\nexport const isEmptySort = (sort: unknown): boolean => {\n if (sort === undefined || sort === null || sort === '') {\n return true;\n }\n\n if (Array.isArray(sort)) {\n return sort.length === 0;\n }\n\n if (typeof sort === 'object') {\n return Object.keys(sort).length === 0;\n }\n\n return false;\n};\n\ntype Direction = 'asc' | 'desc';\n\nconst parseSortEntry = (entry: unknown): { field: string; direction: Direction } | null => {\n if (typeof entry === 'string') {\n const [field, direction] = entry.trim().split(':');\n\n return field ? { field, direction: toDirection(direction) } : null;\n }\n\n if (entry && typeof entry === 'object') {\n const fields = Object.keys(entry);\n const field = fields[fields.length - 1];\n\n return field\n ? { field, direction: toDirection((entry as Record<string, unknown>)[field]) }\n : null;\n }\n\n return null;\n};\n\nconst toDirection = (value: unknown): Direction =>\n typeof value === 'string' && value.toLowerCase() === 'desc' ? 'desc' : 'asc';\n\n/**\n * Completes a sort that ends on the position with the `id` of the row.\n *\n * Positions alone don't make a total order: every row of a document shares its position,\n * rows written outside of the Document Service have none, and without a tie-breaker each\n * database would place those rows differently, and not always on the same page. Among\n * equals the most recent row comes first, like new entries do.\n *\n * @returns the same `sort` when it does not end on the position.\n */\nconst toSortEntries = (sort: unknown): unknown[] => {\n if (typeof sort === 'string') {\n return sort.split(',');\n }\n\n return Array.isArray(sort) ? sort : [sort];\n};\n\nexport const withTieBreaker = (sort: unknown): unknown => {\n const entries = toSortEntries(sort);\n const last = parseSortEntry(entries[entries.length - 1]);\n\n if (!last || last.field !== POSITION_ATTRIBUTE) {\n return sort;\n }\n\n const tieBreaker: Direction = last.direction === 'asc' ? 'desc' : 'asc';\n\n if (typeof sort === 'string') {\n return `${sort},id:${tieBreaker}`;\n }\n\n if (Array.isArray(sort)) {\n return [\n ...sort,\n typeof entries[entries.length - 1] === 'string' ? `id:${tieBreaker}` : { id: tieBreaker },\n ];\n }\n\n return { ...(sort as Record<string, unknown>), id: tieBreaker };\n};\n"],"names":["computeMove","from","anchor","placement","position","shift","to","by","movingDown","isEmptySort","sort","undefined","Array","isArray","length","Object","keys","parseSortEntry","entry","field","direction","trim","split","toDirection","fields","value","toLowerCase","toSortEntries","withTieBreaker","entries","last","POSITION_ATTRIBUTE","tieBreaker","id"],"mappings":"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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { POSITION_ATTRIBUTE } from '../constants.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Works out how to place a document right before or after an anchor document.
|
|
5
|
+
*
|
|
6
|
+
* Positions are unique integers that may have gaps. Only the documents sitting between
|
|
7
|
+
* the moved document and the anchor are shifted, by one, towards the slot the moved
|
|
8
|
+
* document leaves behind.
|
|
9
|
+
*
|
|
10
|
+
* @returns null when the document is already in place.
|
|
11
|
+
*/ const computeMove = ({ from, anchor, placement })=>{
|
|
12
|
+
if (from === anchor) {
|
|
13
|
+
// Two documents should never share a position. If it happens anyway (e.g. concurrent
|
|
14
|
+
// writes), open a slot next to the anchor instead of relying on the slot left behind.
|
|
15
|
+
return placement === 'before' ? {
|
|
16
|
+
position: anchor,
|
|
17
|
+
shift: {
|
|
18
|
+
from: anchor,
|
|
19
|
+
to: null,
|
|
20
|
+
by: 1
|
|
21
|
+
}
|
|
22
|
+
} : {
|
|
23
|
+
position: anchor + 1,
|
|
24
|
+
shift: {
|
|
25
|
+
from: anchor + 1,
|
|
26
|
+
to: null,
|
|
27
|
+
by: 1
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const movingDown = from < anchor;
|
|
32
|
+
if (placement === 'before') {
|
|
33
|
+
if (movingDown) {
|
|
34
|
+
const position = anchor - 1;
|
|
35
|
+
return from === position ? null : {
|
|
36
|
+
position,
|
|
37
|
+
shift: {
|
|
38
|
+
from: from + 1,
|
|
39
|
+
to: position,
|
|
40
|
+
by: -1
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
position: anchor,
|
|
46
|
+
shift: {
|
|
47
|
+
from: anchor,
|
|
48
|
+
to: from - 1,
|
|
49
|
+
by: 1
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (movingDown) {
|
|
54
|
+
return {
|
|
55
|
+
position: anchor,
|
|
56
|
+
shift: {
|
|
57
|
+
from: from + 1,
|
|
58
|
+
to: anchor,
|
|
59
|
+
by: -1
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const position = anchor + 1;
|
|
64
|
+
return from === position ? null : {
|
|
65
|
+
position,
|
|
66
|
+
shift: {
|
|
67
|
+
from: position,
|
|
68
|
+
to: from - 1,
|
|
69
|
+
by: 1
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Whether a Document Service `sort` param is absent or empty.
|
|
75
|
+
*/ const isEmptySort = (sort)=>{
|
|
76
|
+
if (sort === undefined || sort === null || sort === '') {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
if (Array.isArray(sort)) {
|
|
80
|
+
return sort.length === 0;
|
|
81
|
+
}
|
|
82
|
+
if (typeof sort === 'object') {
|
|
83
|
+
return Object.keys(sort).length === 0;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
};
|
|
87
|
+
const parseSortEntry = (entry)=>{
|
|
88
|
+
if (typeof entry === 'string') {
|
|
89
|
+
const [field, direction] = entry.trim().split(':');
|
|
90
|
+
return field ? {
|
|
91
|
+
field,
|
|
92
|
+
direction: toDirection(direction)
|
|
93
|
+
} : null;
|
|
94
|
+
}
|
|
95
|
+
if (entry && typeof entry === 'object') {
|
|
96
|
+
const fields = Object.keys(entry);
|
|
97
|
+
const field = fields[fields.length - 1];
|
|
98
|
+
return field ? {
|
|
99
|
+
field,
|
|
100
|
+
direction: toDirection(entry[field])
|
|
101
|
+
} : null;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
};
|
|
105
|
+
const toDirection = (value)=>typeof value === 'string' && value.toLowerCase() === 'desc' ? 'desc' : 'asc';
|
|
106
|
+
/**
|
|
107
|
+
* Completes a sort that ends on the position with the `id` of the row.
|
|
108
|
+
*
|
|
109
|
+
* Positions alone don't make a total order: every row of a document shares its position,
|
|
110
|
+
* rows written outside of the Document Service have none, and without a tie-breaker each
|
|
111
|
+
* database would place those rows differently, and not always on the same page. Among
|
|
112
|
+
* equals the most recent row comes first, like new entries do.
|
|
113
|
+
*
|
|
114
|
+
* @returns the same `sort` when it does not end on the position.
|
|
115
|
+
*/ const toSortEntries = (sort)=>{
|
|
116
|
+
if (typeof sort === 'string') {
|
|
117
|
+
return sort.split(',');
|
|
118
|
+
}
|
|
119
|
+
return Array.isArray(sort) ? sort : [
|
|
120
|
+
sort
|
|
121
|
+
];
|
|
122
|
+
};
|
|
123
|
+
const withTieBreaker = (sort)=>{
|
|
124
|
+
const entries = toSortEntries(sort);
|
|
125
|
+
const last = parseSortEntry(entries[entries.length - 1]);
|
|
126
|
+
if (!last || last.field !== POSITION_ATTRIBUTE) {
|
|
127
|
+
return sort;
|
|
128
|
+
}
|
|
129
|
+
const tieBreaker = last.direction === 'asc' ? 'desc' : 'asc';
|
|
130
|
+
if (typeof sort === 'string') {
|
|
131
|
+
return `${sort},id:${tieBreaker}`;
|
|
132
|
+
}
|
|
133
|
+
if (Array.isArray(sort)) {
|
|
134
|
+
return [
|
|
135
|
+
...sort,
|
|
136
|
+
typeof entries[entries.length - 1] === 'string' ? `id:${tieBreaker}` : {
|
|
137
|
+
id: tieBreaker
|
|
138
|
+
}
|
|
139
|
+
];
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
...sort,
|
|
143
|
+
id: tieBreaker
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export { computeMove, isEmptySort, withTieBreaker };
|
|
148
|
+
//# sourceMappingURL=utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.mjs","sources":["../../../../server/src/custom-order/services/utils.ts"],"sourcesContent":["import { POSITION_ATTRIBUTE } from '../constants';\n\nexport type Placement = 'before' | 'after';\n\nexport interface MovePlan {\n /** New position of the moved document. */\n position: number;\n /**\n * Positions to shift to make room, bounds included. `to: null` means every position\n * from `from` upwards.\n */\n shift: { from: number; to: number | null; by: 1 | -1 } | null;\n}\n\n/**\n * Works out how to place a document right before or after an anchor document.\n *\n * Positions are unique integers that may have gaps. Only the documents sitting between\n * the moved document and the anchor are shifted, by one, towards the slot the moved\n * document leaves behind.\n *\n * @returns null when the document is already in place.\n */\nexport const computeMove = ({\n from,\n anchor,\n placement,\n}: {\n from: number;\n anchor: number;\n placement: Placement;\n}): MovePlan | null => {\n if (from === anchor) {\n // Two documents should never share a position. If it happens anyway (e.g. concurrent\n // writes), open a slot next to the anchor instead of relying on the slot left behind.\n return placement === 'before'\n ? { position: anchor, shift: { from: anchor, to: null, by: 1 } }\n : { position: anchor + 1, shift: { from: anchor + 1, to: null, by: 1 } };\n }\n\n const movingDown = from < anchor;\n\n if (placement === 'before') {\n if (movingDown) {\n const position = anchor - 1;\n\n return from === position\n ? null\n : { position, shift: { from: from + 1, to: position, by: -1 } };\n }\n\n return { position: anchor, shift: { from: anchor, to: from - 1, by: 1 } };\n }\n\n if (movingDown) {\n return { position: anchor, shift: { from: from + 1, to: anchor, by: -1 } };\n }\n\n const position = anchor + 1;\n\n return from === position ? null : { position, shift: { from: position, to: from - 1, by: 1 } };\n};\n\n/**\n * Whether a Document Service `sort` param is absent or empty.\n */\nexport const isEmptySort = (sort: unknown): boolean => {\n if (sort === undefined || sort === null || sort === '') {\n return true;\n }\n\n if (Array.isArray(sort)) {\n return sort.length === 0;\n }\n\n if (typeof sort === 'object') {\n return Object.keys(sort).length === 0;\n }\n\n return false;\n};\n\ntype Direction = 'asc' | 'desc';\n\nconst parseSortEntry = (entry: unknown): { field: string; direction: Direction } | null => {\n if (typeof entry === 'string') {\n const [field, direction] = entry.trim().split(':');\n\n return field ? { field, direction: toDirection(direction) } : null;\n }\n\n if (entry && typeof entry === 'object') {\n const fields = Object.keys(entry);\n const field = fields[fields.length - 1];\n\n return field\n ? { field, direction: toDirection((entry as Record<string, unknown>)[field]) }\n : null;\n }\n\n return null;\n};\n\nconst toDirection = (value: unknown): Direction =>\n typeof value === 'string' && value.toLowerCase() === 'desc' ? 'desc' : 'asc';\n\n/**\n * Completes a sort that ends on the position with the `id` of the row.\n *\n * Positions alone don't make a total order: every row of a document shares its position,\n * rows written outside of the Document Service have none, and without a tie-breaker each\n * database would place those rows differently, and not always on the same page. Among\n * equals the most recent row comes first, like new entries do.\n *\n * @returns the same `sort` when it does not end on the position.\n */\nconst toSortEntries = (sort: unknown): unknown[] => {\n if (typeof sort === 'string') {\n return sort.split(',');\n }\n\n return Array.isArray(sort) ? sort : [sort];\n};\n\nexport const withTieBreaker = (sort: unknown): unknown => {\n const entries = toSortEntries(sort);\n const last = parseSortEntry(entries[entries.length - 1]);\n\n if (!last || last.field !== POSITION_ATTRIBUTE) {\n return sort;\n }\n\n const tieBreaker: Direction = last.direction === 'asc' ? 'desc' : 'asc';\n\n if (typeof sort === 'string') {\n return `${sort},id:${tieBreaker}`;\n }\n\n if (Array.isArray(sort)) {\n return [\n ...sort,\n typeof entries[entries.length - 1] === 'string' ? `id:${tieBreaker}` : { id: tieBreaker },\n ];\n }\n\n return { ...(sort as Record<string, unknown>), id: tieBreaker };\n};\n"],"names":["computeMove","from","anchor","placement","position","shift","to","by","movingDown","isEmptySort","sort","undefined","Array","isArray","length","Object","keys","parseSortEntry","entry","field","direction","trim","split","toDirection","fields","value","toLowerCase","toSortEntries","withTieBreaker","entries","last","POSITION_ATTRIBUTE","tieBreaker","id"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var constants = require('./constants.js');
|
|
4
|
+
|
|
5
|
+
function getService(strapi, name) {
|
|
6
|
+
// Cast is needed because the return type of strapi.service is too vague
|
|
7
|
+
return strapi.service(`plugin::content-manager.${name}`);
|
|
8
|
+
}
|
|
9
|
+
const isFeatureEnabled = (strapi)=>strapi.features.future.isEnabled(constants.FUTURE_FLAG);
|
|
10
|
+
|
|
11
|
+
exports.getService = getService;
|
|
12
|
+
exports.isFeatureEnabled = isFeatureEnabled;
|
|
13
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../server/src/custom-order/utils.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { FUTURE_FLAG } from './constants';\n\ntype CustomOrderServices = typeof import('./services').services;\n\nfunction getService<T extends keyof CustomOrderServices>(strapi: Core.Strapi, name: T) {\n // Cast is needed because the return type of strapi.service is too vague\n return strapi.service(`plugin::content-manager.${name}`) as ReturnType<CustomOrderServices[T]>;\n}\n\nconst isFeatureEnabled = (strapi: Core.Strapi) => strapi.features.future.isEnabled(FUTURE_FLAG);\n\nexport { getService, isFeatureEnabled };\n"],"names":["getService","strapi","name","service","isFeatureEnabled","features","future","isEnabled","FUTURE_FLAG"],"mappings":";;;;AAMA,SAASA,UAAAA,CAAgDC,MAAmB,EAAEC,IAAO,EAAA;;AAEnF,IAAA,OAAOD,OAAOE,OAAO,CAAC,CAAC,wBAAwB,EAAED,IAAAA,CAAAA,CAAM,CAAA;AACzD;AAEA,MAAME,gBAAAA,GAAmB,CAACH,MAAAA,GAAwBA,MAAAA,CAAOI,QAAQ,CAACC,MAAM,CAACC,SAAS,CAACC,qBAAAA;;;;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FUTURE_FLAG } from './constants.mjs';
|
|
2
|
+
|
|
3
|
+
function getService(strapi, name) {
|
|
4
|
+
// Cast is needed because the return type of strapi.service is too vague
|
|
5
|
+
return strapi.service(`plugin::content-manager.${name}`);
|
|
6
|
+
}
|
|
7
|
+
const isFeatureEnabled = (strapi)=>strapi.features.future.isEnabled(FUTURE_FLAG);
|
|
8
|
+
|
|
9
|
+
export { getService, isFeatureEnabled };
|
|
10
|
+
//# sourceMappingURL=utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.mjs","sources":["../../../server/src/custom-order/utils.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { FUTURE_FLAG } from './constants';\n\ntype CustomOrderServices = typeof import('./services').services;\n\nfunction getService<T extends keyof CustomOrderServices>(strapi: Core.Strapi, name: T) {\n // Cast is needed because the return type of strapi.service is too vague\n return strapi.service(`plugin::content-manager.${name}`) as ReturnType<CustomOrderServices[T]>;\n}\n\nconst isFeatureEnabled = (strapi: Core.Strapi) => strapi.features.future.isEnabled(FUTURE_FLAG);\n\nexport { getService, isFeatureEnabled };\n"],"names":["getService","strapi","name","service","isFeatureEnabled","features","future","isEnabled","FUTURE_FLAG"],"mappings":";;AAMA,SAASA,UAAAA,CAAgDC,MAAmB,EAAEC,IAAO,EAAA;;AAEnF,IAAA,OAAOD,OAAOE,OAAO,CAAC,CAAC,wBAAwB,EAAED,IAAAA,CAAAA,CAAM,CAAA;AACzD;AAEA,MAAME,gBAAAA,GAAmB,CAACH,MAAAA,GAAwBA,MAAAA,CAAOI,QAAQ,CAACC,MAAM,CAACC,SAAS,CAACC,WAAAA;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sources":["../../../server/src/history/constants.ts"],"sourcesContent":["export const HISTORY_VERSION_UID = 'plugin::content-manager.history-version';\nexport const FIELDS_TO_IGNORE = [\n 'createdAt',\n 'updatedAt',\n 'publishedAt',\n 'createdBy',\n 'updatedBy',\n 'strapi_stage',\n 'strapi_assignee',\n];\n"],"names":["HISTORY_VERSION_UID","FIELDS_TO_IGNORE"],"mappings":";;AAAO,MAAMA,sBAAsB;MACtBC,gBAAAA,GAAmB;AAC9B,IAAA,WAAA;AACA,IAAA,WAAA;AACA,IAAA,aAAA;AACA,IAAA,WAAA;AACA,IAAA,WAAA;AACA,IAAA,cAAA;AACA,IAAA;;;;;;"}
|
|
1
|
+
{"version":3,"file":"constants.js","sources":["../../../server/src/history/constants.ts"],"sourcesContent":["export const HISTORY_VERSION_UID = 'plugin::content-manager.history-version';\nexport const FIELDS_TO_IGNORE = [\n 'createdAt',\n 'updatedAt',\n 'publishedAt',\n 'createdBy',\n 'updatedBy',\n 'strapi_stage',\n 'strapi_assignee',\n 'strapi_position',\n];\n"],"names":["HISTORY_VERSION_UID","FIELDS_TO_IGNORE"],"mappings":";;AAAO,MAAMA,sBAAsB;MACtBC,gBAAAA,GAAmB;AAC9B,IAAA,WAAA;AACA,IAAA,WAAA;AACA,IAAA,aAAA;AACA,IAAA,WAAA;AACA,IAAA,WAAA;AACA,IAAA,cAAA;AACA,IAAA,iBAAA;AACA,IAAA;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.mjs","sources":["../../../server/src/history/constants.ts"],"sourcesContent":["export const HISTORY_VERSION_UID = 'plugin::content-manager.history-version';\nexport const FIELDS_TO_IGNORE = [\n 'createdAt',\n 'updatedAt',\n 'publishedAt',\n 'createdBy',\n 'updatedBy',\n 'strapi_stage',\n 'strapi_assignee',\n];\n"],"names":["HISTORY_VERSION_UID","FIELDS_TO_IGNORE"],"mappings":"AAAO,MAAMA,sBAAsB;MACtBC,gBAAAA,GAAmB;AAC9B,IAAA,WAAA;AACA,IAAA,WAAA;AACA,IAAA,aAAA;AACA,IAAA,WAAA;AACA,IAAA,WAAA;AACA,IAAA,cAAA;AACA,IAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"constants.mjs","sources":["../../../server/src/history/constants.ts"],"sourcesContent":["export const HISTORY_VERSION_UID = 'plugin::content-manager.history-version';\nexport const FIELDS_TO_IGNORE = [\n 'createdAt',\n 'updatedAt',\n 'publishedAt',\n 'createdBy',\n 'updatedBy',\n 'strapi_stage',\n 'strapi_assignee',\n 'strapi_position',\n];\n"],"names":["HISTORY_VERSION_UID","FIELDS_TO_IGNORE"],"mappings":"AAAO,MAAMA,sBAAsB;MACtBC,gBAAAA,GAAmB;AAC9B,IAAA,WAAA;AACA,IAAA,WAAA;AACA,IAAA,aAAA;AACA,IAAA,WAAA;AACA,IAAA,WAAA;AACA,IAAA,cAAA;AACA,IAAA,iBAAA;AACA,IAAA;;;;;"}
|
|
@@ -13,7 +13,6 @@ var historyVersion = require('./validation/history-version.js');
|
|
|
13
13
|
let pageSizeNumber = 20;
|
|
14
14
|
if (page) {
|
|
15
15
|
const parsedPage = parseInt(page, 10);
|
|
16
|
-
pageNumber = parseInt(page, 10);
|
|
17
16
|
if (!Number.isNaN(parsedPage) && parsedPage >= 1) {
|
|
18
17
|
pageNumber = parsedPage;
|
|
19
18
|
}
|
|
@@ -93,7 +92,12 @@ const createHistoryVersionController = ({ strapi })=>{
|
|
|
93
92
|
if (permissionChecker.cannot.update()) {
|
|
94
93
|
throw new strapiUtils.errors.ForbiddenError();
|
|
95
94
|
}
|
|
96
|
-
|
|
95
|
+
// Version ids are positive integers, other values cannot match a version
|
|
96
|
+
const versionId = Number(request.params.versionId);
|
|
97
|
+
if (Number.isInteger(versionId) === false || versionId < 1) {
|
|
98
|
+
throw new strapiUtils.errors.NotFoundError('History version not found');
|
|
99
|
+
}
|
|
100
|
+
const restoredDocument = await utils.getService(strapi, 'history').restoreVersion(versionId);
|
|
97
101
|
return {
|
|
98
102
|
data: {
|
|
99
103
|
documentId: restoredDocument.documentId
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history-version.js","sources":["../../../../server/src/history/controllers/history-version.ts"],"sourcesContent":["import { async, errors } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport { pick } from 'lodash';\n\nimport { getService as getContentManagerService } from '../../utils';\nimport { getService } from '../utils';\nimport type { HistoryVersions } from '../../../../shared/contracts';\nimport { validateRestoreVersion } from './validation/history-version';\n\n/**\n * Parses pagination params and makes sure they're within valid ranges\n */\nconst getValidPagination = ({ page, pageSize }: { page: any; pageSize: any }) => {\n let pageNumber = 1;\n let pageSizeNumber = 20;\n\n if (page) {\n const parsedPage = parseInt(page, 10);\n
|
|
1
|
+
{"version":3,"file":"history-version.js","sources":["../../../../server/src/history/controllers/history-version.ts"],"sourcesContent":["import { async, errors } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport { pick } from 'lodash';\n\nimport { getService as getContentManagerService } from '../../utils';\nimport { getService } from '../utils';\nimport type { HistoryVersions } from '../../../../shared/contracts';\nimport { validateRestoreVersion } from './validation/history-version';\n\n/**\n * Parses pagination params and makes sure they're within valid ranges\n */\nconst getValidPagination = ({ page, pageSize }: { page: any; pageSize: any }) => {\n let pageNumber = 1;\n let pageSizeNumber = 20;\n\n if (page) {\n const parsedPage = parseInt(page, 10);\n\n if (!Number.isNaN(parsedPage) && parsedPage >= 1) {\n pageNumber = parsedPage;\n }\n }\n\n if (pageSize) {\n const parsedPageSize = parseInt(pageSize, 10);\n\n if (!Number.isNaN(parsedPageSize) && parsedPageSize >= 1 && parsedPageSize <= 100) {\n pageSizeNumber = parsedPageSize;\n }\n }\n\n return { page: pageNumber, pageSize: pageSizeNumber };\n};\n\nconst createHistoryVersionController = ({ strapi }: { strapi: Core.Strapi }) => {\n return {\n async findMany(ctx) {\n const contentTypeUid = ctx.query.contentType as UID.ContentType;\n const isSingleType = strapi.getModel(contentTypeUid)?.kind === 'singleType';\n\n if (isSingleType && !contentTypeUid) {\n throw new errors.ForbiddenError('contentType is required');\n }\n\n if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {\n throw new errors.ForbiddenError('contentType and documentId are required');\n }\n\n /**\n * There are no permissions specifically for history versions,\n * but we need to check that the user can read the content type\n */\n const permissionChecker = getContentManagerService('permission-checker').create({\n userAbility: ctx.state.userAbility,\n model: ctx.query.contentType,\n });\n\n if (permissionChecker.cannot.read()) {\n return ctx.forbidden();\n }\n\n const query: HistoryVersions.GetHistoryVersions.Request['query'] =\n await permissionChecker.sanitizeQuery(ctx.query);\n\n const { results, pagination } = await getService(strapi, 'history').findVersionsPage({\n query: {\n ...query,\n ...getValidPagination({ page: query.page, pageSize: query.pageSize }),\n },\n state: { userAbility: ctx.state.userAbility },\n });\n\n const sanitizedResults = await async.map(\n results,\n async (version: HistoryVersions.HistoryVersionDataResponse & { locale: string }) => {\n return {\n ...version,\n data: await permissionChecker.sanitizeOutput(version.data),\n createdBy: version.createdBy\n ? pick(version.createdBy, ['id', 'firstname', 'lastname', 'username', 'email'])\n : undefined,\n };\n }\n );\n\n return {\n data: sanitizedResults,\n meta: { pagination },\n };\n },\n\n async restoreVersion(ctx) {\n const request = ctx.request as unknown as HistoryVersions.RestoreHistoryVersion.Request;\n\n await validateRestoreVersion(request.body, 'contentType is required');\n\n const permissionChecker = getContentManagerService('permission-checker').create({\n userAbility: ctx.state.userAbility,\n model: request.body.contentType,\n });\n\n if (permissionChecker.cannot.update()) {\n throw new errors.ForbiddenError();\n }\n\n // Version ids are positive integers, other values cannot match a version\n const versionId = Number(request.params.versionId);\n if (Number.isInteger(versionId) === false || versionId < 1) {\n throw new errors.NotFoundError('History version not found');\n }\n\n const restoredDocument = await getService(strapi, 'history').restoreVersion(versionId);\n\n return {\n data: { documentId: restoredDocument.documentId },\n } satisfies HistoryVersions.RestoreHistoryVersion.Response;\n },\n } satisfies Core.Controller;\n};\n\nexport { createHistoryVersionController };\n"],"names":["getValidPagination","page","pageSize","pageNumber","pageSizeNumber","parsedPage","parseInt","Number","isNaN","parsedPageSize","createHistoryVersionController","strapi","findMany","ctx","contentTypeUid","query","contentType","isSingleType","getModel","kind","errors","ForbiddenError","documentId","permissionChecker","getContentManagerService","create","userAbility","state","model","cannot","read","forbidden","sanitizeQuery","results","pagination","getService","findVersionsPage","sanitizedResults","async","map","version","data","sanitizeOutput","createdBy","pick","undefined","meta","restoreVersion","request","validateRestoreVersion","body","update","versionId","params","isInteger","NotFoundError","restoredDocument"],"mappings":"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"}
|
|
@@ -11,7 +11,6 @@ import { validateRestoreVersion } from './validation/history-version.mjs';
|
|
|
11
11
|
let pageSizeNumber = 20;
|
|
12
12
|
if (page) {
|
|
13
13
|
const parsedPage = parseInt(page, 10);
|
|
14
|
-
pageNumber = parseInt(page, 10);
|
|
15
14
|
if (!Number.isNaN(parsedPage) && parsedPage >= 1) {
|
|
16
15
|
pageNumber = parsedPage;
|
|
17
16
|
}
|
|
@@ -91,7 +90,12 @@ const createHistoryVersionController = ({ strapi })=>{
|
|
|
91
90
|
if (permissionChecker.cannot.update()) {
|
|
92
91
|
throw new errors.ForbiddenError();
|
|
93
92
|
}
|
|
94
|
-
|
|
93
|
+
// Version ids are positive integers, other values cannot match a version
|
|
94
|
+
const versionId = Number(request.params.versionId);
|
|
95
|
+
if (Number.isInteger(versionId) === false || versionId < 1) {
|
|
96
|
+
throw new errors.NotFoundError('History version not found');
|
|
97
|
+
}
|
|
98
|
+
const restoredDocument = await getService$1(strapi, 'history').restoreVersion(versionId);
|
|
95
99
|
return {
|
|
96
100
|
data: {
|
|
97
101
|
documentId: restoredDocument.documentId
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history-version.mjs","sources":["../../../../server/src/history/controllers/history-version.ts"],"sourcesContent":["import { async, errors } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport { pick } from 'lodash';\n\nimport { getService as getContentManagerService } from '../../utils';\nimport { getService } from '../utils';\nimport type { HistoryVersions } from '../../../../shared/contracts';\nimport { validateRestoreVersion } from './validation/history-version';\n\n/**\n * Parses pagination params and makes sure they're within valid ranges\n */\nconst getValidPagination = ({ page, pageSize }: { page: any; pageSize: any }) => {\n let pageNumber = 1;\n let pageSizeNumber = 20;\n\n if (page) {\n const parsedPage = parseInt(page, 10);\n
|
|
1
|
+
{"version":3,"file":"history-version.mjs","sources":["../../../../server/src/history/controllers/history-version.ts"],"sourcesContent":["import { async, errors } from '@strapi/utils';\nimport type { Core, UID } from '@strapi/types';\nimport { pick } from 'lodash';\n\nimport { getService as getContentManagerService } from '../../utils';\nimport { getService } from '../utils';\nimport type { HistoryVersions } from '../../../../shared/contracts';\nimport { validateRestoreVersion } from './validation/history-version';\n\n/**\n * Parses pagination params and makes sure they're within valid ranges\n */\nconst getValidPagination = ({ page, pageSize }: { page: any; pageSize: any }) => {\n let pageNumber = 1;\n let pageSizeNumber = 20;\n\n if (page) {\n const parsedPage = parseInt(page, 10);\n\n if (!Number.isNaN(parsedPage) && parsedPage >= 1) {\n pageNumber = parsedPage;\n }\n }\n\n if (pageSize) {\n const parsedPageSize = parseInt(pageSize, 10);\n\n if (!Number.isNaN(parsedPageSize) && parsedPageSize >= 1 && parsedPageSize <= 100) {\n pageSizeNumber = parsedPageSize;\n }\n }\n\n return { page: pageNumber, pageSize: pageSizeNumber };\n};\n\nconst createHistoryVersionController = ({ strapi }: { strapi: Core.Strapi }) => {\n return {\n async findMany(ctx) {\n const contentTypeUid = ctx.query.contentType as UID.ContentType;\n const isSingleType = strapi.getModel(contentTypeUid)?.kind === 'singleType';\n\n if (isSingleType && !contentTypeUid) {\n throw new errors.ForbiddenError('contentType is required');\n }\n\n if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {\n throw new errors.ForbiddenError('contentType and documentId are required');\n }\n\n /**\n * There are no permissions specifically for history versions,\n * but we need to check that the user can read the content type\n */\n const permissionChecker = getContentManagerService('permission-checker').create({\n userAbility: ctx.state.userAbility,\n model: ctx.query.contentType,\n });\n\n if (permissionChecker.cannot.read()) {\n return ctx.forbidden();\n }\n\n const query: HistoryVersions.GetHistoryVersions.Request['query'] =\n await permissionChecker.sanitizeQuery(ctx.query);\n\n const { results, pagination } = await getService(strapi, 'history').findVersionsPage({\n query: {\n ...query,\n ...getValidPagination({ page: query.page, pageSize: query.pageSize }),\n },\n state: { userAbility: ctx.state.userAbility },\n });\n\n const sanitizedResults = await async.map(\n results,\n async (version: HistoryVersions.HistoryVersionDataResponse & { locale: string }) => {\n return {\n ...version,\n data: await permissionChecker.sanitizeOutput(version.data),\n createdBy: version.createdBy\n ? pick(version.createdBy, ['id', 'firstname', 'lastname', 'username', 'email'])\n : undefined,\n };\n }\n );\n\n return {\n data: sanitizedResults,\n meta: { pagination },\n };\n },\n\n async restoreVersion(ctx) {\n const request = ctx.request as unknown as HistoryVersions.RestoreHistoryVersion.Request;\n\n await validateRestoreVersion(request.body, 'contentType is required');\n\n const permissionChecker = getContentManagerService('permission-checker').create({\n userAbility: ctx.state.userAbility,\n model: request.body.contentType,\n });\n\n if (permissionChecker.cannot.update()) {\n throw new errors.ForbiddenError();\n }\n\n // Version ids are positive integers, other values cannot match a version\n const versionId = Number(request.params.versionId);\n if (Number.isInteger(versionId) === false || versionId < 1) {\n throw new errors.NotFoundError('History version not found');\n }\n\n const restoredDocument = await getService(strapi, 'history').restoreVersion(versionId);\n\n return {\n data: { documentId: restoredDocument.documentId },\n } satisfies HistoryVersions.RestoreHistoryVersion.Response;\n },\n } satisfies Core.Controller;\n};\n\nexport { createHistoryVersionController };\n"],"names":["getValidPagination","page","pageSize","pageNumber","pageSizeNumber","parsedPage","parseInt","Number","isNaN","parsedPageSize","createHistoryVersionController","strapi","findMany","ctx","contentTypeUid","query","contentType","isSingleType","getModel","kind","errors","ForbiddenError","documentId","permissionChecker","getContentManagerService","create","userAbility","state","model","cannot","read","forbidden","sanitizeQuery","results","pagination","getService","findVersionsPage","sanitizedResults","async","map","version","data","sanitizeOutput","createdBy","pick","undefined","meta","restoreVersion","request","validateRestoreVersion","body","update","versionId","params","isInteger","NotFoundError","restoredDocument"],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ var _ = require('lodash');
|
|
|
5
5
|
var constants = require('../constants.js');
|
|
6
6
|
var utils = require('./utils.js');
|
|
7
7
|
var index = require('../../utils/index.js');
|
|
8
|
+
var auditLogs = require('../../audit-logs.js');
|
|
8
9
|
|
|
9
10
|
const createHistoryService = ({ strapi })=>{
|
|
10
11
|
const query = strapi.db.query(constants.HISTORY_VERSION_UID);
|
|
@@ -80,15 +81,16 @@ const createHistoryService = ({ strapi })=>{
|
|
|
80
81
|
const results = ids.map((id)=>versionsById.get(id)).filter(Boolean);
|
|
81
82
|
const populateEntry = async (entry)=>{
|
|
82
83
|
return strapiUtils.traverseEntity(async (options, utils)=>{
|
|
84
|
+
if (options.key === 'id' && options.schema.modelType === 'component') {
|
|
85
|
+
// Ids on components throw an error when restoring
|
|
86
|
+
utils.remove('id');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
83
89
|
if (!options.attribute) return;
|
|
84
90
|
if (!options.value) return;
|
|
85
91
|
const currentValue = Array.isArray(options.value) ? options.value : [
|
|
86
92
|
options.value
|
|
87
93
|
];
|
|
88
|
-
if (options.attribute.type === 'component') {
|
|
89
|
-
// Ids on components throw an error when restoring
|
|
90
|
-
utils.remove('id');
|
|
91
|
-
}
|
|
92
94
|
if (options.attribute.type === 'relation' && // TODO: handle polymorphic relations
|
|
93
95
|
options.attribute.relation !== 'morphToOne' && options.attribute.relation !== 'morphToMany') {
|
|
94
96
|
if (options.attribute.target === 'admin::user') {
|
|
@@ -158,6 +160,9 @@ const createHistoryService = ({ strapi })=>{
|
|
|
158
160
|
id: versionId
|
|
159
161
|
}
|
|
160
162
|
});
|
|
163
|
+
if (version === null) {
|
|
164
|
+
throw new strapiUtils.errors.NotFoundError('History version not found');
|
|
165
|
+
}
|
|
161
166
|
const contentTypeSchemaAttributes = strapi.getModel(version.contentType).attributes;
|
|
162
167
|
const schemaDiff = serviceUtils.getSchemaAttributesDiff(version.schema, contentTypeSchemaAttributes);
|
|
163
168
|
// Set all added attribute values to null
|
|
@@ -170,10 +175,13 @@ const createHistoryService = ({ strapi })=>{
|
|
|
170
175
|
const schema = structuredClone(version.schema);
|
|
171
176
|
schema.attributes = _.omit(contentTypeSchemaAttributes, constants.FIELDS_TO_IGNORE);
|
|
172
177
|
const dataWithoutMissingRelations = await strapiUtils.traverseEntity(async (options, utils)=>{
|
|
173
|
-
if (
|
|
174
|
-
if (options.attribute.type === 'component') {
|
|
178
|
+
if (options.key === 'id' && options.schema.modelType === 'component') {
|
|
175
179
|
// Ids on components throw an error when restoring
|
|
176
180
|
utils.remove('id');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (!options.attribute) return;
|
|
184
|
+
if (options.attribute.type === 'component') {
|
|
177
185
|
if (options.attribute.repeatable && options.value === null) {
|
|
178
186
|
// Repeatable Components should always be an array
|
|
179
187
|
utils.set(options.key, []);
|
|
@@ -212,6 +220,15 @@ const createHistoryService = ({ strapi })=>{
|
|
|
212
220
|
if (!restoredDocument) {
|
|
213
221
|
throw new strapiUtils.errors.ApplicationError('Failed to restore version');
|
|
214
222
|
}
|
|
223
|
+
await strapiUtils.emitAudit({
|
|
224
|
+
strapi
|
|
225
|
+
}, auditLogs.AUDITED_EVENTS.ENTRY_HISTORY_RESTORE, {
|
|
226
|
+
uid: version.contentType,
|
|
227
|
+
documentId: restoredDocument.documentId,
|
|
228
|
+
locale: version.locale ?? null,
|
|
229
|
+
versionId: version.id,
|
|
230
|
+
versionCreatedAt: new Date(version.createdAt).toISOString()
|
|
231
|
+
});
|
|
215
232
|
return restoredDocument;
|
|
216
233
|
}
|
|
217
234
|
};
|