Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 1.5.0 #269

Merged
merged 58 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
eac8ebe
AREG-140 - fix - return all (including non curated) antibodies when i…
D-GopalKrishna May 31, 2024
74ba8ab
AREG-140 - fix helper filter structure and create isFilterAndSortMode…
D-GopalKrishna May 31, 2024
1c807c8
AREG-140 - add activeTab to navbar-searchbar and update filterableCol…
D-GopalKrishna May 31, 2024
e7d187e
AREG-140 remove clearSearch and add Antibody API calls + util update
D-GopalKrishna May 31, 2024
cf59aad
AREG-140 cross url maintain filters and sorting models
D-GopalKrishna May 31, 2024
26ecef8
AREG-140 user's antibodies filter
D-GopalKrishna Jun 3, 2024
7970dbb
AREG-140 update the tests
D-GopalKrishna Jun 3, 2024
8dedbb9
AREG-140 adapt FE for my submission bug
D-GopalKrishna Jun 3, 2024
8d13978
AREG-140 additional comments as notes
D-GopalKrishna Jun 3, 2024
be7ef65
Merge pull request #254 from MetaCell/feature/AREG-140
filippomc Jun 4, 2024
ef529d6
Merge branch 'release/1.4.0' into develop
filippomc Jun 18, 2024
e1a4abd
Add ix to export query
filippomc Jun 27, 2024
65a9414
AREG-search-catalog-number-fix - add ix to the sorting annotation in …
D-GopalKrishna Jul 5, 2024
fe60913
Add content history
filippomc Jul 8, 2024
6b22c18
Build fix
filippomc Jul 8, 2024
ff953fd
AREG-143 add new partner logo
Aiga115 Sep 9, 2024
8a7b811
AREG-143 change link of partners logo
Aiga115 Sep 9, 2024
25c597b
Merge pull request #261 from MetaCell/feature/AREG-143
filippomc Sep 9, 2024
ff6a280
migration to muiv6 - grid and system mui changes
Aiga115 Sep 12, 2024
05f0afd
migration to mui v6 - slotProps change, grid and mui system props change
Aiga115 Sep 12, 2024
ae026e2
migration mui v6 - theme variants change
Aiga115 Sep 12, 2024
ad2adea
migration mui v6-change sx props in datagrid component
Aiga115 Sep 12, 2024
9bd415e
migration mui v6-datagrid component migration
Aiga115 Sep 12, 2024
ba2cb58
AREG-144 add new partners
Aiga115 Sep 13, 2024
30c507e
Merge pull request #263 from MetaCell/feature/AREG-144
filippomc Sep 13, 2024
cd5ce5b
Merge branch 'feature/migration_mui' of github.com:MetaCell/scicrunch…
filippomc Sep 17, 2024
816d25e
mui migration v6-update package.json file
Aiga115 Sep 17, 2024
92cb31b
Merge branch 'feature/migration_mui' of github.com:MetaCell/scicrunch…
filippomc Sep 17, 2024
39f6c8c
migration mui v6 - change made to hideable
Aiga115 Sep 17, 2024
d3b6fbd
Merge branch 'feature/migration_mui' of github.com:MetaCell/scicrunch…
filippomc Sep 18, 2024
7ddd714
Mui migration fix
filippomc Sep 18, 2024
db799e3
Linting fixes
filippomc Sep 18, 2024
ac6abb5
mui_migration_v7 - change to grid toolbar columns button and valueGet…
Aiga115 Sep 18, 2024
a464277
Fix linted code issues
filippomc Sep 18, 2024
cc6af47
Fix linted code issues
filippomc Sep 18, 2024
4fd293b
Merge branch 'feature/mui_migration_v7' of github.com:MetaCell/scicru…
filippomc Sep 18, 2024
5fda5f1
Update yarn.lock
filippomc Sep 18, 2024
bf09a58
AREG-147 fix filter name in data grid, checkbox selected state and al…
Aiga115 Sep 27, 2024
c211955
Merge pull request #265 from MetaCell/feature/AREG-147
filippomc Sep 27, 2024
3f1ba55
AREG-148 - Fix return value in plain_filter_antibodies function
D-GopalKrishna Sep 30, 2024
76382bc
AREG-148 - pass empty filterModel - when tab is changed
D-GopalKrishna Sep 30, 2024
a947f5c
AREG-148 - empty the filterModel and sortModel - when tab is changed …
D-GopalKrishna Sep 30, 2024
4d8dde6
AREG-148 - empty the sortModel - when tab is changed
D-GopalKrishna Sep 30, 2024
65c1b3f
AREG-148 rename applyFilter to applyFilterAndSortModels and update co…
D-GopalKrishna Sep 30, 2024
7c7bc0b
Merge pull request #266 from MetaCell/feature/AREG-148
filippomc Sep 30, 2024
7dd982b
Improve last update calc
filippomc Sep 30, 2024
17d7c13
refactor: add react level caching, fix a few warnings
filippomc Sep 30, 2024
d6299b3
Fix update to no value
filippomc Sep 30, 2024
8f8d3f3
Fix local web server redirect issue
filippomc Sep 30, 2024
8adc531
Chore: change deprecated webpack API
filippomc Sep 30, 2024
257031b
Increase server workers
filippomc Oct 1, 2024
170cbe9
e2e test tweak
filippomc Oct 1, 2024
be52561
Tweak resources requests
filippomc Oct 1, 2024
2d6f1d0
fix-table-ui align data grid cells
Aiga115 Oct 1, 2024
547bbe6
fix-table-ui change made
Aiga115 Oct 1, 2024
eae422f
Merge pull request #267 from MetaCell/feature/fix-table-ui
filippomc Oct 1, 2024
d0d133f
fix-table change made
Aiga115 Oct 1, 2024
35d6a75
Merge pull request #268 from MetaCell/feature/fix-table
filippomc Oct 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion applications/accounts-api/backend/accounts_api/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@


