Skip to content

Commit

Permalink
Merge pull request #358 from fairdataihub/staging
Browse files Browse the repository at this point in the history
feat: 15.2.0
  • Loading branch information
aaronm-2112 authored Aug 21, 2024
2 parents 65af8da + 50fb01c commit 0b68a93
Show file tree
Hide file tree
Showing 33 changed files with 520 additions and 132 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ All notable changes to SODA will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## v15.2.0 - 2024-08-21

## Feature Additions:

- An accounts page is accessible through the sidebar. This page allows users to more easily manage their Pennsieve account(s) that have been connected to SODA.
- It is now possible to upload a dataset to Pennsieve in End-to-End Curation mode without first adding a banner image. This is useful for users who do not have a banner image prepared. Note that before your dataset can be published you will need to add a banner image.
- It is now possible to upload a dataset to Pennsieve in End-to-End Curation mode without first assigning a Principal Investigator (PI). Note that before your dataset can be published you will need to assign a PI.

## Bug Fixes:

- Fixed an issue causing the Verify Files feature to freeze when verifying large datasets.
- Fixed issues in `Advanced features` that made it difficult to add a banner image using the `Upload a banner image` feature.

## V15.1.0 - 2024-07-18

## Feature Additions:
Expand Down
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
MIT License


Copyright (c) 2024 FAIR Data Innovations Hub

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "soda-for-sparc",
"procductName": "SODA for SPARC",
"version": "15.1.0",
"version": "15.2.0",
"description": "Keep Calm and Curate",
"main": "./out/main/index.js",
"author": "SODA Team",
Expand Down
1 change: 1 addition & 0 deletions src/pyflask/apis/apiCurate.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ def post(self):
"main_curation_uploaded_files": fields.Integer(description="Number of files that are being generated. "),
"local_manifest_id": fields.String(description="ID of the local manifest file created by the Pennsieve Agent for the upload."),
"origin_manifest_id": fields.String(description="ID of the manifest file created on Pennsieve for the upload."),
"main_curation_total_files": fields.Integer(description="Total number of files in the dataset upload session."),
})

# TODO: Add example JSON structures for upload
Expand Down
8 changes: 3 additions & 5 deletions src/pyflask/curate/curate.py
Original file line number Diff line number Diff line change
Expand Up @@ -1842,10 +1842,8 @@ def get_origin_manifest_id(dataset_id):
for _ in range(max_attempts):
manifests = get_upload_manifests(dataset_id)
if manifests and "manifests" in manifests and manifests["manifests"]:
namespace_logger.info(f"Manifests returned: {manifests}")
# sort the manifests list by date_created timestamp field in descending order
manifests["manifests"].sort(key=lambda x: x["date_created"], reverse=True)
namespace_logger.info(f"Manifests sorted: {manifests}")
return manifests["manifests"][0]["id"]
time.sleep(5) # Wait for 5 seconds before the next attempt

Expand Down Expand Up @@ -2397,7 +2395,6 @@ def monitor_subscriber_progress(events_dict):
# 1. Scan the dataset structure and create a list of files/folders to be uploaded with the desired renaming
if generate_option == "new" and starting_point == "new":
vs = ums.df_mid_has_progress()
namespace_logger.info(f"Line 2413. Progress found? {vs}")
if resume == False or resume == True and not vs:
namespace_logger.info("NO progress found so we will start from scratch and construct the manifest")
main_curate_progress_message = "Preparing a list of files to upload"
Expand Down Expand Up @@ -2663,7 +2660,6 @@ def monitor_subscriber_progress(events_dict):
ps.subscribe(10, False, monitor_subscriber_progress)

except Exception as e:
namespace_logger.error("Error uploading dataset files")
namespace_logger.error(e)
raise PennsieveUploadException("The Pennsieve Agent has encountered an issue while uploading. Please retry the upload. If this issue persists please follow this <a target='_blank' rel='noopener noreferrer' href='https://docs.sodaforsparc.io/docs/how-to/how-to-reinstall-the-pennsieve-agent'> guide</a> on performing a full reinstallation of the Pennsieve Agent then click the retry button.")

