@retikolo/drag-drop-content-types 1.3.11 → 1.4.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/.prettierrc ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "tabWidth": 2,
3
+ "useTabs": false,
4
+ "singleQuote": true,
5
+ "semi": true,
6
+ "trailingComma": "es5"
7
+ }
package/README.md CHANGED
@@ -47,3 +47,7 @@ http://localhost:1337/api/foo?sort=rank:asc
47
47
 
48
48
  ## 🤝 Contribute
49
49
  Feel free to fork and make pull requests to this plugin. All input is welcome - thanks for all contributions so far!
50
+
51
+
52
+ ## ⭐️ Support
53
+ I you like this project, please give it a star. Maybe this will help it getting integrated to strapi's core some day 😊.
@@ -126,6 +126,7 @@ const SortModal = () => {
126
126
  try {
127
127
  // Increase performance by breaking loop after last element having a rank change is updated
128
128
  const sortedList = arrayMoveImmutable(data, oldIndex, newIndex);
129
+ const rankUpdates = [];
129
130
  let rankHasChanged = false;
130
131
  // Iterate over all results and append them to the list
131
132
  for (let i = 0; i < sortedList.length; i++) {
@@ -133,20 +134,23 @@ const SortModal = () => {
133
134
  if (sortedList[i].id != data[i].id) {
134
135
  const newRank =
135
136
  parseInt(pageSize * (currentPage - 1) + i) || 0;
136
- // Update rank via put request
137
- await axiosInstance.put(
138
- `/drag-drop-content-types/sort-update/${sortedList[i].id}`,
139
- {
140
- contentType: contentTypePath,
141
- rankFieldName: settings.rank,
142
- rank: newRank,
143
- }
144
- );
137
+ const update = {
138
+ id: sortedList[i].id,
139
+ rank: newRank,
140
+ };
141
+ rankUpdates.push(update);
145
142
  rankHasChanged = true;
146
143
  } else if (rankHasChanged) {
147
144
  break;
148
145
  }
149
146
  }
147
+
148
+ // Batch Update DB with new ranks
149
+ await axiosInstance.put("/drag-drop-content-types/batch-update", {
150
+ contentType: contentTypePath,
151
+ updates: rankUpdates,
152
+ });
153
+
150
154
  // distinguish last page from full/first page
151
155
  let sortedListViewEntries =
152
156
  currentPage == 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retikolo/drag-drop-content-types",
3
- "version": "1.3.11",
3
+ "version": "1.4.0",
4
4
  "description": "This plugin add a drag and droppable list that allows you to sort content type entries.",
5
5
  "strapi": {
6
6
  "name": "drag-drop-content-types",
@@ -17,7 +17,8 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "array-move": "^4.0.0",
20
- "react-sortable-hoc": "^2.0.0"
20
+ "react-sortable-hoc": "^2.0.0",
21
+ "zod": "^3.20.2"
21
22
  },
22
23
  "author": {
23
24
  "name": "Aeneas Meier",
@@ -1,5 +1,8 @@
1
+ // @ts-check
1
2
  'use strict';
2
3
 
4
+ const { z } = require('zod');
5
+
3
6
  // Get the store from the drag-drop plugin
4
7
  function getPluginStore() {
5
8
  return strapi.store({
@@ -17,6 +20,7 @@ async function createDefaultConfig() {
17
20
  rank: 'rank',
18
21
  title: '',
19
22
  }
23
+
20
24
  };
21
25
  await pluginStore.set({ key: 'settings', value });
22
26
  return pluginStore.get({ key: 'settings' });
@@ -43,7 +47,7 @@ async function setSettings(settings) {
43
47
  // Search for entries ordered by rank
44
48
  async function index(contentType, start, limit, locale, rankFieldName) {
45
49
  let indexData = {
46
- sort: { },
50
+ sort: {},
47
51
  populate: '*',
48
52
  start: start,
49
53
  limit: limit,
@@ -51,7 +55,7 @@ async function index(contentType, start, limit, locale, rankFieldName) {
51
55
  }
52
56
  indexData.sort[rankFieldName] = 'asc'
53
57
  try {
54
- return await strapi.entityService.findMany(contentType, indexData );
58
+ return await strapi.entityService.findMany(contentType, indexData);
55
59
  } catch (err) {
56
60
  return {};
57
61
  }
@@ -67,6 +71,40 @@ async function update(id, contentType, rank, rankFieldName) {
67
71
  return await strapi.query(contentType).update(updateData);
68
72
  }
69
73
 
74
+ /**
75
+ *
76
+ * @param {RankUpdate[]} updates
77
+ * @param {string} contentType
78
+ */
79
+ async function batchUpdate(updates, contentType) {
80
+ const config = await getSettings();
81
+ const sortFieldName = config.body.rank;
82
+ const results = [];
83
+
84
+ for (const update of updates) {
85
+ // update entry's rank in db
86
+ try {
87
+ const updatedEntry = await strapi.db.query(contentType).update({
88
+ where: { id: update.id },
89
+ data: {
90
+ [sortFieldName]: update.rank,
91
+ },
92
+ });
93
+ updatedEntry?.id && results.push(updatedEntry);
94
+ } catch (err) {
95
+ console.log(err);
96
+ }
97
+ }
98
+ if (results?.length !== updates?.length) {
99
+ throw new Error('Error updating rank entries.');
100
+ } else {
101
+ return results.map((entry) => ({
102
+ id: entry.id,
103
+ rank: entry[sortFieldName],
104
+ }));
105
+ }
106
+ }
107
+
70
108
  module.exports = {
71
109
  async getSettings(ctx) {
72
110
  try {
@@ -98,4 +136,33 @@ module.exports = {
98
136
  ctx.throw(500, err);
99
137
  }
100
138
  },
101
- };
139
+ async batchUpdate(ctx) {
140
+ try {
141
+ const payload = await BatchUpdateRequestSchema.parseAsync(
142
+ ctx.request.body
143
+ );
144
+ try {
145
+ ctx.body = await batchUpdate(payload.updates, payload.contentType);
146
+ } catch (err) {
147
+ ctx.throw(500, err);
148
+ }
149
+ } catch (err) {
150
+ ctx.throw(400, err);
151
+ }
152
+ },
153
+ };
154
+
155
+ // TYPE-SAFETY AND VALIDATION
156
+
157
+ // Request schema used for parsing/validating incoming API requests. Uses Zod which works well with Typescript if used in the future.
158
+ const RankUpdateSchema = z.object({
159
+ id: z.number(),
160
+ rank: z.number(),
161
+ });
162
+ const BatchUpdateRequestSchema = z.object({
163
+ contentType: z.string(),
164
+ updates: z.array(RankUpdateSchema),
165
+ });
166
+
167
+ // Try to enforce Typescript types in Javascript using JSDoc
168
+ /** @typedef { z.infer<typeof RankUpdateSchema> } RankUpdate */
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  module.exports = {
4
2
  type: 'admin',
5
3
  routes: [
@@ -22,22 +20,31 @@ module.exports = {
22
20
  },
23
21
  },
24
22
  {
25
- method: "POST",
26
- path: "/sort-index",
27
- handler: "sort.index",
23
+ method: 'POST',
24
+ path: '/sort-index',
25
+ handler: 'sort.index',
26
+ config: {
27
+ policies: [],
28
+ auth: false,
29
+ },
30
+ },
31
+ {
32
+ method: 'PUT',
33
+ path: '/batch-update',
34
+ handler: 'sort.batchUpdate',
28
35
  config: {
29
36
  policies: [],
30
37
  auth: false,
31
38
  },
32
39
  },
33
40
  {
34
- method: "PUT",
35
- path: "/sort-update/:id",
36
- handler: "sort.update",
41
+ method: 'PUT',
42
+ path: '/sort-update/:id',
43
+ handler: 'sort.update',
37
44
  config: {
38
45
  policies: [],
39
46
  auth: false,
40
47
  },
41
48
  },
42
49
  ],
43
- };
50
+ };