Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
a2a61ec
add attibute button html
ZinnurovArtur Mar 4, 2024
8a9657d
some logic in concept creator
ZinnurovArtur Mar 4, 2024
96d2d69
adding the attribute component
ZinnurovArtur Mar 8, 2024
2542464
initialize the component inside creator
ZinnurovArtur Mar 8, 2024
b6dd169
adding to the concept create page
ZinnurovArtur Mar 8, 2024
a3b8be7
adding the input values
ZinnurovArtur Mar 10, 2024
706ed7d
deleted some spaces
ZinnurovArtur Mar 11, 2024
db06dbe
Merge remote-tracking branch 'origin/Development' into artur-workings…
ZinnurovArtur Apr 3, 2024
788ef05
adding icon to the attribute button
ZinnurovArtur Apr 3, 2024
b92513d
using basic style
ZinnurovArtur Apr 3, 2024
1c44ff7
some experiments
ZinnurovArtur Apr 15, 2024
d04d841
some data is returning
ZinnurovArtur Apr 15, 2024
37fc043
adding components for testing
ZinnurovArtur May 20, 2024
39f8710
Merge remote-tracking branch 'origin/Development' into artur-workings…
ZinnurovArtur May 20, 2024
efa421e
deleted title
ZinnurovArtur May 28, 2024
662dc90
adding different dropdown
ZinnurovArtur May 28, 2024
9382dc6
attribute type for input
ZinnurovArtur May 28, 2024
40d6d18
adding the test modal with attributes
ZinnurovArtur Jun 10, 2024
0c1f92c
adding test mockup modal
ZinnurovArtur Jun 10, 2024
ecb2ef5
call the import setting for now
ZinnurovArtur Jun 17, 2024
04b7af5
adding the setting page for attributs
ZinnurovArtur Jun 25, 2024
f9d183b
call modal attribute for now
ZinnurovArtur Jun 26, 2024
0dbc4cd
deleting unused
ZinnurovArtur Jun 27, 2024
58e2bf3
delete unused code
ZinnurovArtur Jul 1, 2024
44bdd8d
deletion some other code
ZinnurovArtur Jul 1, 2024
b19375e
deleted unused
ZinnurovArtur Jul 16, 2024
c41a886
table test addition
ZinnurovArtur Jul 16, 2024
4ce9873
adding package to html
ZinnurovArtur Jul 16, 2024
fc772ca
Merge remote-tracking branch 'origin/Development' into artur-workings…
ZinnurovArtur Aug 5, 2024
dd30ab3
using the different package installer
ZinnurovArtur Aug 5, 2024
5e40fca
gridjs example
ZinnurovArtur Aug 5, 2024
632f2dc
remove unused
ZinnurovArtur Aug 5, 2024
66a51ea
again removed unused
ZinnurovArtur Aug 6, 2024
ec054f1
adjusting the concept data
ZinnurovArtur Aug 6, 2024
2a637b3
deleting unused functions again
ZinnurovArtur Aug 6, 2024
a3e6b04
removed unused and adding the js fetch concepts
ZinnurovArtur Aug 6, 2024
52eee38
adding none list available page
ZinnurovArtur Sep 9, 2024
fdea508
adding the button and attribute creation test
ZinnurovArtur Sep 11, 2024
1ae9133
adding button different place
ZinnurovArtur Sep 11, 2024
c6fe7d1
adding id
ZinnurovArtur Sep 16, 2024
e16ad67
test adding the creation
ZinnurovArtur Sep 16, 2024
3fdd987
adding templates
ZinnurovArtur Sep 16, 2024
ebb6d26
adding some test component of attribute addition
ZinnurovArtur Sep 18, 2024
3420956
adding the attribute value addition
ZinnurovArtur Sep 18, 2024
ecddfc3
removed unused and adding the creation logic
ZinnurovArtur Sep 19, 2024
57aa9a4
Merge remote-tracking branch 'origin/Development' into artur-workings…
ZinnurovArtur Sep 19, 2024
2e1c873
forgot tinymde
ZinnurovArtur Sep 19, 2024
74fba6d
adding column addition
ZinnurovArtur Sep 19, 2024
db84fba
adding ids to the component
ZinnurovArtur Sep 20, 2024
4acec44
formating and adding new checks
ZinnurovArtur Sep 20, 2024
8a01fa8
adding dynamic value retrive
ZinnurovArtur Sep 20, 2024
0592cfd
adding dynamic editor
ZinnurovArtur Sep 20, 2024
db6f9fd
testing edit cell
ZinnurovArtur Sep 20, 2024
2f3ffc1
test if cell is editable
ZinnurovArtur Sep 20, 2024
b6f09b3
adding test function for cell
ZinnurovArtur Sep 23, 2024
3317fc1
deleted the input due to putting this inside of the cell
ZinnurovArtur Sep 23, 2024
1b31226
deleting inputs
ZinnurovArtur Sep 23, 2024
6b79db5
adding the uuid and value assing
ZinnurovArtur Sep 23, 2024
a9457c0
adding the cell editing to show the user progr3ess
ZinnurovArtur Sep 24, 2024
1e72fe3
adding data if no input
ZinnurovArtur Sep 24, 2024
d6fa558
adding type string description
ZinnurovArtur Sep 25, 2024
62594ed
adjusting the cancel button
ZinnurovArtur Sep 25, 2024
bb6c249
update the name and attribute on input
ZinnurovArtur Sep 25, 2024
75e2f23
some adjustments and refactor
ZinnurovArtur Sep 25, 2024
5bfc743
revert span button
ZinnurovArtur Sep 26, 2024
c36faca
adding the attribute test temporarly data
ZinnurovArtur Sep 27, 2024
6350f75
adding the delete icon for accrdion
ZinnurovArtur Sep 30, 2024
abe792f
adding delete button as component and manage the cancel
ZinnurovArtur Sep 30, 2024
f928147
adding delete button to the attribute row
ZinnurovArtur Sep 30, 2024
cea3802
adding logic to the delete button
ZinnurovArtur Sep 30, 2024
bbb6e69
adding check if user only adding attribute
ZinnurovArtur Sep 30, 2024
f65847b
adding map when try to retrive the attributes
ZinnurovArtur Sep 30, 2024
c2823df
removing log
ZinnurovArtur Sep 30, 2024
a629ebe
adding delete toast
ZinnurovArtur Sep 30, 2024
a1a9c2f
fix of attribute name validation
ZinnurovArtur Sep 30, 2024
665abf2
adding the button disabled in case of no concepts
ZinnurovArtur Sep 30, 2024
1caf598
removing console log and fix the deletion
ZinnurovArtur Oct 1, 2024
a731ccd
adding the placeholder functionality
ZinnurovArtur Oct 2, 2024
bbee729
Merge remote-tracking branch 'origin/Development' into artur-workings…
ZinnurovArtur Oct 3, 2024
6e28ac0
Fix the duplicated attribute name
ZinnurovArtur Oct 8, 2024
5c7f304
moved the invoke elements so can be find in builddialgoe
ZinnurovArtur Oct 8, 2024
fda60b7
adding validation to the backend
ZinnurovArtur Oct 8, 2024
e43a8f5
adding better form of hide button
ZinnurovArtur Oct 8, 2024
b96544e
adding some different form of validation and same for creattion
ZinnurovArtur Oct 8, 2024
b3def75
adding attributes to the backend
ZinnurovArtur Oct 8, 2024
a9a5b67
even if empty still proceed
ZinnurovArtur Oct 8, 2024
ab74e03
fix of not showing button
ZinnurovArtur Oct 8, 2024
4ecdda4
fixing the attribute index change
ZinnurovArtur Oct 8, 2024
67bcd27
showing the attributes in the concept data request
ZinnurovArtur Oct 8, 2024
27de5c0
appending attributes to the concept_data
ZinnurovArtur Oct 8, 2024
63f8dc4
check if concept is new
ZinnurovArtur Oct 8, 2024
c1949bd
showing the attriubes to the api
ZinnurovArtur Oct 10, 2024
e54bbac
adding the validation
ZinnurovArtur Oct 28, 2024
af09921
check if string is empty
ZinnurovArtur Oct 28, 2024
c6e6a4f
adding docs
ZinnurovArtur Oct 28, 2024
5ead994
removed console logs
ZinnurovArtur Oct 28, 2024
69a5de6
check if empty and showing the attribute to the codelist
ZinnurovArtur Oct 28, 2024
187a932
adding to the page render concept_attributes
ZinnurovArtur Oct 28, 2024
380ff7a
bug fixes of adding existing concepts or emtpy concepts without attr
ZinnurovArtur Nov 6, 2024
a2357fe
adding checks on the backend
ZinnurovArtur Nov 6, 2024
8f114f9
removed console log
ZinnurovArtur Nov 6, 2024
5e8c4ac
adding another regex check
ZinnurovArtur Nov 19, 2024
c41f15c
removing string validation on the backend
ZinnurovArtur Nov 19, 2024
4d8474d
fixing showing the concept attribute in the detail page
ZinnurovArtur Dec 6, 2024
cb99cbe
removing unpackage for js
ZinnurovArtur Dec 6, 2024
97e91d7
adding grid js scss
ZinnurovArtur Dec 6, 2024
628423d
adding grid.js to the create scss
ZinnurovArtur Dec 6, 2024
5c631d3
adjusting the float values
ZinnurovArtur Dec 6, 2024
0dcae45
scss changes
ZinnurovArtur Dec 9, 2024
d2670f3
Merge remote-tracking branch 'origin/AZ/dev-upstream' into artur-work…
ZinnurovArtur Jan 21, 2025
e665981
removed some comments
ZinnurovArtur Jan 21, 2025
17ee8ab
renamed to accordion and changed id
ZinnurovArtur Jan 21, 2025
813009c
renamded to accordion
ZinnurovArtur Jan 21, 2025
b8ac044
Updated workingset (#1775)
JackScanlon Jan 22, 2025
11f6c63
Adding workingset from upstream (#1778)
ZinnurovArtur Mar 25, 2025
09db2a2
fix: fixing the js file for attributes tool
ZinnurovArtur Mar 25, 2025
aff8c42
feat: Feat/hdrn (#1790)
ieuans Jun 27, 2025
dd036f9
Merge branch 'master' into Development
JackScanlon Jun 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions .github/workflows/testing-pipline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@ jobs:
steps:
- uses: actions/checkout@v3
- run: |
sudo apt-get update
sudo apt-get install -y libgconf-2-4 libatk1.0-0 libatk-bridge2.0-0 libgdk-pixbuf2.0-0 libgtk-3-0 libgbm-dev libnss3-dev libxss-dev libasound2
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y libgconf-2-4 libatk1.0-0 libatk-bridge2.0-0 libgdk-pixbuf2.0-0 libgtk-3-0 libgbm-dev libnss3-dev libxss-dev libasound2
- uses: browser-actions/setup-chrome@v1
- uses: actions/cache@v3
with:
Expand All @@ -65,6 +64,7 @@ jobs:

- name: Install Dependencies
run: |
sudo apt-get install -y -q dirmngr
python -m pip install --upgrade pip
pip install --upgrade --upgrade-strategy eager --default-timeout 100 -r docker/requirements/test.txt

Expand Down
49 changes: 46 additions & 3 deletions CodeListLibrary_project/clinicalcode/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
from .models.GenericEntity import GenericEntity
from .models.Template import Template
from .models.OntologyTag import OntologyTag
from .models.Organisation import Organisation
from .models.DMD_CODES import DMD_CODES

from .forms.TemplateForm import TemplateAdminForm
from .forms.EntityClassForm import EntityAdminForm
from .forms.OrganisationForms import OrganisationAdminForm, OrganisationMembershipInline, OrganisationAuthorityInline

@admin.register(OntologyTag)
class OntologyTag(admin.ModelAdmin):
Expand Down Expand Up @@ -51,10 +54,9 @@ def save_model(self, request, obj, form, change):

@admin.register(Brand)
class BrandAdmin(admin.ModelAdmin):
list_display = ['name', 'id', 'logo_path', 'owner', 'description']
list_filter = ['name', 'description', 'created', 'modified', 'owner']
list_filter = ['name', 'description', 'created', 'modified']
list_display = ['name', 'id', 'logo_path', 'description']
search_fields = ['name', 'id', 'description']
exclude = ['created_by', 'updated_by']


@admin.register(DataSource)
Expand All @@ -72,6 +74,47 @@ class CodingSystemAdmin(admin.ModelAdmin):
search_fields = ['name', 'codingsystem_id', 'description']
exclude = []

@admin.register(Organisation)
class OrganisationAdmin(admin.ModelAdmin):
"""
Organisation admin representation
"""
form = OrganisationAdminForm
inlines = [OrganisationMembershipInline, OrganisationAuthorityInline]
#exclude = ['created', 'owner', 'members', 'brands']

list_filter = ['id', 'name']
search_fields = ['id', 'name']
list_display = ['id', 'name', 'slug']
prepopulated_fields = {'slug': ['name']}

def get_form(self, request, obj=None, **kwargs):
"""
Responsible for pre-populating form data & resolving the associated model form

Args:
request (RequestContext): the request context of the form
obj (dict|None): an Organisation model instance (optional; defaults to `None`)
**kwargs (**kwargs): arbitrary form key-value pair data

Returns:
(OrganisationModelForm) - the prepared ModelForm instance
"""
form = super(OrganisationAdmin, self).get_form(request, obj, **kwargs)

if obj is None:
form.base_fields['slug'].initial = ''
form.base_fields['created'].initial = timezone.now()
else:
form.base_fields['slug'].initial = obj.slug
form.base_fields['created'].initial = obj.created

form.base_fields['slug'].disabled = True
form.base_fields['slug'].help_text = 'This field is not editable'
form.base_fields['created'].disabled = True
form.base_fields['created'].help_text = 'This field is not editable'

return form

@admin.register(Template)
class TemplateAdmin(admin.ModelAdmin):
Expand Down
3 changes: 3 additions & 0 deletions CodeListLibrary_project/clinicalcode/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ def get_schema(self, request=None, public=False):
url(r'^data-sources/$',
DataSource.get_datasources,
name='data_sources'),
url(r'^data-sources/(?P<datasource_id>[\d-]+)/export/$',
DataSource.get_datasource_internal_detail,
name='data_source_by_internal_id'),
url(r'^data-sources/(?P<datasource_id>[\w-]+)/detail/$',
DataSource.get_datasource_detail,
name='data_source_by_id'),
Expand Down
54 changes: 36 additions & 18 deletions CodeListLibrary_project/clinicalcode/api/views/Collection.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,46 @@
from rest_framework import status
from django.db.models import F, Q
from rest_framework.response import Response
from rest_framework.decorators import (api_view, permission_classes)
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.response import Response
from rest_framework import status
from django.db.models import F
from django.contrib.postgres.search import TrigramWordSimilarity

from ...models import Tag, GenericEntity
from ...entity_utils import api_utils
from ...entity_utils import constants
from ...entity_utils import constants, gen_utils, api_utils

@api_view(['GET'])
@permission_classes([IsAuthenticatedOrReadOnly])
def get_collections(request):
"""
Get all collections
Get all Collections

Available parameters:

| Param | Type | Default | Desc |
|---------------|-----------------|---------|---------------------------------------------------------------|
| search | `str` | `NULL` | Full-text search across _name_ field |
| id | `int/list[int]` | `NULL` | Match by a single `int` _id_ field, or match by array overlap |
"""
collections = Tag.objects.filter(
tag_type=constants.TAG_TYPE.COLLECTION.value
) \
.order_by('id')

result = collections.annotate(
name=F('description')
) \
.values('id', 'name')
search = request.query_params.get('search', '')

collections = Tag.get_brand_records_by_request(request, params={ 'tag_type': 2 })
if collections is not None:
if not gen_utils.is_empty_string(search) and len(search.strip()) > 1:
collections = collections.annotate(
similarity=TrigramWordSimilarity(search, 'description')
) \
.filter(Q(similarity__gte=0.7)) \
.order_by('-similarity')
else:
collections = collections.order_by('id')

collections = collections.annotate(
name=F('description')
) \
.values('id', 'name')

return Response(
data=list(result),
data=collections.values('id', 'name'),
status=status.HTTP_200_OK
)

Expand All @@ -36,8 +51,11 @@ def get_collection_detail(request, collection_id):
Get detail of specified collection by collection_id, including associated
published entities
"""
collection = Tag.objects.filter(id=collection_id)
if not collection.exists():
collection = Tag.get_brand_assoc_queryset(request.BRAND_OBJECT, 'collections')
if collection is not None:
collection = collection.filter(id=collection_id)

if not collection or not collection.exists():
return Response(
data={
'message': 'Collection with id does not exist'
Expand Down
4 changes: 2 additions & 2 deletions CodeListLibrary_project/clinicalcode/api/views/Concept.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def get_concepts(request):
query_clauses.append(psycopg2.sql.SQL('''(
setweight(to_tsvector('pg_catalog.english', coalesce(historical.name,'')), 'A') ||
setweight(to_tsvector('pg_catalog.english', coalesce(historical.description,'')), 'B')
) @@ to_tsquery('pg_catalog.english', replace(websearch_to_tsquery('pg_catalog.english', %(search_query)s)::text || ':*', '<->', '|'))
) @@ to_tsquery('pg_catalog.english', replace(to_tsquery('pg_catalog.english', concat(regexp_replace(trim(%(search_query)s), '\W+', ':* & ', 'gm'), ':*'))::text, '<->', '|'))
'''))

# Resolve pagination behaviour
Expand Down Expand Up @@ -422,7 +422,7 @@ def get_concept_detail(request, concept_id, version_id=None, export_codes=False,
if not user_can_access:
return Response(
data={
'message': 'Concept version must be published or you must have permission to access it'
'message': 'Entity version must be published or you must have permission to access it'
},
content_type='json',
status=status.HTTP_401_UNAUTHORIZED
Expand Down
148 changes: 134 additions & 14 deletions CodeListLibrary_project/clinicalcode/api/views/DataSource.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,159 @@
from rest_framework.decorators import (api_view, permission_classes)
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.response import Response
from rest_framework import status
from django.db.models import Subquery, OuterRef
from django.db.models import Q, Subquery, OuterRef
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from django.contrib.postgres.search import TrigramWordSimilarity

from ...models import DataSource, Template, GenericEntity
from ...entity_utils import api_utils
from ...entity_utils import gen_utils
from ...entity_utils import constants
from ...entity_utils import api_utils, gen_utils, constants

@api_view(['GET'])
@permission_classes([IsAuthenticatedOrReadOnly])
def get_datasources(request):
"""
Get all datasources
Get all DataSources

Available parameters:

| Param | Type | Default | Desc |
|---------------|-----------------|---------|---------------------------------------------------------------|
| search | `str` | `NULL` | Full-text search across _name_ and _description_ fields |
| id | `int/list[int]` | `NULL` | Match by a single `int` _id_ field, or match by array overlap |
| name | `str` | `NULL` | Case insensitive direct match of _name_ field |
| uid | `str/uuid` | `NULL` | Case insensitive direct match of _uid_ field |
| datasource_id | `int` | `NULL` | Match by exact _datasource_id_ |
| url | `str` | `NULL` | Case insensitive direct match of _url_ field |
| source | `str` | `NULL` | Case insensitive direct match of _source_ field |
"""
datasources = DataSource.objects.all().order_by('id')
datasources = list(datasources.values('id', 'name', 'url', 'uid', 'source'))
params = gen_utils.parse_model_field_query(DataSource, request, ignored_fields=['description'])
if params is not None:
datasources = DataSource.objects.filter(**params)
else:
datasources = DataSource.objects.all()

search = request.query_params.get('search')
if not gen_utils.is_empty_string(search) and len(search.strip()) > 3:
datasources = datasources.annotate(
similarity=(
TrigramWordSimilarity(search, 'name') + \
TrigramWordSimilarity(search, 'description')
)
) \
.filter(Q(similarity__gte=0.7)) \
.order_by('-similarity')
else:
datasources = datasources.order_by('id')

return Response(
data=datasources,
data=datasources.values('id', 'name', 'description', 'url', 'uid', 'datasource_id', 'source'),
status=status.HTTP_200_OK
)

@api_view(['GET'])
@permission_classes([IsAuthenticatedOrReadOnly])
def get_datasource_internal_detail(request, datasource_id):
"""
Get detail of specified datasource by by its internal Id
"""
query = None
if gen_utils.parse_int(datasource_id, default=None) is not None:
query = { 'id': int(datasource_id) }

if not query:
return Response(
data={
'message': 'Invalid id, expected int-like value'
},
content_type='json',
status=status.HTTP_400_BAD_REQUEST
)

datasource = DataSource.objects.filter(**query)
if not datasource.exists():
return Response(
data={
'message': 'Datasource with this internal Id does not exist'
},
content_type='json',
status=status.HTTP_404_NOT_FOUND
)

datasource = datasource.first()

# Get all templates and their versions where data_sources exist
templates = Template.history.filter(
definition__fields__has_key='data_sources'
) \
.annotate(
was_deleted=Subquery(
Template.history.filter(
id=OuterRef('id'),
history_date__gte=OuterRef('history_date'),
history_type='-'
)
.order_by('id', '-history_id')
.distinct('id')
.values('id')
)
) \
.exclude(was_deleted__isnull=False) \
.order_by('id', '-template_version', '-history_id') \
.distinct('id', 'template_version')

template_ids = list(templates.values_list('id', flat=True))
template_versions = list(templates.values_list('template_version', flat=True))

# Get all published entities with this datasource
entities = GenericEntity.history.filter(
template_id__in=template_ids,
template_version__in=template_versions,
publish_status=constants.APPROVAL_STATUS.APPROVED.value
) \
.extra(where=[f"""
exists(
select 1
from jsonb_array_elements(
case jsonb_typeof(template_data->'data_sources') when 'array'
then template_data->'data_sources'
else '[]'
end
) as val
where val in ('{datasource.id}')
)"""
]) \
.order_by('id', '-history_id') \
.distinct('id')

# Format results
entities = api_utils.annotate_linked_entities(entities)

result = {
'id': datasource.id,
'name': datasource.name,
'url': datasource.url,
'uid': datasource.uid,
'description': datasource.description,
'source': datasource.source,
'phenotypes': list(entities)
}

return Response(
data=result,
status=status.HTTP_200_OK
)

@api_view(['GET'])
@permission_classes([IsAuthenticatedOrReadOnly])
def get_datasource_detail(request, datasource_id):
"""
Get detail of specified datasource by datasource_id (id or HDRUK UUID for
linkage between applications), including associated published entities
Get detail of specified datasource by `datasource_id`, _i.e._ the HDRUK DataSource `pid` or its `UUID` for linkage between applications, including associated published entities.
"""
query = None
if gen_utils.is_valid_uuid(datasource_id):
query = { 'uid': datasource_id }
elif gen_utils.parse_int(datasource_id, default=None) is not None:
query = { 'id': int(datasource_id) }
query = { 'datasource_id': int(datasource_id) }

if not query:
return Response(
Expand Down
Loading
Loading