Skip to content

Commit 8715c7a

Browse files
authored
Merge pull request #1322 from microbiomedata/884-sortable-submissions-list
884 sortable submissions list
2 parents 8f2ebd9 + 2aea3e8 commit 8715c7a

File tree

10 files changed

+128
-17
lines changed

10 files changed

+128
-17
lines changed

nmdc_server/api.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -633,8 +633,10 @@ async def list_submissions(
633633
db: Session = Depends(get_db),
634634
user: models.User = Depends(get_current_user),
635635
pagination: Pagination = Depends(),
636+
column_sort: str = "created",
637+
sort_order: str = "desc",
636638
):
637-
query = crud.get_submissions_for_user(db, user)
639+
query = crud.get_submissions_for_user(db, user, column_sort, sort_order)
638640
return pagination.response(query)
639641

640642

@@ -671,6 +673,8 @@ async def get_submission(
671673
created=submission.created,
672674
author=schemas.User(**submission.author.__dict__),
673675
permission_level=permission_level,
676+
templates=submission.templates,
677+
study_name=submission.study_name,
674678
)
675679
if submission.locked_by is not None:
676680
submission_metadata_schema.locked_by = schemas.User(**submission.locked_by.__dict__)
@@ -938,8 +942,14 @@ async def submit_metadata(
938942
db: Session = Depends(get_db),
939943
user: models.User = Depends(get_current_user),
940944
):
941-
submission = SubmissionMetadata(**body.dict(), author_orcid=user.orcid)
945+
submission = SubmissionMetadata(
946+
**body.dict(),
947+
author_orcid=user.orcid,
948+
)
942949
submission.author_id = user.id
950+
submission.study_name = body.metadata_submission.studyForm.studyName
951+
submission.templates = body.metadata_submission.templates
952+
943953
db.add(submission)
944954
db.commit()
945955
owner_role = SubmissionRole(

nmdc_server/crud.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -629,10 +629,18 @@ def can_edit_entire_submission(db: Session, submission_id: str, user_orcid: str)
629629
return (role and models.SubmissionEditorRole(role.role) in contributors_edit_roles) is True
630630

631631

632-
def get_submissions_for_user(db: Session, user: models.User):
632+
def get_submissions_for_user(db: Session, user: models.User, column_sort: str, order: str):
633633
"""Return all submissions that a user has permission to view."""
634-
all_submissions = db.query(models.SubmissionMetadata).order_by(
635-
models.SubmissionMetadata.created.desc()
634+
column = (
635+
models.User.name
636+
if column_sort == "author.name"
637+
else getattr(models.SubmissionMetadata, column_sort)
638+
)
639+
640+
all_submissions = (
641+
db.query(models.SubmissionMetadata)
642+
.join(models.User, models.SubmissionMetadata.author_id == models.User.id)
643+
.order_by(column.asc() if order == "asc" else column.desc())
636644
)
637645

638646
if user.is_admin:

nmdc_server/fakes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,8 @@ class Meta:
345345
author = SubFactory(UserFactory)
346346
author_orcid = Faker("pystr")
347347
status = "In Progress"
348+
study_name = Faker("word")
349+
templates = Faker("pylist", nb_elements=2, value_types=[str])
348350
created = datetime.utcnow()
349351
# TODO specify all fields!
350352
metadata_submission = {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""Add study_name and template columns to submission_metadata
2+
3+
Revision ID: 0ff690fb929d
4+
Revises: c0b36f8dc4b8
5+
Create Date: 2024-08-01 16:01:05.023371
6+
7+
"""
8+
9+
from typing import Optional
10+
11+
import sqlalchemy as sa
12+
from alembic import op
13+
from sqlalchemy.dialects.postgresql import JSONB
14+
from sqlalchemy.sql import column, table
15+
16+
# revision identifiers, used by Alembic.
17+
revision: str = "0ff690fb929d"
18+
down_revision: Optional[str] = "c0b36f8dc4b8"
19+
branch_labels: Optional[str] = None
20+
depends_on: Optional[str] = None
21+
22+
23+
def upgrade():
24+
# ### commands auto generated by Alembic - please adjust! ###
25+
op.add_column("submission_metadata", sa.Column("study_name", sa.String(), nullable=True))
26+
op.add_column(
27+
"submission_metadata",
28+
sa.Column("templates", JSONB(astext_type=sa.Text()), nullable=True), # type:ignore
29+
)
30+
submission_metadata = table(
31+
"submission_metadata",
32+
column("id", sa.String),
33+
column("metadata_submission", JSONB),
34+
column("study_name", sa.String),
35+
column("templates", JSONB),
36+
)
37+
38+
connection = op.get_bind()
39+
submissions = connection.execute(
40+
sa.select([submission_metadata.c.id, submission_metadata.c.metadata_submission])
41+
)
42+
43+
for submission in submissions:
44+
study_name = submission.metadata_submission["studyForm"].get("studyName")
45+
templates = submission.metadata_submission.get("templates")
46+
if study_name:
47+
connection.execute(
48+
submission_metadata.update()
49+
.where(submission_metadata.c.id == submission.id)
50+
.values(study_name=study_name)
51+
)
52+
if templates:
53+
connection.execute(
54+
submission_metadata.update()
55+
.where(submission_metadata.c.id == submission.id)
56+
.values(templates=templates)
57+
)
58+
# ### end Alembic commands ###
59+
60+
61+
def downgrade():
62+
# ### commands auto generated by Alembic - please adjust! ###
63+
op.drop_column("submission_metadata", "templates")
64+
op.drop_column("submission_metadata", "study_name")
65+
# ### end Alembic commands ###

nmdc_server/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,8 @@ class SubmissionMetadata(Base):
851851
status = Column(String, nullable=False, default="in-progress")
852852
metadata_submission = Column(JSONB, nullable=False)
853853
author_id = Column(UUID(as_uuid=True), ForeignKey(User.id))
854+
study_name = Column(String, nullable=True)
855+
templates = Column(JSONB, nullable=True)
854856

855857
# The client which initially created the submission. A null value indicates it was created by
856858
# an "unregistered" client. This could be legitimate usage, but it should be monitored.

nmdc_server/schemas_submission.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ class SubmissionMetadataSchema(SubmissionMetadataSchemaCreate):
111111
created: datetime
112112
status: str
113113
author: schemas.User
114+
templates: List[str]
115+
study_name: Optional[str]
114116

115117
lock_updated: Optional[datetime]
116118
locked_by: Optional[schemas.User]

web/src/data/api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,8 @@ export interface BulkDownload {
338338
export interface SearchParams {
339339
offset?: number;
340340
limit?: number;
341+
sortColumn?: string;
342+
sortOrder?: string;
341343
conditions: Condition[];
342344
data_object_filter?: DataObjectFilter[];
343345
}

web/src/use/usePaginatedResults.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export default function usePaginatedResult<T>(
1717
results: { count: 0, results: [] } as SearchResponse<T>,
1818
offset: 0,
1919
limit, // same as pageSize
20+
sortColumn: '',
21+
sortOrder: 'desc',
2022
pageSync: 1,
2123
});
2224
const { error, loading, request } = useRequest();
@@ -33,6 +35,8 @@ export default function usePaginatedResult<T>(
3335
data.results = await func({
3436
limit: data.limit,
3537
offset: data.offset,
38+
sortColumn: data.sortColumn,
39+
sortOrder: data.sortOrder,
3640
conditions: conditions.value,
3741
data_object_filter: dataObjectFilter?.value,
3842
});
@@ -66,12 +70,19 @@ export default function usePaginatedResult<T>(
6670
debouncedFetchResults();
6771
}
6872

73+
function setSortOptions(columnSort: string, sortOrder: string) {
74+
data.sortColumn = columnSort;
75+
data.sortOrder = sortOrder;
76+
debouncedFetchResults();
77+
}
78+
6979
return {
7080
data,
7181
error,
7282
loading,
7383
page,
7484
setPage,
7585
setItemsPerPage,
86+
setSortOptions,
7687
};
7788
}

web/src/views/SubmissionPortal/Components/SubmissionList.vue

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<script lang="ts">
22
import {
3-
defineComponent, ref, watch,
3+
defineComponent, ref, watch, Ref,
44
} from '@vue/composition-api';
5-
import { DataTableHeader } from 'vuetify';
5+
import { DataOptions, DataTableHeader } from 'vuetify';
66
import { useRouter } from '@/use/useRouter';
77
import usePaginatedResults from '@/use/usePaginatedResults';
88
import {
@@ -19,28 +19,23 @@ import ContactCard from '@/views/SubmissionPortal/Components/ContactCard.vue';
1919
const headers: DataTableHeader[] = [
2020
{
2121
text: 'Study Name',
22-
value: 'metadata_submission.studyForm.studyName',
23-
sortable: false,
22+
value: 'study_name',
2423
},
2524
{
2625
text: 'Author',
2726
value: 'author.name',
28-
sortable: false,
2927
},
3028
{
3129
text: 'Template',
32-
value: 'metadata_submission.templates',
33-
sortable: false,
30+
value: 'templates',
3431
},
3532
{
3633
text: 'Status',
3734
value: 'status',
38-
sortable: false,
3935
},
4036
{
4137
text: 'Created',
4238
value: 'created',
43-
sortable: false,
4439
},
4540
{
4641
text: '',
@@ -57,9 +52,15 @@ export default defineComponent({
5752
setup() {
5853
const router = useRouter();
5954
const itemsPerPage = 10;
60-
const options = ref({
55+
const options: Ref<DataOptions> = ref<DataOptions>({
6156
page: 1,
6257
itemsPerPage,
58+
sortBy: ['created'],
59+
sortDesc: [true],
60+
groupBy: [],
61+
groupDesc: [],
62+
multiSort: false,
63+
mustSort: false,
6364
});
6465
6566
function getStatus(item: api.MetadataSubmissionRecord) {
@@ -80,7 +81,11 @@ export default defineComponent({
8081
}
8182
8283
const submission = usePaginatedResults(ref([]), api.listRecords, ref([]), itemsPerPage);
83-
watch(options, () => submission.setPage(options.value.page), { deep: true });
84+
watch(options, () => {
85+
submission.setPage(options.value.page);
86+
const sortOrder = options.value.sortDesc[0] ? 'desc' : 'asc';
87+
submission.setSortOptions(options.value.sortBy[0], sortOrder);
88+
}, { deep: true });
8489
8590
return {
8691
HARMONIZER_TEMPLATES,
@@ -173,7 +178,7 @@ export default defineComponent({
173178
:authenticated="true"
174179
/>
175180
</template>
176-
<template #[`item.metadata_submission.templates`]="{ item }">
181+
<template #[`item.templates`]="{ item }">
177182
{{ item.metadata_submission.templates.map((template) => HARMONIZER_TEMPLATES[template].displayName).join(' + ') }}
178183
</template>
179184
<template #[`item.created`]="{ item }">

web/src/views/SubmissionPortal/store/api.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ interface MetadataSubmissionRecord {
4747
lock_updated: string;
4848
permission_level: string | null;
4949
source_client: 'submission_portal' | 'field_notes' | null;
50+
study_name: string;
51+
templates: string[];
5052
}
5153

5254
interface PaginatedResponse<T> {
@@ -87,6 +89,8 @@ async function listRecords(params: SearchParams) {
8789
params: {
8890
limit: params.limit,
8991
offset: params.offset,
92+
column_sort: params.sortColumn,
93+
sort_order: params.sortOrder,
9094
},
9195
});
9296
return resp.data;

0 commit comments

Comments
 (0)