if __name__ == '__main__':
main()
main()
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,3 @@ def info_from_bearerAuth(token):
:rtype: dict | None
"""
return {'uid': 'user_id'}

Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def users_username_password_put(username, update_password: UpdatePassword = None
user_service.update_password(username, update_password.new_password)
return "OK", 204


def users_username_orcid_put(username, body): # noqa: E501
"""users_username_orcid_put

Expand All @@ -108,5 +109,5 @@ def users_username_orcid_put(username, body): # noqa: E501
if not user_service.validate_orcid_id(body):
return "Invalid ORCID ID", 400
user_service.associate_orcid_id(username, body)

return "OK", 204
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ class UserNotFound(Exception):
class UserNotAuthorized(Exception):
pass


class ValidationError(Exception):
pass


def get_user(userid: str) -> User:
try:
client = AuthClient()
Expand Down Expand Up @@ -112,7 +114,7 @@ def update_user(userid, user: User):
}
}

admin_client.update_user(userid, updated_user)
admin_client.update_user(userid, updated_user)
return get_user(userid)
except KeycloakError as e:
if e.response_code == 404:
Expand Down Expand Up @@ -145,13 +147,14 @@ def update_password(username: str, new_password: str):
raise Exception(
"Unhandled Keycloak exception while updating user") from e


def associate_orcid_id(userid: str, orcid: str):
client = AuthClient()
admin_client = client.get_admin_client()
try:
orcid_no_prefix = orcid.replace("https://orcid.org/", "")

admin_client.update_user(userid, {"attributes": {"orcid": orcid}})
admin_client.update_user(userid, {"attributes": {"orcid": orcid}})
admin_client.add_user_social_login(userid, "orcid", orcid_no_prefix, orcid_no_prefix)
except KeycloakError as e:
try:
Expand All @@ -161,5 +164,6 @@ def associate_orcid_id(userid: str, orcid: str):
raise Exception(
"Unhandled Keycloak exception while updating user") from e

def validate_orcid_id( orcid: str) -> bool:

