Skip to content

#79 / Library Updates for UI - #80

Merged
demariadaniel merged 48 commits into
mainfrom
79/bug-fixes-for-modal
Aug 12, 2025
Merged

demariadaniel merged 48 commits into
mainfrom
79/bug-fixes-for-modal

Conversation

@demariadaniel

@demariadaniel demariadaniel commented Aug 6, 2025 •

Copy link
Copy Markdown
Contributor

#79 Feat: Changes to Support UI Changes in: https://github.com/overture-stack/stage/pull/253/files

Summary

#79 contains changes to fix the rendering of Iobio Labels
This requires an update to iobio-charts @0.26.0 and new JSX definitions
This PR bundles the library update with several other package improvements

Issues

Description of Changes

  • Updates iobio-charts to @ 0.26
  • Adds component definitions for Iobio LabelInfoButton and Panel
  • Updates use of label prop
  • Adds default copy for LabelInfoButton from Iobio site
  • Adds Zod Validation and improves Type definitions
  • Moves Score related files out of Metadata generator folder
  • Changes Score configuration

Readiness Checklist

  • Self Review
    • I have performed a self review of code
    • I have run the application locally and manually tested the feature
    • I have checked all updates to correct typos and misspellings
  • Formatting
    • Code follows the project style guide
    • Autmated code formatters (ie. Prettier) have been run
  • Local Testing
    • Successfully built all packages locally
    • Successfully ran all test suites, all unit and integration tests pass
  • Updated Tests
    • Unit and integration tests have been added that describe the bug that was fixed or the features that were added
  • Documentation
    • All new environment variables added to .env.schema file and documented in the README
    • All changes to server HTTP endpoints have open-api documentation
    • All new functions exported from their module have TSDoc comment documentation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved out of utils/elasticMetadataClient

Comment on lines +117 to +120
if (!FileMetaDataSchema.safeParse(indexFileMetadata))
console.error(`Error retrieving Index file from Score with object_id: ${fileObjectId}, results may be inaccurate`);

return { scoreFileMetadata, indexFileMetadata };

@joneubank joneubank Aug 7, 2025 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most importantly, FileMetaDataSchema.safeParse(...) ALWAYS is truthy, it returns an object. you want to check FileMetaDataSchema.safeParse(...).success.

Following that, we should be returning the data from the parse result, not the original (untyped) response data:

const metadataParseResult = FileMetaDataSchema.safeParse(indexFileMetadata);

if(!metadataParseResult.success) {
  console.error(`Error retrieving Index file from Score with object_id: ${fileObjectId}, results may be inaccurate`);
  // return something that indicates our data wasn't available, otherwise the consumer of this function will process data that is the wrong shape and will break.
}

return { scoreFileMetadata, indexFileMetadata: metadataParseResult.data };

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry let me revise this, I followed up on some of your previous PR comments then the changes got lost in the shuffle and may have rushed a few revisions

