@tunghtml/strapi-plugin-filtered-relation 1.1.1 → 1.1.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.1.2] - 2024-12-02
4
+
5
+ ### Fixed
6
+
7
+ - **Critical Bug - Data Loss Prevention**: Fixed critical bug where disconnect operation happened before validating target record existence
8
+ - Previously: Disconnected investor first, then checked if target exists → data loss if target missing
9
+ - Now: Validates ALL conditions first (target exists, data valid), then performs disconnect/connect
10
+ - Prevents "Investor not found in current record" error on subsequent operations
11
+ - Users can now safely perform multiple status changes without page refresh
12
+ - **Improved Error Notifications**: Changed error notification type from "warning" to "danger"
13
+ - Makes errors more visible and distinguishable from warnings
14
+ - Helps users quickly identify critical issues that need attention
15
+
16
+ ### Changed
17
+
18
+ - Reordered `handleStatusChange` logic flow:
19
+ 1. Get current record data
20
+ 2. Find investor to move
21
+ 3. **Validate target record exists** (NEW - moved before disconnect)
22
+ 4. **Validate target data is valid** (NEW)
23
+ 5. Disconnect from current record (only after validation passes)
24
+ 6. Connect to target record
25
+ 7. Refresh UI
26
+ - All error notifications now use `type: "danger"` instead of `type: "warning"`
27
+
28
+ ### Technical Details
29
+
30
+ - Added validation check for target record data integrity before any mutations
31
+ - Prevents partial state updates that could leave data in inconsistent state
32
+ - Follows transaction-like pattern: validate everything, then commit changes
33
+
3
34
  ## [1.1.1] - 2024-12-02
4
35
 
5
36
  ### Fixed
@@ -172,35 +172,14 @@ const FilteredRelationInput = (props) => {
172
172
  "[FilteredRelation] Investor not found in current record"
173
173
  );
174
174
  toggleNotification({
175
- type: "warning",
175
+ type: "danger",
176
176
  message:
177
177
  "Investor not found in current record. Please refresh the page.",
178
178
  });
179
179
  return;
180
180
  }
181
181
 
182
- // Build full payload like UI admin does
183
- const updatePayload = {
184
- documentId: currentData.documentId,
185
- [displayField]: {
186
- connect: [],
187
- disconnect: [
188
- {
189
- id: investorToRemove.id,
190
- documentId: investorToRemove.documentId,
191
- },
192
- ],
193
- },
194
- participantStatus: currentData.participantStatus,
195
- };
196
-
197
- // Use disconnect with full payload
198
- const removeResponse = await put(
199
- `/content-manager/collection-types/${targetModel}/${itemId}`,
200
- updatePayload
201
- );
202
-
203
- // Step 3: Find Meeting Participation Status with new status (same meeting)
182
+ // Step 3: VALIDATE target record EXISTS BEFORE disconnecting (critical fix)
204
183
  const newFilterParams = {};
205
184
  if (filterField1) {
206
185
  newFilterParams[filterField1] = newStatus;
@@ -229,16 +208,13 @@ const FilteredRelationInput = (props) => {
229
208
  searchResponse?.data ||
230
209
  [];
231
210
 
232
- let targetRecordId;
233
- let targetInvestors = [];
234
-
235
211
  if (targetRecords.length === 0) {
236
212
  console.error(
237
213
  "[FilteredRelation] No target record found with new status for this meeting."
238
214
  );
239
215
  const collectionDisplayName = targetModelInput || "record";
240
216
  toggleNotification({
241
- type: "warning",
217
+ type: "danger",
242
218
  message: `No ${collectionDisplayName} found with status "${newStatus}" for this meeting. Please create one first.`,
243
219
  });
244
220
  return;
@@ -246,14 +222,44 @@ const FilteredRelationInput = (props) => {
246
222
 
247
223
  // Get full target record data
248
224
  const targetRecord = targetRecords[0];
249
- targetRecordId = targetRecord.documentId || targetRecord.id;
225
+ const targetRecordId = targetRecord.documentId || targetRecord.id;
250
226
 
251
227
  // Get target record with all fields
252
228
  const targetRecordUrl = `/content-manager/collection-types/${targetModel}/${targetRecordId}?populate=*`;
253
229
  const targetRecordFull = await get(targetRecordUrl);
254
230
  const targetData = targetRecordFull?.data?.data || {};
255
231
 
256
- // Step 4: Add investor to target record
232
+ if (!targetData || !targetData.documentId) {
233
+ console.error("[FilteredRelation] Target record data is invalid");
234
+ toggleNotification({
235
+ type: "danger",
236
+ message: "Target record not found. Please refresh and try again.",
237
+ });
238
+ return;
239
+ }
240
+
241
+ // Step 4: NOW disconnect from current record (after validation passed)
242
+ const updatePayload = {
243
+ documentId: currentData.documentId,
244
+ [displayField]: {
245
+ connect: [],
246
+ disconnect: [
247
+ {
248
+ id: investorToRemove.id,
249
+ documentId: investorToRemove.documentId,
250
+ },
251
+ ],
252
+ },
253
+ participantStatus: currentData.participantStatus,
254
+ };
255
+
256
+ // Use disconnect with full payload
257
+ const removeResponse = await put(
258
+ `/content-manager/collection-types/${targetModel}/${itemId}`,
259
+ updatePayload
260
+ );
261
+
262
+ // Step 5: Add investor to target record
257
263
  // Build full payload like UI admin does
258
264
  const addPayload = {
259
265
  documentId: targetData.documentId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tunghtml/strapi-plugin-filtered-relation",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "A Strapi custom field plugin for displaying filtered relations with dynamic placeholder support and status change capability",
5
5
  "keywords": [
6
6
  "strapi",