Expand Down Expand Up @@ -3482,6 +3478,7 @@ def main_curate_function(soda_json_structure, resume):
global main_curate_status
global manifest_id
global origin_manifest_id
global total_files

namespace_logger.info("Starting main_curate_function")
namespace_logger.info(f"main_curate_function metadata generate-options={soda_json_structure['generate-dataset']}")
Expand Down Expand Up @@ -3519,7 +3516,8 @@ def main_curate_function(soda_json_structure, resume):
"main_total_generate_dataset_size": main_total_generate_dataset_size,
"main_curation_uploaded_files": main_curation_uploaded_files,
"local_manifest_id": manifest_id,
"origin_manifest_id": origin_manifest_id
"origin_manifest_id": origin_manifest_id,
"main_curation_total_files": total_files,
}


Expand Down
5 changes: 0 additions & 5 deletions src/pyflask/datasets/compare_local_remote_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ def import_subfolders(subfolder, path):
curr_file = {"name": child["content"]["name"], "path": curr_path}
subfolder["files"][child["content"]["name"]] = curr_file
for folder_name, folder in subfolder["folders"].items():
namespace_logger.info(f"Importing subfolders for {folder_name}")
import_subfolders(folder, f"{path}/{folder_name}")
except Exception as e:
print(f"Exception when calling API: {e}")
Expand Down Expand Up @@ -71,7 +70,6 @@ def import_pennsieve_dataset(dataset_id, path):
pennsieve_dataset_structure["files"][child["content"]["name"]] = curr_file

for folder_name, folder in pennsieve_dataset_structure["folders"].items():
namespace_logger.info(f"Importing subfolders for {folder_name}")
import_subfolders(folder, f"{folder_name}")
except Exception as e:
print(f"Exception when calling API: {e}")
Expand Down Expand Up @@ -100,7 +98,6 @@ def import_local_dataset(path):
curr_file = {"name": child, "path": curr_path}
local_dataset_structure["files"][child] = curr_file
for folder_name, folder in local_dataset_structure["folders"].items():
namespace_logger.info(f"Importing subfolders for {folder_name}")
import_local_subfolders(folder, f"{path}/{folder_name}")
except Exception as e:
print(f"Exception when calling API: {e}")
Expand All @@ -126,7 +123,6 @@ def import_local_subfolders(subfolder, path):
curr_file = {"name": child, "path": curr_path}
subfolder["files"][child] = curr_file
for folder_name, folder in subfolder["folders"].items():
namespace_logger.info(f"Importing subfolders for {folder_name}")
import_local_subfolders(folder, f"{path}/{folder_name}")
except Exception as e:
print(f"Exception when calling API: {e}")
Expand Down Expand Up @@ -168,7 +164,6 @@ def run_comparison(dataset_id, local_dataset_path):
global pennsieve_dataset_paths

if not os.path.exists(local_dataset_path) and not os.path.isdir(local_dataset_path):
print(f"Path {local_dataset_path} does not exist or is not a directory")
raise FileNotFoundError(f"Path {local_dataset_path} does not exist or is not a directory")


Expand Down
2 changes: 1 addition & 1 deletion src/pyflask/startup/minimumApiVersion.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ def get_api_version():



return {'version': os.getenv('API_VERSION', "15.1.0")}
return {'version': os.getenv('API_VERSION', "15.2.0")}


11 changes: 9 additions & 2 deletions src/renderer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<link rel="import" href="src/sections/guided_mode/guided_curate_dataset.html" />
<link rel="import" href="src/sections/documentation/documentation.html" />
<link rel="import" href="src/sections/contact-us/contact_us.html" />
<link rel="import" href="src/sections/accounts/accounts.html" />
<link rel="import" href="src/sections/advanced-features/advanced_features.html" />
<link rel="import" href="src/sections/sds-templates/sds_templates.html" />