def validate_orcid_id(orcid: str) -> bool:
return re.match(r'^https://orcid.org/\d{4}-\d{4}-\d{4}-\d{3}[0-9X]$', orcid)
8 changes: 4 additions & 4 deletions applications/accounts-api/backend/accounts_api/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ def deserialize_date(string):
:rtype: date
"""
if string is None:
return None
return None

try:
from dateutil.parser import parse
return parse(string).date()
Expand All @@ -88,8 +88,8 @@ def deserialize_datetime(string):
:rtype: datetime
"""
if string is None:
return None
return None

try:
from dateutil.parser import parse
return parse(string)
Expand Down
1 change: 0 additions & 1 deletion applications/accounts-api/backend/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,3 @@
accounts_api
"""
)

8 changes: 4 additions & 4 deletions applications/portal/api/templates/main.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ app.add_middleware(
allow_headers=["*"],
)

from cloudharness.middleware import set_authentication_token, get_authentication_token
from cloudharness.middleware import set_authentication_token, get_authentication_token # noqa E402

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
Expand All @@ -67,8 +67,8 @@ async def add_process_time_header(request: Request, call_next):
if os.environ.get('KUBERNETES_SERVICE_HOST', None):
# init the auth service when running in/for k8s
import threading
from cloudharness_django.services import get_auth_service, init_services
from cloudharness import log
from cloudharness_django.services import get_auth_service, init_services # noqa E402
from cloudharness import log # noqa E402
import time
def start_auth_service():
try:
Expand Down Expand Up @@ -146,6 +146,6 @@ app.mount("/", get_asgi_application())
# import uvicorn
# uvicorn.run(app, host="0.0.0.0", port=8000)

from api.helpers import init_sentry
from api.helpers import init_sentry # noqa E402

init_sentry()
34 changes: 19 additions & 15 deletions applications/portal/backend/api/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from django.utils.html import escape, format_html, format_html_join, mark_safe
from django.utils.text import format_lazy
from import_export.admin import ImportExportModelAdmin
from simple_history.admin import SimpleHistoryAdmin
from keycloak.exceptions import KeycloakGetError
from cloudharness_django.models import Member

Expand All @@ -36,13 +37,14 @@
def id_with_ab(obj: Antibody):
return f"AB_{obj.ab_id}"


@cache
def get_user_by_kc_id(kc_id) -> User:
try:
return Member.objects.get(kc_id=kc_id).user
except Member.DoesNotExist:
return None


class VerboseManyToManyRawIdWidget(ManyToManyRawIdWidget):
"""
Expand Down Expand Up @@ -100,20 +102,21 @@ class AntibodyFilesAdmin(admin.TabularInline):
extra = 1


# not in fields - catalog_num_search
# not in fields - catalog_num_search
antibody_fields_shown = (
"ab_name", "ab_id", "accession", "commercial_type", "catalog_num", "cat_alt", "citation", "vendor",
"url","ab_target", "entrez_id", "uniprot_id", "target_species_raw", "subregion",
"ab_name", "ab_id", "accession", "commercial_type", "catalog_num", "cat_alt", "citation", "vendor",
"url", "ab_target", "entrez_id", "uniprot_id", "target_species_raw", "subregion",
"modifications", "epitope", "source_organism", "clonality", "clone_id", "product_isotype",
"product_conjugate", "defining_citation", "product_form", "comments",
"kit_contents", "feedback", "curator_comment", "disc_date", "status", "show_link",
# also in the read-only fields
"uid", "uid_legacy", "insert_time", "lastedit_time", "curate_time",
)


@admin.register(Antibody)
class AntibodyAdmin(ImportExportModelAdmin):
class AntibodyAdmin(ImportExportModelAdmin, SimpleHistoryAdmin):

change_form_template = "admin/antibody_change_form.html"

# Import/Export module settings
Expand All @@ -130,7 +133,7 @@ class AntibodyAdmin(ImportExportModelAdmin):
fields = antibody_fields_shown

inlines = [TargetSpeciesInlineAdmin, AntibodyFilesAdmin, ApplicationsInlineAdmin]

