Skip to content

Commit

Permalink
Merge pull request #703 from hubmapconsortium/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
axdanbol authored Sep 10, 2024
2 parents 818bf60 + 35060ea commit 489c518
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 23 deletions.
2 changes: 1 addition & 1 deletion apps/cde-visualization-wc/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"maximumError": "10kb"
}
],
"outputHashing": "all"
"outputHashing": "none"
},
"development": {
"optimization": false,
Expand Down
20 changes: 17 additions & 3 deletions apps/ftu-ui-small-wc/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';
import { Router } from '@angular/router';
import { dispatch, dispatch$, dispatchAction$, select$, selectSnapshot } from '@hra-ui/cdk/injectors';
import { FTU_DATA_IMPL_ENDPOINTS, FtuDataImplEndpoints, IllustrationMappingItem } from '@hra-ui/services';
import {
FTU_DATA_IMPL_ENDPOINTS,
FtuDataImplEndpoints,
IllustrationMappingItem,
Iri,
RawIllustration,
} from '@hra-ui/services';
import { ActiveFtuActions, IllustratorActions, IllustratorSelectors } from '@hra-ui/state';
import { ActionContext, ActionStatus, Actions } from '@ngxs/store';
import { ReplaySubject, firstValueFrom, from, of, take, toArray } from 'rxjs';
Expand Down Expand Up @@ -48,8 +54,16 @@ describe('AppComponent', () => {
});

describe('.selectedIllustration', () => {
const iri = 'foo/bar';
const illustration = { '@id': iri };
const iri = 'https://foo.bar/';
const illustration: RawIllustration = {
'@id': iri as Iri,
label: '',
organ_id: '',
organ_label: '',
representation_of: '',
mapping: [],
illustration_files: [],
};
const params = {
queryParams: { id: iri },
};
Expand Down
19 changes: 15 additions & 4 deletions apps/ftu-ui-small-wc/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@ import { FullscreenContainerComponent, FullscreenContentComponent } from '@hra-u
import {
FTU_DATA_IMPL_ENDPOINTS,
FtuDataImplEndpoints,
illustrationsInput,
rawCellSummariesInput,
RawCellSummary,
RawDatasets,
rawDatasetsInput,
RawIllustration,
RawIllustrationsJsonld,
selectedIllustrationInput,
setUrl,
} from '@hra-ui/services';
import {
Expand Down Expand Up @@ -98,13 +102,17 @@ function filterUndefined<T>(): OperatorFunction<T | undefined, T> {
export class AppComponent implements OnInit, OnChanges {
/** Illustration to display (choosen automatically if not provided) */
@Input() selectedIllustration?: string | RawIllustration;

/** Set of all illustrations */
@Input() illustrations: string | RawIllustrationsJsonld =
'https://cdn.humanatlas.io/digital-objects/graph/2d-ftu-illustrations/latest/assets/2d-ftu-illustrations.jsonld';

/** Cell summaries to display in tables */
@Input() summaries: string | RawCellSummary = '';

/** Datasets to display in the sources tab */
@Input() datasets: string | RawDatasets = '';

/** Base href if different from the page */
@Input() baseHref = '';

Expand Down Expand Up @@ -197,9 +205,9 @@ export class AppComponent implements OnInit, OnChanges {
if (!endpointsUpdated) {
const { illustrations, datasets, summaries, baseHref } = this;
this.endpoints.next({
illustrations,
datasets,
summaries,
illustrations: illustrationsInput(illustrations) ?? '',
datasets: rawDatasetsInput(datasets) ?? '',
summaries: rawCellSummariesInput(summaries) ?? '',
baseHref,
});
endpointsUpdated = true;
Expand Down Expand Up @@ -237,7 +245,10 @@ export class AppComponent implements OnInit, OnChanges {
* Updates the selected illustration using a default if not provided
*/
private updateSelectedIllustration(): void {
const { selectedIllustration: selected } = this;
const { selectedIllustration } = this;
console.log('fooo', selectedIllustration);
const selected = selectedIllustrationInput(selectedIllustration);
console.log('bar');
if (selected === undefined || selected === '') {
this.setDefaultSelectedIllustration();
} else {
Expand Down
14 changes: 11 additions & 3 deletions apps/ftu-ui/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
selectSnapshot,
} from '@hra-ui/cdk/injectors';
import { LinkRegistryActions } from '@hra-ui/cdk/state';
import { FTU_DATA_IMPL_ENDPOINTS, IllustrationMappingItem } from '@hra-ui/services';
import { FTU_DATA_IMPL_ENDPOINTS, IllustrationMappingItem, Iri, RawIllustration } from '@hra-ui/services';
import {
ActiveFtuActions,
IllustratorActions,
Expand Down Expand Up @@ -71,8 +71,16 @@ describe('AppComponent', () => {
});

describe('.selectedIllustration', () => {
const iri = 'foo/bar';
const illustration = { '@id': iri };
const iri = 'https://foo.bar/';
const illustration: RawIllustration = {
'@id': iri as Iri,
label: '',
organ_id: '',
organ_label: '',
representation_of: '',
mapping: [],
illustration_files: [],
};

it('accepts an iri string', async () => {
await shallow.render({ bind: { selectedIllustration: iri } });
Expand Down
17 changes: 13 additions & 4 deletions apps/ftu-ui/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ import { ScreenNoticeBehaviorComponent } from '@hra-ui/components/behavioral';
import {
FTU_DATA_IMPL_ENDPOINTS,
FtuDataImplEndpoints,
illustrationsInput,
rawCellSummariesInput,
RawCellSummary,
RawDatasets,
rawDatasetsInput,
RawIllustration,
RawIllustrationsJsonld,
selectedIllustrationInput,
setUrl,
} from '@hra-ui/services';
import {
Expand Down Expand Up @@ -97,13 +101,17 @@ export class AppComponent implements AfterContentInit, OnChanges, OnInit {

/** Illustration to display (choosen automatically if not provided) */
@Input() selectedIllustration?: string | RawIllustration;

/** Set of all illustrations */
@Input() illustrations: string | RawIllustrationsJsonld =
'https://cdn.humanatlas.io/digital-objects/graph/2d-ftu-illustrations/latest/assets/2d-ftu-illustrations.jsonld';

/** Cell summaries to display in tables */
@Input() summaries: string | RawCellSummary = '';

/** Datasets to display in the sources tab */
@Input() datasets: string | RawDatasets = '';

/** Base href if different from the page */
@Input() baseHref = '';

Expand Down Expand Up @@ -203,9 +211,9 @@ export class AppComponent implements AfterContentInit, OnChanges, OnInit {
if (!endpointsUpdated) {
const { illustrations, datasets, summaries, baseHref } = this;
this.endpoints.next({
illustrations,
datasets,
summaries,
illustrations: illustrationsInput(illustrations) ?? '',
datasets: rawDatasetsInput(datasets) ?? '',
summaries: rawCellSummariesInput(summaries) ?? '',
baseHref,
});
endpointsUpdated = true;
Expand Down Expand Up @@ -248,7 +256,8 @@ export class AppComponent implements AfterContentInit, OnChanges, OnInit {
* Updates the selected illustration using a default if not provided
*/
private updateSelectedIllustration(): void {
const { selectedIllustration: selected } = this;
const { selectedIllustration } = this;
const selected = selectedIllustrationInput(selectedIllustration);
if (selected) {
const iri = typeof selected === 'string' ? selected : selected['@id'];
this.updateLink(LinkIds.ExploreFTU, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ import {
FtuDataImplEndpoints,
FtuDataImplService,
IllustrationMappingItem,
illustrationsInput,
Iri,
RAW_ILLUSTRATION,
RawCellEntry,
RawIllustration,
RawIllustrationFile,
RawIllustrationsJsonld,
selectedIllustrationInput,
tryParseJson,
} from '@hra-ui/services';
import { Observable, of, OperatorFunction, ReplaySubject, switchMap } from 'rxjs';
import { z } from 'zod';
Expand Down Expand Up @@ -68,7 +71,7 @@ export class MedicalIllustrationComponent implements OnInit, OnChanges {
@Input() selectedIllustration?: string | RawIllustration;

/** Optional set of all illustrations. Used when selectedIllustration is an iri */
@Input() illustrations: string | RawIllustrationsJsonld = '';
@Input() illustrations?: string | RawIllustrationsJsonld;

/** A cell or id to highlight in the illustration */
@Input() highlight?: string | RawCellEntry;
Expand All @@ -85,11 +88,12 @@ export class MedicalIllustrationComponent implements OnInit, OnChanges {
/** Get the normalized id for the highlight input */
get highlightId(): string | undefined {
const { highlight } = this;
if (typeof highlight === 'object') {
return highlight.representation_of;
const parsed = tryParseJson<string | RawCellEntry>(highlight);
if (typeof parsed === 'object') {
return parsed.representation_of;
}

return highlight;
return parsed;
}

/** Data endpoints */
Expand Down Expand Up @@ -141,14 +145,14 @@ export class MedicalIllustrationComponent implements OnInit, OnChanges {
const { baseHref, illustrations } = this;
this.endpoints.next({
baseHref,
illustrations,
illustrations: illustrationsInput(illustrations) ?? '',
datasets: '',
summaries: '',
});
}

if ('selectedIllustration' in changes) {
this.illustration$.next(this.selectedIllustration);
this.illustration$.next(selectedIllustrationInput(this.selectedIllustration));
}

this.initialized = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ export class DataLoaderService {
return runInInjectionContext(injector, () => {
const loader = inject<InstanceType<LoaderT>>(loaderToken);
const load = (sourceValue: string | T | undefined): Observable<T> => {
try {
if (typeof sourceValue === 'string') {
sourceValue = JSON.parse(sourceValue);
}
} catch {
// Ignore errors
}

if (typeof sourceValue !== 'string') {
return of(sourceValue ?? initialValue);
}
Expand Down
1 change: 1 addition & 0 deletions libs/services/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from './lib/service.module';
export * from './lib/shared/common.model';

export * as FtuDataSchemas from './lib/ftu-data/ftu-data.model';
export * from './lib/ftu-data/ftu-data.transformers';
128 changes: 128 additions & 0 deletions libs/services/src/lib/ftu-data/ftu-data.transformers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { z } from 'zod';
import { RAW_CELL_SUMMARIES, RAW_DATASETS, RAW_ILLUSTRATION, RAW_ILLUSTRATIONS_JSONLD } from './ftu-data.model';

/**
* Tries to parse a value as json. Returns the original value if it could not be parsed.
*
* @param value Value to parse
* @returns Parsed json value or the original value
*/
export function tryParseJson<R = unknown>(value: unknown): R {
try {
if (typeof value === 'string') {
return JSON.parse(value);
}
} catch {
// Ignore errors
}

return value as R;
}

/**
* Tests whether a value is path like
*
* @param value Value to test
* @returns True if the value is path like
*/
function isPath(value: unknown): boolean {
try {
if (typeof value === 'string') {
new URL(value, 'https://base.url/');
return true;
}
} catch {
// Ignore errors
}

return false;
}

/**
* Creates a zod schema for validating input values that accepts either an url,
* a path, javascript object, or a json encoded string of such an object.
*
* @param schema Input object schema
* @returns A zod type for validating input values
*/
function createInputValidation<T extends z.ZodTypeAny>(schema: T) {
return z.preprocess(
tryParseJson,
z.union([
z.string().url().optional(),
z.literal(''),
z.custom<string>((value) => (isPath(value) ? value : false), 'Invalid path'),
schema,
]),
);
}

/**
* Parses a value using the provided schema. Throws an error on parsing failure.
*
* @param schema Schema to use for parsing
* @param value Value to parse
* @returns The parsed value
*/
function parseInput<T extends z.ZodTypeAny>(schema: T, value: unknown): z.infer<T> {
const result = schema.safeParse(value);
if (result.success) {
return result.data;
}

throw new TypeError(
`Invalid input. Expected an url, a path, or a json encoded ${schema.description} object. Received: ${value}`,
);
}

/** Selected illustration input schema */
export const SELECTED_ILLUSTRATION_INPUT = createInputValidation(RAW_ILLUSTRATION).describe('illustration');

/**
* Parses selected illustration input
*
* @param value Value to parse
* @returns Parsed input
*/
export function selectedIllustrationInput(value: unknown) {
return parseInput(SELECTED_ILLUSTRATION_INPUT, value);
}

/** Illustrations input schema */
export const ILLUSTRATIONS_INPUT = createInputValidation(RAW_ILLUSTRATIONS_JSONLD).describe('illustrations');

/**
* Parses illustrations input
*
* @param value Value to parse
* @returns Parsed input
*/
export function illustrationsInput(value: unknown) {
return parseInput(ILLUSTRATIONS_INPUT, value);
}

/** Cell summaries input schema */
export const RAW_CELL_SUMMARIES_INPUT = createInputValidation(RAW_CELL_SUMMARIES).describe('cell summaries');

/**
* Parses cell summaries input
*
* @param value Value to parse
* @returns Parsed input
*/
export function rawCellSummariesInput(value: unknown) {
return parseInput(RAW_CELL_SUMMARIES_INPUT, value);
}

/** Datasets input schema */
export const RAW_DATASETS_INPUT = createInputValidation(RAW_DATASETS).describe('datasets');

/**
* Parses datasets input
*
* @param value Value to parse
* @returns Parsed input
*/
export function rawDatasetsInput(value: unknown) {
return parseInput(RAW_DATASETS_INPUT, value);
}
Loading

0 comments on commit 489c518

Please sign in to comment.