From 2f96c2e9c7a1dd7e733da45413b8b9c2d17816e5 Mon Sep 17 00:00:00 2001 From: Benjamin Capodanno Date: Fri, 12 Dec 2025 17:01:53 -0800 Subject: [PATCH 01/10] feat: handle IGVF external links --- src/components/ScoreSetSecondaryMetadata.vue | 29 +++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/components/ScoreSetSecondaryMetadata.vue b/src/components/ScoreSetSecondaryMetadata.vue index 06cbd321..ffc5a350 100644 --- a/src/components/ScoreSetSecondaryMetadata.vue +++ b/src/components/ScoreSetSecondaryMetadata.vue @@ -69,10 +69,16 @@ -
- - UCSC Genome Browser - View in the UCSC Genome Browser + + @@ -109,4 +115,19 @@ const sortedMetaAnalyzedByScoreSetUrns = computed(() => _.sortBy(props.scoreSet. .mavedb-contributor { margin: 0 0.5em; } +.external-link { + display: block; +} +.external-link a { + display: inline-flex; + align-items: center; + gap: 6px; +} +.external-link img { + height: 20px; + width: auto; +} +.external-link img { + display: block; +} From c34cfa4eeff9314111bd8d0f46af2fd0e5557067 Mon Sep 17 00:00:00 2001 From: Benjamin Capodanno Date: Tue, 16 Dec 2025 13:01:23 -0800 Subject: [PATCH 02/10] chore: update OpenAPI schema Reflects changes in https://github.com/VariantEffect/mavedb-api/pull/619 --- src/schema/openapi.d.ts | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/schema/openapi.d.ts b/src/schema/openapi.d.ts index 4c96869e..5dd455a1 100644 --- a/src/schema/openapi.d.ts +++ b/src/schema/openapi.d.ts @@ -571,9 +571,9 @@ export interface paths { * The index to start from. If None, starts from the beginning. * limit : Optional[int] * The maximum number of variants to return. If None, returns all variants. - * namespaces: List[Literal["scores", "counts"]] + * namespaces: List[Literal["scores", "counts", "vep", "gnomad"]] * The namespaces of all columns except for accession, hgvs_nt, hgvs_pro, and hgvs_splice. - * We may add ClinVar and gnomAD in the future. + * We may add ClinVar in the future. * drop_na_columns : bool, optional * Whether to drop columns that contain only NA values. Defaults to False. * db : Session @@ -2577,6 +2577,10 @@ export interface components { keywords: components["schemas"]["ExperimentControlledKeyword"][]; /** Scoreseturns */ scoreSetUrns: string[]; + /** Externallinks */ + externalLinks: { + [key: string]: components["schemas"]["ExternalLink"]; + }; /** Numscoresets */ numScoreSets?: number | null; /** Processingstate */ @@ -2945,7 +2949,14 @@ export interface components { /** Offset */ offset: number; }; - /** ExternalLink */ + /** + * ExternalLink + * @description Represents an external hyperlink for view models. + * + * Attributes: + * url (Optional[str]): Fully qualified URL for the external resource. + * May be None if no link is available or applicable. + */ ExternalLink: { /** Url */ url?: string | null; @@ -4573,6 +4584,10 @@ export interface components { keywords: components["schemas"]["SavedExperimentControlledKeyword"][]; /** Scoreseturns */ scoreSetUrns: string[]; + /** Externallinks */ + externalLinks: { + [key: string]: components["schemas"]["ExternalLink"]; + }; /** Processingstate */ processingState?: string | null; }; @@ -8749,9 +8764,9 @@ export interface operations { * The index to start from. If None, starts from the beginning. * limit : Optional[int] * The maximum number of variants to return. If None, returns all variants. - * namespaces: List[Literal["scores", "counts"]] + * namespaces: List[Literal["scores", "counts", "vep", "gnomad"]] * The namespaces of all columns except for accession, hgvs_nt, hgvs_pro, and hgvs_splice. - * We may add ClinVar and gnomAD in the future. + * We may add ClinVar in the future. * drop_na_columns : bool, optional * Whether to drop columns that contain only NA values. Defaults to False. * db : Session @@ -8771,8 +8786,8 @@ export interface operations { start?: number; /** @description Maximum number of variants to return */ limit?: number; - /** @description One or more data types to include: scores, counts, clinVar, gnomAD */ - namespaces?: ("scores" | "counts")[]; + /** @description One or more data types to include: scores, counts, clinVar, gnomAD, VEP */ + namespaces?: ("scores" | "counts" | "vep" | "gnomad")[]; drop_na_columns?: boolean | null; include_custom_columns?: boolean | null; include_post_mapped_hgvs?: boolean | null; From 037c9c6bb4f714ae0f04d51af8bb684273525f9f Mon Sep 17 00:00:00 2001 From: Benjamin Capodanno Date: Tue, 16 Dec 2025 13:01:29 -0800 Subject: [PATCH 03/10] fix: update IGVF link text for clarity --- src/components/ScoreSetSecondaryMetadata.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ScoreSetSecondaryMetadata.vue b/src/components/ScoreSetSecondaryMetadata.vue index ffc5a350..bc55b86f 100644 --- a/src/components/ScoreSetSecondaryMetadata.vue +++ b/src/components/ScoreSetSecondaryMetadata.vue @@ -72,7 +72,7 @@
Current version {{ item.currentVersion }}
- - + +
+ +
Score Sets
    @@ -528,6 +535,23 @@ export default { } .mave-save-to-collection-button { - margin: 1em 0; + margin: 1em; +} + +/* External links */ +.external-link { + display: block; +} +.external-link a { + display: inline-flex; + align-items: center; + gap: 6px; +} +.external-link img { + height: 20px; + width: auto; +} +.external-link img { + display: block; } From fa060870a9fb28a8ad5e739b39aadde294aba51e Mon Sep 17 00:00:00 2001 From: Benjamin Capodanno Date: Tue, 16 Dec 2025 13:31:54 -0800 Subject: [PATCH 05/10] feat: add linkifyTextHtml function for converting URLs to clickable links --- src/composition/formatters.ts | 3 ++- src/lib/formats.ts | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/composition/formatters.ts b/src/composition/formatters.ts index e7b05ae3..51736a2c 100644 --- a/src/composition/formatters.ts +++ b/src/composition/formatters.ts @@ -1,11 +1,12 @@ import _ from 'lodash' import pluralize from 'pluralize' -import {formatDate, formatInt} from '@/lib/formats' +import {formatDate, formatInt, linkifyTextHtml} from '@/lib/formats' export default () => ({ formatDate, formatInt, + linkifyTextHtml, pluralize, startCase: (s: string) => _.startCase(s) }) diff --git a/src/lib/formats.ts b/src/lib/formats.ts index 31272ab4..e7affef5 100644 --- a/src/lib/formats.ts +++ b/src/lib/formats.ts @@ -12,3 +12,39 @@ export function formatInt(x: number | null) { maximumFractionDigits: 0 }) } + +/** + * Safely convert plain text containing URLs into HTML with clickable links. + * - Escapes HTML to prevent XSS + * - Linkifies http/https URLs and bare www. domains + * - Preserves trailing punctuation outside the link + */ +export function linkifyTextHtml(text: string | null | undefined): string { + if (!text) return '' + + const escapeHtml = (s: string) => + String(s) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, ''') + + const escaped = escapeHtml(text) + + // Linkify http/https URLs + let linked = escaped.replace(/\bhttps?:\/\/[^\s<)]+[\w\/#?=&%+\-._~]*\b[\)\]]?/gi, (raw) => { + let url = raw + const m = url.match(/[).,!?:;]+$/) + const trailing = m ? m[0] : '' + if (trailing) url = url.slice(0, -trailing.length) + return `${url}${trailing}` + }) + + // Linkify bare www. domains + linked = linked.replace(/(^|[^\w/])(www\.[^\s<)]+)\b/gi, (match, pre, host) => { + return `${pre}${host}` + }) + + return linked +} From 7145fcee3acd4bbc86b96ec8ad53cdb3a5886227 Mon Sep 17 00:00:00 2001 From: Benjamin Capodanno Date: Tue, 16 Dec 2025 13:32:01 -0800 Subject: [PATCH 06/10] feat: enable linkification of collection descriptions in CollectionView and CollectionsView --- src/components/screens/CollectionView.vue | 14 ++++++++++++-- src/components/screens/CollectionsView.vue | 12 +++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/components/screens/CollectionView.vue b/src/components/screens/CollectionView.vue index adff52ca..1f292c44 100644 --- a/src/components/screens/CollectionView.vue +++ b/src/components/screens/CollectionView.vue @@ -70,7 +70,11 @@ @open="editCollectionDescription" > - + + + { useHead({title: 'My saved collections'}) - + return { - ...useFormatters(), + ...useFormatters() } }, From 5faa199cefe80f9e97f72bd04164b25b68e14c94 Mon Sep 17 00:00:00 2001 From: Benjamin Capodanno Date: Tue, 16 Dec 2025 13:32:12 -0800 Subject: [PATCH 07/10] feat: add IGVF resource links to HomeScreen --- src/components/screens/HomeScreen.vue | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/components/screens/HomeScreen.vue b/src/components/screens/HomeScreen.vue index 29d86891..86b6438d 100644 --- a/src/components/screens/HomeScreen.vue +++ b/src/components/screens/HomeScreen.vue @@ -94,6 +94,20 @@