readonly_fields = (
"submitter_name",
"submitter_email",
Expand All @@ -143,11 +146,11 @@ class AntibodyAdmin(ImportExportModelAdmin):
)
autocomplete_fields = ("vendor", "source_organism")
save_on_top = True
show_save=False
show_save = False

formfield_overrides = {
models.CharField: {'widget': TextInput(attrs={'size':'120'})},
models.TextField: {'widget': Textarea(attrs={'rows':2, 'cols':120})}
models.CharField: {'widget': TextInput(attrs={'size': '120'})},
models.TextField: {'widget': Textarea(attrs={'rows': 2, 'cols': 120})}
}

@property
Expand All @@ -163,7 +166,7 @@ def get_user(self, user_id):
def submitter_name(self, obj: Antibody):
if not obj.uid:
return "Unknown"

dj_user: User = get_user_by_kc_id(obj.uid)
if dj_user:
return f"{dj_user.get_full_name()} ({dj_user.username})"
Expand All @@ -185,7 +188,7 @@ def submitter_email(self, obj: Antibody):
dj_user: User = get_user_by_kc_id(obj.uid)
if dj_user:
return dj_user.email

try:
submitter = self.get_user(user_id=obj.uid)
return f"{submitter['email']}"
Expand Down Expand Up @@ -337,10 +340,10 @@ def queryset(self, request, queryset):
if self.value():
return queryset.filter(vendor__commercial_type=self.value())
return queryset


@admin.register(VendorDomain)
class VendorDomainAdmin(admin.ModelAdmin):
class VendorDomainAdmin(SimpleHistoryAdmin):
list_display = (
"base_url",
"vendor",
Expand All @@ -350,8 +353,9 @@ class VendorDomainAdmin(admin.ModelAdmin):
list_editable = ("is_domain_visible",)
list_filter = [CommercialTypeFilter]


@admin.register(Vendor)
class VendorAdmin(admin.ModelAdmin):
class VendorAdmin(SimpleHistoryAdmin):
delete_confirmation_template = "admin/vendor/delete_confirmation.html"
search_fields = ("name",)
list_display = ("id", "name", "commercial_type", "nif_id", "eu_id")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from openapi.models import UpdateAntibody as UpdateAntibodyDTO
from openapi.models import Antibody as AntibodyDTO


def get_antibodies(page: int, size: int, updated_from: datetime, updated_to: datetime, status=str) -> PaginatedAntibodies:
if page is None:
page = 1
Expand Down Expand Up @@ -82,9 +83,10 @@ def update_user_antibody(accession_number: str, body: UpdateAntibodyDTO) -> Anti


def delete_antibody(antibody_id: str) -> None:
#FIXME this must be protected
# FIXME this must be protected
return antibody_service.delete_antibody(antibody_id)


def get_by_accession(accession_number: int) -> AntibodyDTO:
try:
return antibody_service.get_antibody_by_accession(accession_number)
Expand All @@ -104,7 +106,6 @@ def get_antibodies_export():
# return FileResponse(fname, filename="antibodies_export.csv")



def get_antibodies_export_admin():
"""
Export all fields of all antibodies to a CSV file - Only for admin users
Expand All @@ -119,6 +120,3 @@ def get_antibodies_export_admin():
if filesystem_service.check_if_file_exists_and_recent(fname) and is_admin:
generate_all_antibodies_fields_to_csv(fname)
return RedirectResponse("/" + fname)



Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from openapi.models import DataInfo
from api.services import antibody_service


def get_datainfo():
return DataInfo(total=antibody_service.count(), lastupdate=antibody_service.last_update())
return DataInfo(total=antibody_service.count(), lastupdate=antibody_service.last_update())
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ def ingest(body: IngestRequest):
detail="You are not authorized to ingest data.")
except:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="You are not authorized to ingest data.")
detail="You are not authorized to ingest data.")
execute_ingestion_workflow(body.driveLinkOrId, body.hot)
return status.HTTP_200_OK



2 changes: 1 addition & 1 deletion applications/portal/backend/api/helpers/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .sentry import init_sentry
from .sentry import init_sentry
5 changes: 3 additions & 2 deletions applications/portal/backend/api/helpers/sentry.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import re
from cloudharness import log


def init_sentry():
try:

app_cfg = get_current_configuration()
sentry_cfg = app_cfg.get("sentry", {})
resources_extensions = set(["css", "js", "png", "jpg", "jpeg", "gif", "svg", "ico", "xml"])
Expand All @@ -24,7 +25,7 @@ def traces_sampler(sampling_context):
extension = "." in url and url.split(".")[-1]
if extension in resources_extensions:
return sentry_cfg.get("traces_sample_rate_resources", 0.0)

return sentry_cfg.get("traces_sample_rate", 1.0)

sentry.init(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
CLONALITIES = {c[0] for c in AntibodyClonality.choices}
COMMERCIAL_TYPES = {c[0] for c in CommercialType.choices}


class AntibodyIdentifier:
def __init__(self, fields, condition: Callable, q: Callable, filter_dataset: Callable):
"""
Expand Down
2 changes: 1 addition & 1 deletion applications/portal/backend/api/import_export/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .AntibodyResource import AntibodyResource # noqa: F401
from .AntibodyResource import AntibodyResource # noqa: F401
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ def get_antibody_q2(dataset, catalog_number_field, vendor_field) -> Q:
**{"%s__%s__in" % (vendor_field.attribute, vendor_field.widget.field): remove_empty_string(
dataset[vendor_field.column_name])})


