diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 6d0d79be4..f74595a38 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -14,7 +14,8 @@ jobs: steps: - uses: actions/checkout@v4 with: - submodules: true + submodules: 'recursive' + lfs: true - uses: actions/setup-node@v4 with: node-version: 18 diff --git a/backend/cases/views_api.py b/backend/cases/views_api.py index c84d84bfb..5b5c388bb 100644 --- a/backend/cases/views_api.py +++ b/backend/cases/views_api.py @@ -4,6 +4,7 @@ from django.conf import settings from django.db import transaction from django.middleware.csrf import get_token +from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_view from modelcluster.queryset import FakeQuerySet from projectroles.app_settings import AppSettingAPI from projectroles.views_api import ( @@ -60,6 +61,15 @@ class CasePagination(PageNumberPagination): max_page_size = 1000 +@extend_schema_view( + get=extend_schema( + parameters=[ + OpenApiParameter(name="order_by", type=str), + OpenApiParameter(name="order_dir", type=str), + OpenApiParameter(name="q", type=str), + ] + ) +) class CaseListApiView(SODARAPIBaseProjectMixin, ListAPIView): """ List all cases in the current project. diff --git a/backend/varfish/tests/drf_openapi_schema/varfish_api_schema.yaml b/backend/varfish/tests/drf_openapi_schema/varfish_api_schema.yaml index a997ce07d..46cd6d13d 100644 --- a/backend/varfish/tests/drf_openapi_schema/varfish_api_schema.yaml +++ b/backend/varfish/tests/drf_openapi_schema/varfish_api_schema.yaml @@ -856,6 +856,14 @@ paths: **Returns:** List of project details (see :py:class:`CaseRetrieveApiView`) parameters: + - in: query + name: order_by + schema: + type: string + - in: query + name: order_dir + schema: + type: string - name: page required: false in: query @@ -874,6 +882,10 @@ paths: type: string pattern: ^[0-9a-f-]+$ required: true + - in: query + name: q + schema: + type: string tags: - cases security: diff --git a/frontend/.gitignore b/frontend/.gitignore index 8fe425b2e..7123b4700 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,4 +1,5 @@ /components.d.ts +/test-results !/src !/ext/varfish-api/src/lib diff --git a/frontend/end-to-end-tests/seqvar-filtration.spec.ts b/frontend/end-to-end-tests/seqvar-filtration.spec.ts index 18453e7f3..18c102ecd 100644 --- a/frontend/end-to-end-tests/seqvar-filtration.spec.ts +++ b/frontend/end-to-end-tests/seqvar-filtration.spec.ts @@ -122,7 +122,7 @@ test.describe('genotype', () => { test.describe('genotype (recessive)', () => { test.beforeEach(async ({ page }) => { await page - .locator('button[aria-label="Create query based on recessive"]') + .locator('button[title="Create query based on recessive"]') .click() }) diff --git a/frontend/ext/varfish-api/src/lib/types.gen.ts b/frontend/ext/varfish-api/src/lib/types.gen.ts index bc736802d..cd29f861e 100644 --- a/frontend/ext/varfish-api/src/lib/types.gen.ts +++ b/frontend/ext/varfish-api/src/lib/types.gen.ts @@ -3545,6 +3545,8 @@ export type CasesApiCaseListListData = { project: string; }; query?: { + order_by?: string; + order_dir?: string; /** * A page number within the paginated result set. */ @@ -3553,6 +3555,7 @@ export type CasesApiCaseListListData = { * Number of results to return per page. */ page_size?: number; + q?: string; }; }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1cda0dd81..36c55e1dd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,11 +17,11 @@ "@vueform/multiselect": "^2.6.7", "@vuelidate/core": "^2.0.3", "@vuelidate/validators": "^2.0.4", + "@wdns/vuetify-resize-drawer": "^3.1.6", "bootstrap": "^4.6.2", "camelcase": "^8.0.0", "core-js": "^3.37.0", "fast-deep-equal": "^3.1.3", - "iconify-icon": "^2.1.0", "igv": "^2.15.11", "javascript-time-ago": "^2.5.10", "jquery": "^3.7.1", @@ -2890,7 +2890,8 @@ "node_modules/@iconify/types": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", - "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==" + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true }, "node_modules/@iconify/utils": { "version": "2.1.23", @@ -8031,6 +8032,26 @@ } } }, + "node_modules/@wdns/vuetify-resize-drawer": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@wdns/vuetify-resize-drawer/-/vuetify-resize-drawer-3.1.6.tgz", + "integrity": "sha512-mye9lsiQVAlrELjBXit22PmXOEVDWUGR5k5tdFeKm82pk+nxBB7EVMCc+i+aFSmJMk8CAgk4uO5P8y+gaegWHA==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/webdevnerdstuff" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/WebDevNerdStuff" + } + ], + "license": "MIT", + "dependencies": { + "vue": "^3.4.20", + "vuetify": "^3.5.6" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", @@ -14215,18 +14236,6 @@ "ms": "^2.0.0" } }, - "node_modules/iconify-icon": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-2.1.0.tgz", - "integrity": "sha512-lto4XU3bwTQnb+D/CsJ4dWAo0aDe+uPMxEtxyOodw9l7R9QnJUUab3GCehlw2M8mDHdeUu/ufx8PvRQiJphhXg==", - "license": "MIT", - "dependencies": { - "@iconify/types": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/cyberalien" - } - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/frontend/package.json b/frontend/package.json index 196fc7fa2..e071c276d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,6 +6,7 @@ "build": "vite build --emptyOutDir", "test:unit": "vitest run", "test:unit:nocov": "vitest run", + "test:e2e": "playwright test", "lint": "eslint . --fix --max-warnings 0", "type-check": "vue-tsc --noEmit --composite false", "prettier-check": "npx prettier --check src/*/** tests/*/**", @@ -24,11 +25,11 @@ "@vueform/multiselect": "^2.6.7", "@vuelidate/core": "^2.0.3", "@vuelidate/validators": "^2.0.4", + "@wdns/vuetify-resize-drawer": "^3.1.6", "bootstrap": "^4.6.2", "camelcase": "^8.0.0", "core-js": "^3.37.0", "fast-deep-equal": "^3.1.3", - "iconify-icon": "^2.1.0", "igv": "^2.15.11", "javascript-time-ago": "^2.5.10", "jquery": "^3.7.1", diff --git a/frontend/src/cases/components/CaseDetail/CardCase.vue b/frontend/src/cases/components/CaseDetail/CardCase.vue index 4390a5923..5d5999ecb 100644 --- a/frontend/src/cases/components/CaseDetail/CardCase.vue +++ b/frontend/src/cases/components/CaseDetail/CardCase.vue @@ -96,6 +96,8 @@ const badgeStatusColor = computed(() => { Reference Genome {{ caseObj.release }} + Case Version + {{ caseObj.case_version }}
  • diff --git a/frontend/src/cases/components/CaseDetail/Content.vue b/frontend/src/cases/components/CaseDetail/Content.vue index edd2f35dc..da472c8d0 100644 --- a/frontend/src/cases/components/CaseDetail/Content.vue +++ b/frontend/src/cases/components/CaseDetail/Content.vue @@ -42,7 +42,7 @@ const caseQcStore = useCaseQcStore()
    @@ -70,7 +70,7 @@ const caseQcStore = useCaseQcStore()
    diff --git a/frontend/src/cases/components/CaseListTable/CaseListTable.vue b/frontend/src/cases/components/CaseListTable/CaseListTable.vue index 07472443c..bc53d0e2f 100644 --- a/frontend/src/cases/components/CaseListTable/CaseListTable.vue +++ b/frontend/src/cases/components/CaseListTable/CaseListTable.vue @@ -1,27 +1,33 @@ @@ -16,7 +16,7 @@ const props = withDefaults( floating permanent color="grey-lighten-3" - :rail="navbarHidden" + :rail="!navbarShown" > diff --git a/frontend/src/cases/router/index.ts b/frontend/src/cases/router/index.ts index 81cbd3b1f..b581f16b2 100644 --- a/frontend/src/cases/router/index.ts +++ b/frontend/src/cases/router/index.ts @@ -2,6 +2,7 @@ import StrucvarDetails from '@/svs/views/StrucvarDetails/StrucvarDetails.vue' import StrucvarFilterLegacy from '@/svs/views/StrucvarFilterLegacy/StrucvarFilterLegacy.vue' import { useHistoryStore } from '@/varfish/stores/history' import SeqvarFilterLegacy from '@/variants/views/SeqvarFilterLegacy/SeqvarFilterLegacy.vue' +import SeqvarsQuery from '@/seqvars/views/SeqvarsQuery/SeqvarsQuery.vue' import SeqvarDetails from '@/variants/views/SeqvarDetails/SeqvarDetails.vue' import { RouteLocationNormalized, @@ -108,6 +109,15 @@ const routes: RouteRecordRaw[] = [ currentTab: 'browser', }), }, + { + name: 'seqvars-query', + path: '/-/cases/:project/seqvars/queries/:case', + component: SeqvarsQuery, + props: (route: RouteLocationNormalized) => ({ + projectUuid: route.params.project, + caseUuid: route.params.case, + }), + }, { name: 'variants-filter', path: '/-/cases/:project/variants/filter/:case', diff --git a/frontend/src/cases/views/CaseDetail/CaseDetail.vue b/frontend/src/cases/views/CaseDetail/CaseDetail.vue index a763cb039..8156dddb1 100644 --- a/frontend/src/cases/views/CaseDetail/CaseDetail.vue +++ b/frontend/src/cases/views/CaseDetail/CaseDetail.vue @@ -1,9 +1,10 @@