Repository navigation
feat(api): table queries for use cases, collaboratives, AI models, publications - #254
Merged
Merged
Conversation
…blications Add useCasesTable, collaborativesTable, aiModelsTable and publicationsTable, shaped like datasetsTable: client filters and sort options limited to an allowlist per module, limit/offset paging, the total after filters, and counts per status for the dashboard tabs (ignoring the status filter so tab labels stay stable). Each query shows the same rows as the module's existing list query, plus published (for AI models: public and active) rows when includePublic is set. The existing list queries are unchanged. StatusCount and status_counts() are shared in api/utils/qs_utils.py. No migration.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
The tab counts in datasetsTable were an inline copy of what status_counts() in api/utils/qs_utils.py now does for the other four tables. Call the helper instead, so all five tables count statuses in one place. status_counts() takes an optional item_type so the dataset table keeps its DatasetStatusCount type; the GraphQL schema is unchanged.
anantjain341
marked this pull request as ready for review
October 22, 2026 15:09
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backend for "Pagination and filter implementation" (https://github.com/CivicDataLab/DataSpace/issues/277): use cases (https://github.com/CivicDataLab/DataSpace/issues/278), collaboratives (https://github.com/CivicDataLab/DataSpace/issues/279), AI models (https://github.com/CivicDataLab/DataSpace/issues/280) and publications (https://github.com/CivicDataLab/DataSpace/issues/287).
Adds four new queries for the dashboard tables, built the same way as
datasetsTable(#215):useCasesTable,collaborativesTable,aiModelsTable,publicationsTable.The existing
useCases,collaboratives,aiModelsandpublicationsqueries are untouched, so nothing that runs today changes.What you get in one call
A page of rows, the total count, and the per-status numbers for the tabs. All four look the same:
datarows are the same types the old queries return (TypeUseCase,TypeCollaborative,TypeAIModel,TypePublication), so select whatever the table shows.Mapping the current table UI
The four dashboards have the same layout: two tabs and a table.
statusfilter:DRAFT/PUBLISHED. For AI models:REGISTERED(Draft tab) /ACTIVE(Published tab). Numbers for the tab labels come fromstatusCountstitledisplayName,modelType,providercreated,modified(AI models:createdAt,updatedAt)id(andslugwhere the link uses it), unchangedsortOptions: [{field: "modified", direction: "desc"}](AI models:updated_at)titlewithicontains(AI models:display_name)limit,offset,totalItemsCountPublications today fetch 100 rows and split the tabs in the browser, so anything past 100 never shows. With
publicationsTablethe status filter, paging and tab counts all come from the server.Filters
A list of filters, each: which field, how to compare, what value.
All filters are combined with AND. The value is always a string.
Fields you can filter on:
useCasesTabletitle,status,running_status,idorganization,organization__slugsectors__id,sectors__slug,sectors__namegeographies__id,geographies__name,geographies__codesdgs__code,sdgs__slugtags__valuestarted_on,completed_on,created,modified(ISO date, e.g.2026-01-01)collaborativesTable: the same as use cases, withoutrunning_status.aiModelsTabledisplay_name,name,status,model_type,provider,domain,idorganization,organization__slugsectors__id,sectors__slug,sectors__namegeographies__id,geographies__name,geographies__codetags__valuecreated_at,updated_at(ISO date)publicationsTabletitle,status,license,idresource_type(id),resource_type__slugorganization,organization__slugsectors__id,sectors__slug,sectors__namegeographies__id,geographies__name,geographies__codepublication_date,created,modified(ISO date)Field names are the model's names in snake_case (
display_name,created_at), as indatasetsTable. Filtering on several sectors, geographies or tags never returns a row twice.Ways to compare:
exact(default),iexact— equalscontains,icontains— text search (useicontainsfor a search box)startswith,endswithand theiriversionsgt,gte,lt,lte— for dates and numbersin— any of a comma-separated listisnull—"true"or"false"Anything outside this list returns a GraphQL error that names the allowed fields.
Need another column in the filter panel? It is a one-line change on the backend; ask.
Sorting
Fields:
useCasesTable:title,created,modified,status,running_status,started_on,completed_oncollaborativesTable:title,created,modified,status,started_on,completed_onaiModelsTable:display_name,name,created_at,updated_at,status,model_type,providerpublicationsTable:title,created,modified,status,publication_date,download_countSeveral keys are allowed. Default when omitted: newest first (
created, AI modelscreated_at). The dashboards today sort by last modified, so send that sort to keep the same order.Pagination
limit= page size, 1 to 100 (default 50)offset= rows to skipstatusCountsis computed with every filter applied except the status filter, so the tab numbers do not change when switching tabs.Who sees what
Same rules as each module's current list query. Send the usual headers:
Authorization: Bearer <token>and, inside an organisation,organization: <slug>.datasetsTable, which returns nothing here; it follows whatuseCases,collaboratives,aiModelsandpublicationsalready do.includePublic: trueadds every published row (AI models: public and active).Notes on statuses:
ARCHIVED. The current design has no tab for them, so they show on neither tab, the same as today.DRAFT,VALIDATING,AUDITING,APPROVED,FLAGGED,DEPRECATED).statusCountslists every status that has rows, so a later Approved tab only needs the filter.Full example
AI models, Published tab:
Errors
Ordinary GraphQL
errors, for example:idor a date) returns Django's validation message, the same asdatasetsTabletoday.No migration, no new dependency. Helpers live in
api/utils/qs_utils.py. The status counting is now one shared helper there (status_counts), used by these four tables and bydatasetsTable(second commit; it keeps itsDatasetStatusCounttype, and the GraphQL schema is unchanged).