Skip to content

Commit 79642c6

Browse files
authored
Merge pull request #370 from fairdataihub/staging
feat: 15.2.3 bug fix release
2 parents 1d71189 + 323e483 commit 79642c6

File tree

7 files changed

+221
-274
lines changed

7 files changed

+221
-274
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to SODA will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8+
## v15.2.3 - 2024-11-20
9+
10+
## Bug Fixes:
11+
12+
- Restricted forbidden characters in Guided Mode datasets to avoid JSON save file issues.
13+
- Moved guidedSaveProgress to trigger after every successful page exit for broader save coverage.
14+
815
## v15.2.2 - 2024-10-09
916

1017
## Bug Fixes:

package-lock.json

+162-238
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "soda-for-sparc",
33
"procductName": "SODA for SPARC",
4-
"version": "15.2.2",
4+
"version": "15.2.3",
55
"description": "Keep Calm and Curate",
66
"main": "./out/main/index.js",
77
"author": "SODA Team",

src/pyflask/startup/minimumApiVersion.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def get_api_version():
88
"""
99

1010

11-
return {'version': os.getenv('API_VERSION', "15.2.2")}
11+
return {'version': os.getenv('API_VERSION', "15.2.3")}
1212

1313

1414

src/renderer/src/scripts/guided-mode/guided-curate-dataset.js

+48-31
Original file line numberDiff line numberDiff line change
@@ -1095,11 +1095,15 @@ const savePageChanges = async (pageBeingLeftID) => {
10951095
message: "Please enter a dataset name.",
10961096
});
10971097
}
1098-
if (check_forbidden_characters_ps(datasetNameInput)) {
1098+
1099+
const datasetNameContainsForbiddenCharacters = window.evaluateStringAgainstSdsRequirements(
1100+
datasetNameInput,
1101+
"string-contains-forbidden-characters"
1102+
);
1103+
if (datasetNameContainsForbiddenCharacters) {
10991104
errorArray.push({
11001105
type: "notyf",
1101-
message:
1102-
"A Pennsieve dataset name cannot contain any of the following characters: /:*?'<>.",
1106+
message: `A Pennsieve dataset name cannot contain any of the following characters: @#$%^&*()+=/\|"'~;:<>{}[]?`,
11031107
});
11041108
}
11051109
if (!datasetSubtitleInput) {
@@ -2101,12 +2105,14 @@ const savePageChanges = async (pageBeingLeftID) => {
21012105
}
21022106
}
21032107

2104-
// Save the current version of SODA as the user should be taken back to the first page when the app is updated
2105-
const currentAppVersion = document.getElementById("version").innerHTML;
2106-
window.sodaJSONObj["last-version-of-soda-used"] = currentAppVersion;
2107-
21082108
// Stop any animations that need to be stopped
21092109
startOrStopAnimationsInContainer(pageBeingLeftID, "stop");
2110+
2111+
try {
2112+
await guidedSaveProgress();
2113+
} catch (error) {
2114+
log.error(error);
2115+
}
21102116
} catch (error) {
21112117
guidedSetNavLoadingState(false);
21122118
console.log(error);
@@ -3000,9 +3006,14 @@ const guidedTransitionFromDatasetNameSubtitlePage = () => {
30003006
$("#guided-footer-div").css("display", "flex");
30013007
};
30023008

3003-
const saveGuidedProgress = async (guidedProgressFileName) => {
3009+
const guidedSaveProgress = async () => {
3010+
const guidedProgressFileName = window.sodaJSONObj?.["digital-metadata"]?.["name"];
30043011
//return if guidedProgressFileName is not a strnig greater than 0
3005-
if (typeof guidedProgressFileName !== "string" || guidedProgressFileName.length === 0) {
3012+
if (
3013+
!guidedProgressFileName ||
3014+
typeof guidedProgressFileName !== "string" ||
3015+
guidedProgressFileName.length === 0
3016+
) {
30063017
return;
30073018
}
30083019
//Destination: HOMEDIR/SODA/Guided-Progress
@@ -3026,6 +3037,10 @@ const saveGuidedProgress = async (guidedProgressFileName) => {
30263037
window.sodaJSONObj["subjects-table-data"] = window.subjectsTableData;
30273038
window.sodaJSONObj["samples-table-data"] = window.samplesTableData;
30283039

3040+
// Save the current version of SODA as the user should be taken back to the first page when the app is updated
3041+
const currentAppVersion = document.getElementById("version").innerHTML;
3042+
window.sodaJSONObj["last-version-of-soda-used"] = currentAppVersion;
3043+
30293044
window.fs.writeFileSync(guidedFilePath, JSON.stringify(window.sodaJSONObj, null, 2));
30303045
};
30313046

@@ -3466,7 +3481,7 @@ window.guidedOpenManifestEditSwal = async (highLevelFolderName) => {
34663481
//spreadsheet reply contained results
34673482
await updateManifestJson(highLevelFolderName, result);
34683483
window.electron.ipcRenderer.removeAllListeners("spreadsheet-reply");
3469-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
3484+
await guidedSaveProgress();
34703485
renderManifestCards();
34713486
}
34723487
});
@@ -6815,7 +6830,7 @@ window.openPage = async (targetPageID) => {
68156830

68166831
// Set the last opened page and save it
68176832
window.sodaJSONObj["page-before-exit"] = targetPageID;
6818-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
6833+
await guidedSaveProgress();
68196834
} catch (error) {
68206835
const eMessage = userErrorMessage(error);
68216836
Swal.fire({
@@ -7537,7 +7552,7 @@ const guidedCheckIfUserNeedsToReconfirmAccountDetails = () => {
75377552
return false;
75387553
};
75397554

7540-
const guidedGetPageToReturnTo = (sodaJSONObj) => {
7555+
const guidedGetPageToReturnTo = async (sodaJSONObj) => {
75417556
// Set by window.openPage function
75427557
const usersPageBeforeExit = window.sodaJSONObj["page-before-exit"];
75437558

@@ -7553,7 +7568,11 @@ const guidedGetPageToReturnTo = (sodaJSONObj) => {
75537568
const lastVersionOfSodaUsedOnProgressFile = window.sodaJSONObj["last-version-of-soda-used"];
75547569

75557570
if (lastVersionOfSodaUsedOnProgressFile != currentSodaVersion) {
7556-
// If the last time the user worked on the progress file was in a previous version of SODA, then force the user to restart from the first page
7571+
// If the progress file was last edited in a previous SODA version, reset to the first page
7572+
await swalShowInfo(
7573+
"SODA has been updated since you last worked on this dataset.",
7574+
"You'll be taken to the first page to ensure compatibility with the latest workflow. Your previous work is saved and accessible."
7575+
);
75577576
return firstPageID;
75587577
}
75597578

@@ -7876,7 +7895,7 @@ window.guidedResumeProgress = async (datasetNameToResume) => {
78767895
hideSubNavAndShowMainNav(false);
78777896

78787897
// pageToReturnTo will be set to the page the user will return to
7879-
const pageToReturnTo = guidedGetPageToReturnTo(window.sodaJSONObj);
7898+
const pageToReturnTo = await guidedGetPageToReturnTo(window.sodaJSONObj);
78807899

78817900
await window.openPage(pageToReturnTo);
78827901

@@ -10546,7 +10565,7 @@ window.openCopySubjectMetadataPopup = async () => {
1054610565
window.populateForms(currentSubjectOpenInView, "", "guided");
1054710566
}
1054810567

10549-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
10568+
await guidedSaveProgress();
1055010569
}
1055110570
});
1055210571
};
@@ -10644,7 +10663,7 @@ window.openCopySampleMetadataPopup = async () => {
1064410663
if (currentSampleOpenInView) {
1064510664
openModifySampleMetadataPage(currentSampleOpenInView, currentSampleSubjectOpenInView);
1064610665
}
10647-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
10666+
await guidedSaveProgress();
1064810667
}
1064910668
});
1065010669
};
@@ -12866,7 +12885,7 @@ const renderSubjectsMetadataAsideItems = async () => {
1286612885
//check to see if previousSubject is empty
1286712886
if (previousSubject) {
1286812887
window.addSubject("guided");
12869-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
12888+
await guidedSaveProgress();
1287012889
}
1287112890

1287212891
window.clearAllSubjectFormFields(window.guidedSubjectsFormDiv);
@@ -12884,7 +12903,7 @@ const renderSubjectsMetadataAsideItems = async () => {
1288412903

1288512904
document.getElementById("guided-bootbox-subject-id").value = e.target.innerText;
1288612905

12887-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
12906+
await guidedSaveProgress();
1288812907
});
1288912908
});
1289012909
};
@@ -13011,7 +13030,7 @@ const renderSamplesMetadataAsideItems = async () => {
1301113030
//check to see if previousSample is empty
1301213031
if (previousSample) {
1301313032
window.addSample("guided");
13014-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
13033+
await guidedSaveProgress();
1301513034
}
1301613035

1301713036
//add selected class to clicked element
@@ -13031,7 +13050,7 @@ const renderSamplesMetadataAsideItems = async () => {
1303113050
e.target.innerText.split("/")[0]
1303213051
);
1303313052

13034-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
13053+
await guidedSaveProgress();
1303513054
});
1303613055
});
1303713056
};
@@ -13711,7 +13730,7 @@ const guidedCreateOrRenameDataset = async (bfAccount, datasetName) => {
1371113730
// so new metadata can be uploaded to the newly created dataset
1371213731
// (This would happen if the user deleted the dataset on Pennsieve)
1371313732
window.sodaJSONObj["previously-uploaded-data"] = {};
13714-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
13733+
await guidedSaveProgress();
1371513734
}
1371613735
}
1371713736

@@ -13764,7 +13783,7 @@ const guidedCreateOrRenameDataset = async (bfAccount, datasetName) => {
1376413783
//Save the dataset ID generated by pennsieve so the dataset is not re-uploaded when the user
1376513784
//resumes progress after failing an upload
1376613785
window.sodaJSONObj["digital-metadata"]["pennsieve-dataset-id"] = createdDatasetsID;
13767-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
13786+
await guidedSaveProgress();
1376813787

1376913788
return createdDatasetsID;
1377013789
} catch (error) {
@@ -13830,7 +13849,7 @@ const guidedAddDatasetSubtitle = async (bfAccount, datasetName, datasetSubtitle)
1383013849
datasetSubtitleUploadText.innerHTML = `Successfully added dataset subtitle: ${datasetSubtitle}`;
1383113850
guidedUploadStatusIcon("guided-dataset-subtitle-upload-status", "success");
1383213851
window.sodaJSONObj["previously-uploaded-data"]["subtitle"] = datasetSubtitle;
13833-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
13852+
await guidedSaveProgress();
1383413853

1383513854
// Send successful dataset subtitle upload event to Kombucha
1383613855
window.electron.ipcRenderer.send(
@@ -13916,7 +13935,7 @@ const guidedAddDatasetDescription = async (
1391613935
datasetDescriptionUploadText.innerHTML = `Successfully added dataset description!`;
1391713936
guidedUploadStatusIcon("guided-dataset-description-upload-status", "success");
1391813937
window.sodaJSONObj["previously-uploaded-data"]["description"] = description;
13919-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
13938+
await guidedSaveProgress();
1392013939

1392113940
// Send successful dataset description upload event to Kombucha
1392213941
window.electron.ipcRenderer.send(
@@ -14003,7 +14022,7 @@ const uploadValidBannerImage = async (bfAccount, datasetName, bannerImagePath) =
1400314022
datasetBannerImageUploadText.innerHTML = `Successfully added dataset banner image!`;
1400414023
guidedUploadStatusIcon("guided-dataset-banner-image-upload-status", "success");
1400514024
window.sodaJSONObj["previously-uploaded-data"]["banner-image-path"] = bannerImagePath;
14006-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
14025+
await guidedSaveProgress();
1400714026

1400814027
// Send successful banner image upload event to Kombucha
1400914028
window.electron.ipcRenderer.send(
@@ -14096,7 +14115,7 @@ const guidedAddDatasetLicense = async (bfAccount, datasetName, datasetLicense) =
1409614115
datasetLicenseUploadText.innerHTML = `Successfully added dataset license: ${datasetLicense}`;
1409714116
guidedUploadStatusIcon("guided-dataset-license-upload-status", "success");
1409814117
window.sodaJSONObj["previously-uploaded-data"]["license"] = datasetLicense;
14099-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
14118+
await guidedSaveProgress();
1410014119

1410114120
// Send successful license upload event to Kombucha
1410214121
window.electron.ipcRenderer.send(
@@ -14169,7 +14188,7 @@ const guidedAddDatasetTags = async (bfAccount, datasetName, tags) => {
1416914188
datasetTagsUploadText.innerHTML = `Successfully added dataset tags: ${tags.join(", ")}`;
1417014189
guidedUploadStatusIcon("guided-dataset-tags-upload-status", "success");
1417114190
window.sodaJSONObj["previously-uploaded-data"]["tags"] = tags;
14172-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
14191+
await guidedSaveProgress();
1417314192

1417414193
// Send successful tags upload event to Kombucha
1417514194
window.electron.ipcRenderer.send(
@@ -15688,7 +15707,7 @@ const guidedUploadDatasetToPennsieve = async () => {
1568815707
window.sodaJSONObj["digital-metadata"]["name"];
1568915708

1569015709
// Save the window.sodaJSONObj after a successful upload
15691-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
15710+
await guidedSaveProgress();
1569215711

1569315712
//Display the click next text
1569415713
document.getElementById("guided--verify-files").classList.remove("hidden");
@@ -16493,8 +16512,6 @@ $("#guided-next-button").on("click", async function () {
1649316512

1649416513
try {
1649516514
await savePageChanges(window.pageBeingLeftID);
16496-
//Save progress onto local storage with the dataset name as the key
16497-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
1649816515

1649916516
//Mark page as completed in JSONObj so we know what pages to load when loading local saves
1650016517
//(if it hasn't already been marked complete)
@@ -17087,7 +17104,7 @@ const saveSubPageChanges = async (openSubPageID) => {
1708717104
"import";
1708817105
}
1708917106

17090-
await saveGuidedProgress(window.sodaJSONObj["digital-metadata"]["name"]);
17107+
await guidedSaveProgress();
1709117108
} catch (error) {
1709217109
guidedSetNavLoadingState(false);
1709317110
throw error;

src/renderer/src/scripts/organize-dataset/curate-functions.js

-3
Original file line numberDiff line numberDiff line change
@@ -502,11 +502,8 @@ window.uploadDatasetClickHandler = async (ev) => {
502502
};
503503

504504
window.handleLocalDatasetImport = async (path) => {
505-
console.log("Importing local dataset from path:", path);
506505
const list = await getFilesAndFolders(path);
507-
console.log("List of files and folders:", list);
508506
const currentFileExplorerPath = window.organizeDSglobalPath.value.trim();
509-
console.log("Current file explorer path:", currentFileExplorerPath);
510507
const builtDatasetStructure = await window.buildDatasetStructureJsonFromImportedData(
511508
list.folders,
512509
"dataset_root/", // Use dataset_root as the root folder since we are importing the root in this case

src/renderer/src/scripts/others/renderer.js

+2
Original file line numberDiff line numberDiff line change
@@ -4359,13 +4359,15 @@ const namesOfForbiddenFiles = {
43594359

43604360
const sparcFolderAndFileRegex = /[\+&\%#]/;
43614361
const identifierConventionsRegex = /^[a-zA-Z0-9-_]+$/;
4362+
const forbiddenCharacters = /[@#$%^&*()+=\/\\|"'~;:<>{}\[\]?]/;
43624363

43634364
window.evaluateStringAgainstSdsRequirements = (stringToTest, stringCase) => {
43644365
const testCases = {
43654366
"folder-and-file-name-is-valid": !sparcFolderAndFileRegex.test(stringToTest), // returns true if the string is valid
43664367
"file-is-hidden": stringToTest.startsWith("."), // returns true if the string is hidden
43674368
"file-is-in-forbidden-files-list": namesOfForbiddenFiles?.[stringToTest], // returns true if the string is in the forbidden files list
43684369
"string-adheres-to-identifier-conventions": identifierConventionsRegex.test(stringToTest), // returns true if the string adheres to the identifier conventions
4370+
"string-contains-forbidden-characters": forbiddenCharacters.test(stringToTest), // returns true if the string contains forbidden characters
43694371
};
43704372
return testCases[stringCase];
43714373
};

0 commit comments

Comments
 (0)