def filter_dataset_by_ix(dataset, negate, antibodies):
values = (str(antibody.ix) for antibody in antibodies)
condition = dataset.df['ix'].isin(values)
return ~condition if negate else condition


def filter_dataset_by_accession(dataset, negate, antibodies):
values = (str(antibody.accession) for antibody in antibodies)
condition = dataset.df['accession'].isin(values)
Expand Down Expand Up @@ -64,5 +66,5 @@ def filter_dataset_by_catnum_vendor(dataset, negate, antibodies, catalog_number_
antibody_catalog_numbers.append(antibody.catalog_num)
antibody_vendor_names.append(antibody.vendor.name)
condition = dataset.df[catalog_number_field.column_name].isin(antibody_catalog_numbers) & \
dataset.df[vendor_field.column_name].isin(antibody_vendor_names)
dataset.df[vendor_field.column_name].isin(antibody_vendor_names)
return ~condition if negate else condition
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ def clean(self, value, row=None, **kwargs):
return self.model.objects.none()
else:
ids = value.split(self.separator)
return [self.get_or_create(**{self.field: i.strip()}) for i in ids]
return [self.get_or_create(**{self.field: i.strip()}) for i in ids]
5 changes: 3 additions & 2 deletions applications/portal/backend/api/management/commands/ingest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ def parse_drive_link(drive_link_or_id: str):
except:
# https://drive.google.com/file/d/FILE_ID/view?usp=drive_link
return drive_link_or_id.split("/")[-2]



class Command(BaseCommand):
help = "Ingests antibody data into the database"

def add_arguments(self, parser):
parser.add_argument("file_id", type=str)
parser.add_argument("--hot", action="store_true",
help="execute a hot load (no replacements)",)
help="execute a hot load (no replacements)",)

def handle(self, *args, **options):
metadata = Preprocessor(parse_drive_link(options["file_id"])).preprocess()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def log(self, msg):

def handle(self, *args, **options):
requests_per_second_limit = options.get('max_requests_per_second', 10)

antibodies_ids = get_curated_antibodies_ids()

api_request_rate_limiter = RateLimiter(
Expand Down Expand Up @@ -64,8 +64,6 @@ def process_antibody_ingestion(self, ab_id):
ingested = set_citation_metric(
ab_id, number_of_citations)



def log_failed_antibodies(self, failed_antibody_ids):
if failed_antibody_ids:
antibodies_failed = (
Expand Down
Loading
Loading