Expand Down Expand Up @@ -129,6 +130,12 @@
>Documentation</a
>
</li>
<li>
<a href="#" data-section="account" id="account-view">
<svg height="20px"
width="20px" style="margin-right: 30px; margin-bottom: -5px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512l388.6 0c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304l-91.4 0z"/></svg>Manage Accounts</a
>
</li>
<li>
<a href="#" data-section="contact-us" id="contact-us-view">
<svg
Expand All @@ -141,8 +148,8 @@
<!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
<path
d="M511.1 63.1v287.1c0 35.25-28.75 63.1-64 63.1h-144l-124.9 93.68c-7.875 5.75-19.12 .0497-19.12-9.7v-83.98h-96c-35.25 0-64-28.75-64-63.1V63.1c0-35.25 28.75-63.1 64-63.1h384C483.2 0 511.1 28.75 511.1 63.1z"
></path></svg
>Contact Us</a
></path>
</svg>Contact Us</a
>
</li>
</ul>
Expand Down
11 changes: 10 additions & 1 deletion src/renderer/src/components/renderers/ReactComponentRenderer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import DropdownSelect from "../common/DropdownSelect";
import GenericButton from "../buttons/Generic";
import SingleColumnTable from "../tables/singleColumn";
import PennsieveAgentCheckDisplay from "../backgroundServices/PennsieveAgentCheckDisplay";
import { Divider } from "@mantine/core";

// Wait for the HTML sections to be added to the DOM before rendering React components
while (!window.htmlSectionsAdded) {
Expand Down Expand Up @@ -34,7 +35,7 @@ const componentTypeRenderers = {
},
"external-link": (componentSlot) => {
const props = {
url: componentSlot.getAttribute("data-url"),
href: componentSlot.getAttribute("data-href"),
buttonText: componentSlot.getAttribute("data-button-text"),
buttonType: componentSlot.getAttribute("data-button-type"),
};
Expand Down Expand Up @@ -85,6 +86,14 @@ const componentTypeRenderers = {
</SodaComponentWrapper>
);
},
divider: (componentSlot) => {
const root = createRoot(componentSlot);
root.render(
<SodaComponentWrapper>
<Divider my="xl" />
</SodaComponentWrapper>
);
},
};

// Query all DOM nodes with the data attribute "data-component-type" and render the appropriate component
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {
swalConfirmAction,
swalShowError,
swalShowInfo,
swalShowLoading,
} from "../../../../../scripts/utils/swal-utils";
import { clientError } from "../../../../../scripts/others/http-error-handler/error-handler";

export const accountsClickHandlers = async (index) => {
switch (index) {
case 0:
connectPennsieveAccountClickHandler();
break;
case 1:
changeWorkspaceClickHandler();
break;
case 2:
disconnectPennsieveAccountClickHandler();
break;
case 3:
testPennsieveConnectionClickHandler();
break;
default:
console.log("Invalid row index");
break;
}
};

const connectPennsieveAccountClickHandler = () => {
window.addBfAccount(null, false);
};

const changeWorkspaceClickHandler = () => {
window.openDropdownPrompt(null, "organization", false);
};

const disconnectPennsieveAccountClickHandler = async () => {
let defaultProfile = window.getDefaultProfile();
if (!defaultProfile) {
swalShowError(
"Cannot Disconnect Account",
"If you have previously connected your Pennsieve account with SODA then you will need to make it the active account before you can disconnect it. To make your account active please click the 'Connect Your Pennsieve Account' option. "
);
return;
}
// TODO: Force user to login and check the resulting profile matches the current account before allowing them to disconnect?
let response = await swalConfirmAction(
"warning",
"Disconnect Pennsieve Account from SODA",
"You will need to reconnect your Pennsieve account to use Pennsieve features in SODA. Are you sure you want to disconnect?",
"Yes",
"No"
);
if (response) {
window.disconnectPennsieveAccount(defaultProfile.profile_key);
}
};