Comment on lines +38 to +53
export const FileMetaDataSchema = zod.object({
objectId: zod.string(),
objectKey: zod.string().optional(),
objectMd5: zod.string().optional(),
objectSize: zod.number().optional(),
parts: zod.array(
zod.object({
md5: zod.string().nullable().optional(),
offset: zod.number().optional(),
partNumber: zod.number().optional(),
partSize: zod.number().optional(),
url: zod.string(),
}),
),
uploadId: zod.string().optional(),
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This schema is disconnected from the type we declared in scoreFileTypes. If one changes and the other doesn't, then we are validating the incorrect type.

The way to fix this is to move this schema into the scoreFileTypes.ts file, and then to use zod.infer to generate the type:

export const fileMetaDataSchema = zod.object({
	objectId: zod.string(),
	objectKey: zod.string().optional(),
	objectMd5: zod.string().optional(),
	objectSize: zod.number().optional(),
	parts: zod.array(
		zod.object({
			md5: zod.string().nullable().optional(),
			offset: zod.number().optional(),
			partNumber: zod.number().optional(),
			partSize: zod.number().optional(),
			url: zod.string(),
		}),
	),
	uploadId: zod.string().optional(),
});
export type FileMetaData = zod.infer<typeof fileMetaDataSchema>;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved

@ciaranschutte ciaranschutte left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking really good overall - couple of q's , couple of style fix ups

}): Promise<{ fileUrl: string; fileName?: string; indexFileUrl?: string }> => {
const { documentId } = esConfig;
const elasticDocument = searchResult._source;
if (elasticDocument.file_type && !BamFileExtensions.includes(elasticDocument.file_type)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplify to !BamFileExtensions.includes(elasticDocument.file_type) ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for TS b/c BamFileExtensions does not include undefined

const authKey = process.env.ES_AUTH_KEY;
const esHost = process.env.ES_HOST_URL;
if (!(authKey && esHost)) throw new Error('Required .env configuration values are missing');
if (!(authKey && esHost)) throw new Error('Required ElasticSearch .env configuration values are missing');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap the "if"
good giving a better message - maybe we should go all the way and say no ES_AUTH_KEY or ES_HOST_URL?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right -- added several wrapping {} brackets and improved error messages

Comment on lines +155 to +156
export const infoLabelPercentCopy: { [P in BamPercentKey]: string } = {
mapped_reads:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the current usage in a consumer, example from Stage:

<IobioPanel>
	<IobioLabelInfoButton label={displayNames[key]}>
		<div slot="content">
			<p>{infoLabelPercentCopy[key]}</p>
		</div>
	</IobioLabelInfoButton>
	<IobioPercentBox percentKey={key} totalKey="total_reads" />
</IobioPanel>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of these are really "default descriptions" because the consumer eg. Stage is selecting copy based on the key. There's some "library thinking" to be applied here and I'm not 100% clear what the end goal is.
if these are truly library level defaults, should they display when not given input from a consumer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK so some background info to provide here. iobio-charts exports the Label and InfoButton tooltip together as one component. The content is for the pop up modal. We don't have our own copy for the modal (I'm using what is on Iobio's site).
But the consumer might. So making these a default (display when there's no content) on our package side is a smart suggestion.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restructured the info buttons to show standard display names and modal copy
This requires a bamKey string prop and overrides additional labels/children if provided

df454e6

Comment on lines +27 to +31
export interface IobioDataBrokerProps extends IobioElementProps {
'alignment-url': string;
'index-url'?: string;
server?: string;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the props are camelCased ?
<IobioDataBroker alignmentUrl={fileUrl} indexUrl={indexFileUrl}...>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

react component props should be camelCased while html elements (and web components) are kebab-cased

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shoot yeah there's some overlap here that's not correct, looking into it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is for JSX to recognize the web components. I've updated the names and definitions to be a bit more reflective (hasn't been looked at it in depth for about a year). The kebob case is intentional because those are the properties of the web components.


export default IobioPanel;

export type IobioPanelType = typeof IobioPanel;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the use case of this?
Is there a case where we want to provide a specific IobioPanel react node as a prop?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these were intended to have a Type representation for the components. But they are unused here and in Stage so they could probably be removed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming conventions generally don't want a type to be named with Type, its redundant. There is no harm in having the type name be the same as the variable name (ie. IobioPanel).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joneubank I removed all of these IobioComponentType definitions, they don't have an immediate use case:
e689473

Comment thread packages/iobio-react-components/src/utils/scoreFileTools.mts Outdated
Comment thread packages/iobio-react-components/src/utils/scoreFileTools.mts
Comment thread packages/iobio-react-components/src/utils/scoreFileTools.mts Outdated
Comment thread packages/iobio-react-components/src/utils/scoreFileTools.mts Outdated
Comment thread packages/iobio-react-components/src/components/labelInfoButton.tsx
joneubank
joneubank previously approved these changes Aug 11, 2025

@joneubank joneubank left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good, left two very small suggestions.


export type IobioInfoModalKeys = BamHistogramKey | BamPercentKey;

export const infoModalCopy: { [K in IobioInfoModalKeys]: string } = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export const infoModalCopy: { [K in IobioInfoModalKeys]: string } = {
export const infoModalCopy: Record<IobioInfoModalKeys, string> = {

const urlParams = new URLSearchParams(scoreDownloadParams).toString();
try {
const scoreUrl = urlJoin(scoreApiUrl, scoreApiDownloadPath, objectId, `?${urlParams}`);
const response = (await fetch(scoreUrl)).json();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combining .json() onto this line doesn't actually address the issue @ciaranschutte was pointing out, this now returns the Promise from the .json deserialization to the caller and requires them to handle those errors. If you want any errors from the .json call to be handled by the catch block in this function then you need to await the .json() call as well:

const response = await fetch(scoreUrl);
const jsonData = await response.json();
return jsonData;

uploadId: zod.string().optional(),
});

export type FileMetaData = zod.infer<typeof fileMetaDataSchema>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@ciaranschutte
ciaranschutte dismissed their stale review August 12, 2025 05:06

Jon approved :thumbs-up:

@demariadaniel
demariadaniel merged commit 90fc1f3 into main Aug 12, 2025
@demariadaniel
demariadaniel deleted the 79/bug-fixes-for-modal branch August 12, 2025 12:46
@demariadaniel demariadaniel mentioned this pull request Aug 13, 2025
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants