@nkhang1902/strapi-plugin-export-import-clsx 1.3.9 → 1.4.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.
|
@@ -6,6 +6,7 @@ import { Download, Upload } from "@strapi/icons";
|
|
|
6
6
|
import { useNotification } from "@strapi/strapi/admin";
|
|
7
7
|
|
|
8
8
|
const ExportImportButtons = (props) => {
|
|
9
|
+
const { isExpParticipantsExporting } = props;
|
|
9
10
|
const [isExporting, setIsExporting] = useState(false);
|
|
10
11
|
const [isImporting, setIsImporting] = useState(false);
|
|
11
12
|
const { toggleNotification } = useNotification();
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { useState, useRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
} from "@strapi/design-system";
|
|
5
|
+
import { Download, Upload } from "@strapi/icons";
|
|
6
|
+
import { useNotification } from "@strapi/strapi/admin";
|
|
7
|
+
|
|
8
|
+
const ExportButtonsEditView = (props) => {
|
|
9
|
+
const [isExporting, setIsExporting] = useState(false);
|
|
10
|
+
const { toggleNotification } = useNotification();
|
|
11
|
+
const allowedContentTypes = [
|
|
12
|
+
"api::site-visit.site-visit",
|
|
13
|
+
"api::lunch-attending.lunch-attending",
|
|
14
|
+
"api::experience-networking.experience-networking",
|
|
15
|
+
"api::tour.tour",
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
// Get current content type from props or URL
|
|
19
|
+
const getContentType = () => {
|
|
20
|
+
if (props.layout?.uid) {
|
|
21
|
+
return props.layout.uid;
|
|
22
|
+
}
|
|
23
|
+
// Fallback: extract from URL - handle both content-manager and event-manager
|
|
24
|
+
const path = window.location.pathname;
|
|
25
|
+
|
|
26
|
+
// For event-manager plugin
|
|
27
|
+
const eventManagerMatch = path.match(
|
|
28
|
+
/\/admin\/plugins\/event-manager\/([^\/]+)\/([^\/]+)/
|
|
29
|
+
);
|
|
30
|
+
if (eventManagerMatch) {
|
|
31
|
+
return eventManagerMatch[2]; // Return the collectionType, not the eventId
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// For content-manager
|
|
35
|
+
const contentManagerMatch = path.match(
|
|
36
|
+
/\/admin\/content-manager\/collection-types\/([^\/]+)/
|
|
37
|
+
);
|
|
38
|
+
if (contentManagerMatch) {
|
|
39
|
+
return contentManagerMatch[1];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return null;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Get event filter for event manager - simplified with exclude list
|
|
46
|
+
const getEventFilter = () => {
|
|
47
|
+
const path = window.location.pathname;
|
|
48
|
+
const eventManagerMatch = path.match(
|
|
49
|
+
/\/admin\/plugins\/event-manager\/([^\/]+)\/([^\/]+)/
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (eventManagerMatch) {
|
|
53
|
+
const eventId = eventManagerMatch[1];
|
|
54
|
+
const collectionType = eventManagerMatch[2];
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
eventId &&
|
|
58
|
+
eventId !== "events" &&
|
|
59
|
+
allowedContentTypes.includes(collectionType)
|
|
60
|
+
) {
|
|
61
|
+
return {
|
|
62
|
+
eventId,
|
|
63
|
+
relationField: "event",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return null;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const currentContentType = getContentType();
|
|
72
|
+
|
|
73
|
+
const handleExport = async () => {
|
|
74
|
+
const contentType = getContentType();
|
|
75
|
+
if (!contentType) {
|
|
76
|
+
toggleNotification({
|
|
77
|
+
type: "danger",
|
|
78
|
+
message: "Could not determine content type",
|
|
79
|
+
});
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
setIsExporting(true);
|
|
84
|
+
try {
|
|
85
|
+
const eventFilter = getEventFilter();
|
|
86
|
+
|
|
87
|
+
const queryParams = new URLSearchParams({
|
|
88
|
+
format: "excel",
|
|
89
|
+
contentType: contentType,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Add event filter if we're in event manager
|
|
93
|
+
if (eventFilter) {
|
|
94
|
+
queryParams.set(
|
|
95
|
+
`filters[${eventFilter.relationField}][documentId][$eq]`,
|
|
96
|
+
eventFilter.eventId
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const response = await fetch(`/export-import-clsx/export?${queryParams}&mode=participantList`);
|
|
101
|
+
|
|
102
|
+
if (response.ok) {
|
|
103
|
+
const blob = await response.blob();
|
|
104
|
+
const url = window.URL.createObjectURL(blob);
|
|
105
|
+
const a = document.createElement("a");
|
|
106
|
+
a.href = url;
|
|
107
|
+
|
|
108
|
+
const filename = `${contentType.replace("api::", "")}-export-${
|
|
109
|
+
new Date().toISOString().split("T")[0]
|
|
110
|
+
}.xlsx`;
|
|
111
|
+
|
|
112
|
+
a.download = filename;
|
|
113
|
+
document.body.appendChild(a);
|
|
114
|
+
a.click();
|
|
115
|
+
window.URL.revokeObjectURL(url);
|
|
116
|
+
document.body.removeChild(a);
|
|
117
|
+
|
|
118
|
+
toggleNotification({
|
|
119
|
+
type: "success",
|
|
120
|
+
message: "Successfully exported data",
|
|
121
|
+
});
|
|
122
|
+
} else {
|
|
123
|
+
throw new Error("Export failed");
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
toggleNotification({
|
|
127
|
+
type: "danger",
|
|
128
|
+
message: `Export failed: ${error.message}`,
|
|
129
|
+
});
|
|
130
|
+
} finally {
|
|
131
|
+
setIsExporting(false);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
if (!allowedContentTypes.includes(currentContentType)) {
|
|
136
|
+
return null
|
|
137
|
+
}
|
|
138
|
+
return (
|
|
139
|
+
<>
|
|
140
|
+
<Button
|
|
141
|
+
onClick={handleExport}
|
|
142
|
+
loading={isExporting}
|
|
143
|
+
startIcon={<Download />}
|
|
144
|
+
variant="secondary"
|
|
145
|
+
size="S"
|
|
146
|
+
>
|
|
147
|
+
Export Participants
|
|
148
|
+
</Button>
|
|
149
|
+
</>
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export default ExportButtonsEditView;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nkhang1902/strapi-plugin-export-import-clsx",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "A powerful Strapi plugin for exporting and importing data with Excel support and advanced filtering",
|
|
5
5
|
"main": "./strapi-server.js",
|
|
6
6
|
"scripts": {
|
|
@@ -235,6 +235,8 @@ module.exports = ({ strapi }) => ({
|
|
|
235
235
|
"checkedInInvestors",
|
|
236
236
|
"checkedInVipGuests",
|
|
237
237
|
"checkedInCorporates",
|
|
238
|
+
"wishlist",
|
|
239
|
+
"availableSlot",
|
|
238
240
|
];
|
|
239
241
|
const SHORTCUT_FIELDS = [
|
|
240
242
|
"email",
|
|
@@ -268,7 +270,7 @@ module.exports = ({ strapi }) => ({
|
|
|
268
270
|
.filter(([key, definition]) => definition.type === "relation")
|
|
269
271
|
.map(([key]) => key);
|
|
270
272
|
|
|
271
|
-
const
|
|
273
|
+
const mediaFields = Object.entries(attr)
|
|
272
274
|
.filter(([key, definition]) => definition.type === "media")
|
|
273
275
|
.map(([key]) => key);
|
|
274
276
|
|
|
@@ -307,8 +309,7 @@ module.exports = ({ strapi }) => ({
|
|
|
307
309
|
}
|
|
308
310
|
if (SYSTEM_KEYS.includes(key)) continue;
|
|
309
311
|
if (customFields.includes(key) && !ALLOWED_OBJECT_FIELDS.includes(key) && !ALLOWED_OBJECT_ARRAY_FIELDS.includes(key)) continue;
|
|
310
|
-
if (
|
|
311
|
-
continue;
|
|
312
|
+
if (mediaFields.includes(key)) continue;
|
|
312
313
|
|
|
313
314
|
if (componentFields.includes(key)) {
|
|
314
315
|
for (const subKey in value) {
|
|
@@ -302,12 +302,12 @@ module.exports = ({ strapi }) => ({
|
|
|
302
302
|
const cleaned = {};
|
|
303
303
|
for (const [key, attr] of Object.entries(schema.attributes)) {
|
|
304
304
|
const value = data[key];
|
|
305
|
-
if (value === undefined) continue;
|
|
306
|
-
|
|
307
305
|
if ((!value || value === "") && attr.required) {
|
|
308
|
-
|
|
306
|
+
throw new Error(`Missing required field: ${key}`);
|
|
309
307
|
}
|
|
310
308
|
|
|
309
|
+
if (value === undefined) continue;
|
|
310
|
+
|
|
311
311
|
if (attr.type === 'component') {
|
|
312
312
|
if (!value) {
|
|
313
313
|
cleaned[key] = attr.repeatable ? [] : null;
|
|
@@ -423,8 +423,6 @@ module.exports = ({ strapi }) => ({
|
|
|
423
423
|
|
|
424
424
|
data = this.sanitizeEntryBeforeWrite(data, contentType);
|
|
425
425
|
|
|
426
|
-
console.log(data)
|
|
427
|
-
|
|
428
426
|
if (existing) {
|
|
429
427
|
await strapi.documents(contentType).update({
|
|
430
428
|
documentId: existing.documentId,
|
package/strapi-admin.js
CHANGED
|
@@ -2,6 +2,7 @@ import pluginPkg from "./package.json";
|
|
|
2
2
|
import pluginId from "./admin/src/pluginId";
|
|
3
3
|
import Initializer from "./admin/src/components/Initializer";
|
|
4
4
|
import ExportImportButtons from "./admin/src/components/ExportImportButtons";
|
|
5
|
+
import ExportImportButtonsEditView from "./admin/src/components/ExportImportButtonsEditView";
|
|
5
6
|
|
|
6
7
|
const name = pluginPkg.strapi.name;
|
|
7
8
|
|
|
@@ -20,10 +21,17 @@ export default {
|
|
|
20
21
|
bootstrap(app) {
|
|
21
22
|
const contentManager = app.getPlugin("content-manager");
|
|
22
23
|
if (contentManager && contentManager.injectComponent) {
|
|
24
|
+
// Inject into list view
|
|
23
25
|
contentManager.injectComponent("listView", "actions", {
|
|
24
26
|
name: "export-import-buttons",
|
|
25
27
|
Component: ExportImportButtons,
|
|
26
28
|
});
|
|
29
|
+
|
|
30
|
+
// Inject into edit view
|
|
31
|
+
contentManager.injectComponent("editView", "right-links", {
|
|
32
|
+
name: "export-import-buttons-edit",
|
|
33
|
+
Component: ExportImportButtonsEditView,
|
|
34
|
+
});
|
|
27
35
|
}
|
|
28
36
|
},
|
|
29
|
-
};
|
|
37
|
+
};
|