@adriansteffan/reactive 0.0.39 → 0.0.41
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/.claude/settings.local.json +10 -0
- package/dist/{mod-B9pn3CIt.js → mod-DBgU62Mz.js} +3814 -3788
- package/dist/mod.d.ts +1 -1
- package/dist/reactive.es.js +1 -1
- package/dist/reactive.umd.js +28 -28
- package/dist/{web-B5ojRUs4.js → web-AqTV2861.js} +1 -1
- package/dist/{web-wJPoJ8Wb.js → web-C32MLGZU.js} +1 -1
- package/package.json +1 -1
- package/src/components/upload.tsx +119 -27
package/package.json
CHANGED
|
@@ -108,27 +108,112 @@ function combineTrialsToCsv(
|
|
|
108
108
|
data: any[],
|
|
109
109
|
filename: string,
|
|
110
110
|
names: string[],
|
|
111
|
-
flatteningFunctions: Record<string, (item: any) => any[]
|
|
111
|
+
flatteningFunctions: Record<string, (item: any) => any[] | Record<string, any[]>>,
|
|
112
112
|
fun?: (obj: any) => any,
|
|
113
|
-
) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
113
|
+
): FileUpload | FileUpload[] {
|
|
114
|
+
|
|
115
|
+
// Collect all flattener results first, filtering out completely empty results
|
|
116
|
+
const allResults: (any[] | Record<string, any[]>)[] = names.flatMap((name) => {
|
|
117
|
+
const matchingItems = data.filter((d) => d.name === name);
|
|
118
|
+
|
|
119
|
+
return matchingItems.map((item) => {
|
|
120
|
+
const flattener = item.type && flatteningFunctions[item.type];
|
|
121
|
+
const result = flattener ? flattener(item) : [transform(item)];
|
|
122
|
+
|
|
123
|
+
// Filter out completely empty results
|
|
124
|
+
if (Array.isArray(result) && result.length === 0) {
|
|
125
|
+
return null; // Signal this trial should be completely skipped
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (result && typeof result === 'object' && !Array.isArray(result)) {
|
|
129
|
+
// Check if all arrays in the object are empty
|
|
130
|
+
const hasAnyData = Object.values(result).some(val =>
|
|
131
|
+
Array.isArray(val) && val.length > 0
|
|
132
|
+
);
|
|
133
|
+
if (!hasAnyData) {
|
|
134
|
+
return null; // Signal this trial should be completely skipped
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return result;
|
|
139
|
+
});
|
|
140
|
+
}).filter(result => result !== null);
|
|
141
|
+
|
|
142
|
+
// Check if any result is a multi-table object (has string keys with array values)
|
|
143
|
+
const hasMultiTable = allResults.some((result) =>
|
|
144
|
+
result &&
|
|
145
|
+
typeof result === 'object' &&
|
|
146
|
+
!Array.isArray(result) &&
|
|
147
|
+
Object.keys(result).some(key => Array.isArray(result[key]))
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
if (!hasMultiTable) {
|
|
151
|
+
// all results are arrays, combine them into one CSV
|
|
152
|
+
const processedData = allResults
|
|
153
|
+
.flatMap((result) => Array.isArray(result) ? result : [])
|
|
154
|
+
.map((x) => (fun ? fun(x) : x));
|
|
155
|
+
|
|
156
|
+
// Skip creating CSV if all flatteners returned empty arrays
|
|
157
|
+
if (processedData.length === 0) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
filename,
|
|
163
|
+
encoding: 'utf8' as const,
|
|
164
|
+
content: convertArrayOfObjectsToCSV(processedData),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// handle multi-table results
|
|
169
|
+
// Collect all table keys from all results
|
|
170
|
+
const allTableKeys = new Set<string>();
|
|
171
|
+
allResults.forEach((result) => {
|
|
172
|
+
if (result && typeof result === 'object' && !Array.isArray(result)) {
|
|
173
|
+
Object.keys(result).forEach(key => {
|
|
174
|
+
if (Array.isArray(result[key])) {
|
|
175
|
+
allTableKeys.add(key);
|
|
176
|
+
}
|
|
123
177
|
});
|
|
124
|
-
}
|
|
125
|
-
|
|
178
|
+
}
|
|
179
|
+
});
|
|
126
180
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
181
|
+
// Create separate CSV files for each table key
|
|
182
|
+
const files: FileUpload[] = [];
|
|
183
|
+
|
|
184
|
+
for (const tableKey of allTableKeys) {
|
|
185
|
+
const tableData = allResults.flatMap((result) => {
|
|
186
|
+
if (Array.isArray(result)) {
|
|
187
|
+
// If this result is a simple array, include it in all tables for backward compatibility
|
|
188
|
+
return result;
|
|
189
|
+
} else if (result && typeof result === 'object' && result[tableKey]) {
|
|
190
|
+
// If this result has data for this table key, include it
|
|
191
|
+
return result[tableKey];
|
|
192
|
+
}
|
|
193
|
+
return [];
|
|
194
|
+
}).map((x) => (fun ? fun(x) : x));
|
|
195
|
+
|
|
196
|
+
// Skip creating CSV if all flatteners returned empty arrays for this table
|
|
197
|
+
if (tableData.length === 0) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Remove file extension from filename and add table key
|
|
202
|
+
const baseFilename = filename.replace(/\.csv$/, '');
|
|
203
|
+
|
|
204
|
+
files.push({
|
|
205
|
+
filename: `${baseFilename}_${tableKey}.csv`,
|
|
206
|
+
encoding: 'utf8' as const,
|
|
207
|
+
content: convertArrayOfObjectsToCSV(tableData),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Return empty array if no files were created
|
|
212
|
+
if (files.length === 0) {
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return files.length === 1 ? files[0] : files;
|
|
132
217
|
}
|
|
133
218
|
|
|
134
219
|
interface FileBackend {
|
|
@@ -281,7 +366,7 @@ export default function Upload({
|
|
|
281
366
|
sessionID?: string | null;
|
|
282
367
|
generateFiles: (sessionID: string, data: TrialData[], store?: Store) => FileUpload[];
|
|
283
368
|
sessionCSVBuilder: CSVBuilder;
|
|
284
|
-
trialCSVBuilder: {flatteners: Record<string, ((item: TrialData) => Record<string, any>[])>, builders: CSVBuilder[]};
|
|
369
|
+
trialCSVBuilder: {flatteners: Record<string, ((item: TrialData) => Record<string, any>[] | Record<string, Record<string, any>[]>)>, builders: CSVBuilder[]};
|
|
285
370
|
uploadRaw: boolean;
|
|
286
371
|
autoUpload: boolean;
|
|
287
372
|
androidFolderName?: string;
|
|
@@ -415,15 +500,22 @@ export default function Upload({
|
|
|
415
500
|
|
|
416
501
|
if (trialCSVBuilder) {
|
|
417
502
|
for (const builder of trialCSVBuilder.builders) {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
builder.fun,
|
|
425
|
-
),
|
|
503
|
+
const result = combineTrialsToCsv(
|
|
504
|
+
data,
|
|
505
|
+
`${sessionIDUpload}${builder.filename}.csv`,
|
|
506
|
+
builder.trials ?? [],
|
|
507
|
+
{...defaultFlatteningFunctions, ...trialCSVBuilder.flatteners},
|
|
508
|
+
builder.fun,
|
|
426
509
|
);
|
|
510
|
+
|
|
511
|
+
if (Array.isArray(result)) {
|
|
512
|
+
// Only push files if the array is not empty
|
|
513
|
+
if (result.length > 0) {
|
|
514
|
+
files.push(...result);
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
517
|
+
files.push(result);
|
|
518
|
+
}
|
|
427
519
|
}
|
|
428
520
|
}
|
|
429
521
|
|