const testPennsieveConnectionClickHandler = async () => {
swalShowLoading("Testing Connection", "Please wait while we test your connection to Pennsieve.");

if (
!(
window.defaultBfAccount !== undefined ||
(window.defaultBfAccount === undefined && window.getDefaultProfile())
)
) {
await new Promise((resolve) => setTimeout(resolve, 1000));
await swalShowError(
"No Pennsieve Account Connected",
"Please use the 'Connect Your Pennsieve Account' option and try again."
);
return;
}

try {
const accountValid = await window.check_api_key();
if (!accountValid) {
await swalShowError(
"Your Pennsieve account connected to SODA is invalid",
"Please use the 'Connect Your Pennsieve Account' option and try again."
);
return;
}
await window.synchronizePennsieveWorkspace();
} catch (e) {
clientError(e);
await swalShowInfo(
"Something went wrong while verifying your profile",
"Please try again. If this issue persists please use our `Contact Us` page to report the issue."
);
return;
}

swalShowInfo(
"Connection Test Passed",
"All Pennsieve based features of SODA should work as expected."
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { accountsClickHandlers } from "./clickHandlersAccounts/clickHandlerAccounts";

export const getClickHandlerFunctions = (id) => {
if (id === "account-options-table") {
return accountsClickHandlers;
} else {
return () => console.log("No click handler found for this table");
}
};
23 changes: 17 additions & 6 deletions src/renderer/src/components/tables/singleColumn/index.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import { Table } from "@mantine/core";
import useGlobalStore from "../../../stores/globalStore";
import { getClickHandlerFunctions } from "./clickHandlers/clickHandlersFactory";
import { getRowConfiguration } from "./rows/rowConfigurationFactory";

const SingleColumnTable = ({ columnName, id }) => {
const handleRowClick = (index) => {
let clickHandlerFunction = getClickHandlerFunctions(id);
clickHandlerFunction(index);
};

const rowConfiguration = getRowConfiguration(id);

const rowData = useGlobalStore((state) => state.tableData[id]) || [];

const rows = rowData.map((row, index) => {
return (
<Table.Tr key={index}>
<Table.Td style={{ textAlign: "left" }}>{row}</Table.Td>
</Table.Tr>
);
return rowConfiguration(row, index, handleRowClick);
});

const tableProps = {
withTableBorder: true,
highlightOnHover: true,
};

return (
<Table withTableBorder highlightOnHover>
<Table {...tableProps}>
<Table.Thead>
<Table.Tr>
<Table.Th>{columnName}</Table.Th>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Table } from "@mantine/core";

export const defaultRow = (row, index, handleRowClick) => (
<Table.Tr key={index} onClick={() => handleRowClick(index)}>
<Table.Td style={{ textAlign: "left" }}>{row}</Table.Td>
</Table.Tr>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Table } from "@mantine/core";
import { IconChevronRight } from "@tabler/icons-react";

export const singleColumnIconAfterTextRow = (row, index, handleRowClick) => (
<Table.Tr key={index} onClick={() => handleRowClick(index)}>
<Table.Td style={{ textAlign: "left", cursor: "pointer" }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
}}
>
{row}
<IconChevronRight />
</div>
</Table.Td>
</Table.Tr>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { singleColumnIconAfterTextRow } from "./iconAfterTextRow";
import { defaultRow } from "./defaultRow";

export const getRowConfiguration = (id) => {
if (id === "account-options-table") {
return singleColumnIconAfterTextRow;
} else {
return defaultRow;
}
};
1 change: 1 addition & 0 deletions src/renderer/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import "./scripts/advanced-features/advanced_features";
import "./scripts/sds-templates/sds_templates";
import "./scripts/organize-dataset/verify-file-statuses";
import "./scripts/advanced-features/compare-local-remote-dataset";
import "./scripts/accounts/accounts";

// Application Lotties
import "./assets/lotties/activate-lotties";
Expand Down
Loading

0 comments on commit 0b68a93

Please sign in to comment.