-
Notifications
You must be signed in to change notification settings - Fork 5
#66 🪟 Add Visualizer Modal #248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
2b89570
Install react-modal
demariadaniel 585b3b0
Most Basic Modal Setup
demariadaniel 900f15e
First Pass CSS & Navigation; icons alphabetized
demariadaniel 5221b33
Modal File & images
demariadaniel 7c2446a
Improved modal/button/image styles
demariadaniel 564281a
File Format badges & visualizer descriptions
demariadaniel a641811
Finalized container proportions, cursor, semantics & reorg
demariadaniel 72bf29d
Disabled states
demariadaniel 8babba6
Handle tables enabled/disabled w/ env
demariadaniel d124d8b
Fix package-lock
demariadaniel cd3030a
PR improvements
demariadaniel 2569fe9
Default Iobio disabled
demariadaniel ca908e3
First batch code review updates
demariadaniel ea1d0d0
className use strings
demariadaniel e3efc79
Use derived state for current files
demariadaniel 12ba4d0
Prefer css-in-js
demariadaniel 9307856
Merge branch 'iobio' of https://github.com/overture-stack/stage into …
demariadaniel 82f8dba
Break Modal into components
demariadaniel 2d449e8
Handle key warning
demariadaniel 6b0e5af
Standardize use of Visualizer, Colocate Styles
demariadaniel 51a8cdf
Remove duplicate Modal.setAppElement
demariadaniel 5245031
Anchor files/badges to bottom
demariadaniel 5cc2095
Remove unused import
demariadaniel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,264 @@ | ||
| /* | ||
| * | ||
| * Copyright (c) 2025 The Ontario Institute for Cancer Research. All rights reserved | ||
| * | ||
| * This program and the accompanying materials are made available under the terms of | ||
| * the GNU Affero General Public License v3.0. You should have received a copy of the | ||
| * GNU Affero General Public License along with this program. | ||
| * If not, see <http://www.gnu.org/licenses/>. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY | ||
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT | ||
| * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||
| * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | ||
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
| * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
| * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| * | ||
| */ | ||
|
|
||
| import { css, useTheme, Theme } from '@emotion/react'; | ||
| import urlJoin from 'url-join'; | ||
| import { getConfig } from '../../../../global/config'; | ||
| import { BamFileExtensions, tableTypes } from '../constants'; | ||
| import { FileTableData } from '../fileTypes'; | ||
| import { BadgeItem, VisualizerDetailProps } from './types'; | ||
|
|
||
| const accentBadgeStyle = ({ theme, isDisabled }: { theme: Theme; isDisabled: boolean }) => css` | ||
| ${badgeStyle({ theme, isDisabled })} | ||
| background-color: ${theme.colors.accent_light}; | ||
| margin-left: 5px; | ||
| ${isDisabled ? `background-color: ${theme.colors.grey_5};` : ''} | ||
| `; | ||
|
|
||
| const badgeStyle = ({ theme, isDisabled }: { theme: Theme; isDisabled: boolean }) => css` | ||
| display: inline-flex; | ||
| border: none; | ||
| border-radius: 20px; | ||
| margin: 5px; | ||
| margin-left: 0px; | ||
| min-width: fit-content; | ||
| padding: 3px 10px; | ||
| background-color: ${theme.colors.accent}; | ||
| color: ${theme.colors.white}; | ||
|
|
||
| ${isDisabled ? `background-color: ${theme.colors.grey_6};` : ''} | ||
| `; | ||
|
|
||
| const optionStyle = ({ theme, isEnabled }: { theme: Theme; isEnabled: boolean }) => css` | ||
| background: unset; | ||
| border: 1px solid ${theme.colors.grey_5}; | ||
| border-radius: 16px; | ||
| cursor: pointer; | ||
| display: inline-flex; | ||
| flex: 1; | ||
| font-family: 'Lato', sans-serif; | ||
| margin: 0 0.5rem; | ||
| padding: 10px; | ||
| position: relative; | ||
|
|
||
| ${isEnabled ? '' : `cursor: not-allowed;`} | ||
| `; | ||
|
|
||
| export const VisualizerDetail = ({ title, description, previewImage, logoImage }: VisualizerDetailProps) => { | ||
| return ( | ||
| <> | ||
| <div | ||
| css={css` | ||
| max-height: 28%; | ||
| overflow-y: hidden; | ||
|
|
||
| img { | ||
| width: 100%; | ||
| } | ||
| `} | ||
| > | ||
| <img src={previewImage} /> | ||
| </div> | ||
| <div | ||
| css={css` | ||
| text-align: left; | ||
| `} | ||
| > | ||
| <img | ||
| css={css` | ||
| height: 18px; | ||
| vertical-align: text-bottom; | ||
| width: 18px; | ||
| `} | ||
| src={logoImage} | ||
| /> | ||
| <h4 | ||
| css={css` | ||
| display: inline-block; | ||
| font-size: 18px; | ||
| margin: 0.5rem; | ||
| `} | ||
| > | ||
| {title} | ||
| </h4> | ||
| </div> | ||
| <p | ||
| css={css` | ||
| font-weight: 400; | ||
| font-size: 16px; | ||
| line-height: 16px; | ||
| margin-top: 0px; | ||
| text-align: left; | ||
| height: 30%; | ||
| `} | ||
| > | ||
| {description} | ||
| </p> | ||
| </> | ||
| ); | ||
| }; | ||
|
|
||
| export const Badges = ({ isEnabled, badges }: { isEnabled: boolean; badges: BadgeItem[] }) => { | ||
| const theme = useTheme(); | ||
| const badgeGroup = badges.map((badge, index) => { | ||
| const badgeCss = badge.isAccent | ||
| ? accentBadgeStyle({ theme, isDisabled: !isEnabled }) | ||
| : badgeStyle({ theme, isDisabled: !isEnabled }); | ||
| return ( | ||
| <div key={`badge-${index}`} css={badgeCss}> | ||
| {badge.label} | ||
| </div> | ||
| ); | ||
| }); | ||
| return <>{badgeGroup}</>; | ||
| }; | ||
|
|
||
|
Comment on lines
+119
to
+133
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, missing |
||
| export const VisualizerOption = ({ | ||
| badges, | ||
| details: { title, description, previewImage, logoImage }, | ||
| isEnabled, | ||
| onClick, | ||
| }: { | ||
| badges: BadgeItem[]; | ||
| details: VisualizerDetailProps; | ||
| isEnabled: boolean; | ||
| onClick: () => void; | ||
| }) => { | ||
| const theme = useTheme(); | ||
| return ( | ||
| <button css={optionStyle({ theme, isEnabled })} disabled={!isEnabled} onClick={onClick}> | ||
| <div> | ||
| <VisualizerDetail title={title} description={description} previewImage={previewImage} logoImage={logoImage} /> | ||
|
|
||
| <div | ||
| css={css` | ||
| position: absolute; | ||
| bottom: 10px; | ||
| `} | ||
| > | ||
| <h5 | ||
| css={css` | ||
| font-weight: 700; | ||
| font-size: 16px; | ||
| margin: 0.25rem 0; | ||
| text-align: left; | ||
| `} | ||
| > | ||
| Files: | ||
| </h5> | ||
| <div | ||
| css={css` | ||
| display: flex; | ||
| `} | ||
| > | ||
| <Badges isEnabled={isEnabled} badges={badges} /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </button> | ||
| ); | ||
| }; | ||
|
|
||
| /** | ||
| * | ||
| * Responsibility is rendering the options available | ||
| * ie. read configs, gather data etc then render each option with data | ||
| * | ||
| */ | ||
| export const VisualizerModal = ({ | ||
| closeModal, | ||
| setTable, | ||
| currentFiles, | ||
| }: { | ||
| closeModal: () => void; | ||
| setTable: (tableType: string) => void; | ||
| currentFiles: FileTableData[]; | ||
| }) => { | ||
| const { | ||
| NEXT_PUBLIC_BASE_PATH, | ||
| NEXT_PUBLIC_IOBIO_ENABLED, | ||
| NEXT_PUBLIC_JBROWSE_ENABLED, | ||
| NEXT_PUBLIC_CBIOPORTAL_ENABLED, | ||
| } = getConfig(); | ||
|
|
||
| const isJbrowseEnabled = NEXT_PUBLIC_JBROWSE_ENABLED && currentFiles.length <= 5; | ||
| const isCBioEnabled = NEXT_PUBLIC_CBIOPORTAL_ENABLED && currentFiles.length <= 2; | ||
| const isIobioEnabled = | ||
| NEXT_PUBLIC_IOBIO_ENABLED && | ||
| currentFiles.length === 1 && | ||
| currentFiles[0].file_type && | ||
| BamFileExtensions.includes(currentFiles[0].file_type); | ||
|
|
||
| const selectVisualizer = (tableType: string) => () => { | ||
| setTable(tableType); | ||
| closeModal(); | ||
| }; | ||
|
|
||
| return ( | ||
| <> | ||
| <VisualizerOption | ||
| badges={[ | ||
| { label: '5 Max', isAccent: false }, | ||
| { label: '.VCF', isAccent: true }, | ||
| { label: '.BAM', isAccent: true }, | ||
| ]} | ||
| onClick={selectVisualizer(tableTypes.JBROWSE_TABLE)} | ||
| isEnabled={isJbrowseEnabled} | ||
| details={{ | ||
| title: 'JBrowse', | ||
| description: | ||
| 'A fully featured genome browser that is capable of visualizing diverse types of genome-located data.', | ||
| previewImage: urlJoin(NEXT_PUBLIC_BASE_PATH, '/images/jBrowse_Preview.png'), | ||
| logoImage: urlJoin(NEXT_PUBLIC_BASE_PATH, '/images/jBrowse_Logo.png'), | ||
| }} | ||
| /> | ||
| <VisualizerOption | ||
| badges={[ | ||
| { label: '1 Max', isAccent: false }, | ||
| { label: '.BAM', isAccent: true }, | ||
| ]} | ||
| onClick={selectVisualizer(tableTypes.BAM_TABLE)} | ||
| isEnabled={!!isIobioEnabled} | ||
| details={{ | ||
| title: 'IOBIO', | ||
| description: 'Examine your sequence alignment file in seconds', | ||
| previewImage: urlJoin(NEXT_PUBLIC_BASE_PATH, '/images/IOBIO_Preview.png'), | ||
| logoImage: urlJoin(NEXT_PUBLIC_BASE_PATH, '/images/IOBIO_Logo.png'), | ||
| }} | ||
| /> | ||
| <VisualizerOption | ||
| badges={[ | ||
| { label: '2 Max', isAccent: false }, | ||
| { label: '.VCF', isAccent: true }, | ||
| { label: '.BAM', isAccent: true }, | ||
| ]} | ||
| details={{ | ||
| title: 'cBioPortal', | ||
| description: 'Provides visualization, analysis and download of large-scale cancer genomics data sets.', | ||
| previewImage: urlJoin(NEXT_PUBLIC_BASE_PATH, '/images/cBioPortal_Preview.png'), | ||
| logoImage: urlJoin(NEXT_PUBLIC_BASE_PATH, '/images/cBioPortal_Logo.png'), | ||
| }} | ||
| isEnabled={isCBioEnabled} | ||
| onClick={selectVisualizer(tableTypes.CBIO_TABLE)} | ||
| /> | ||
| </> | ||
| ); | ||
| }; | ||
Oops, something went wrong.
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.

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this change, all of the behaviour of this button has been moved outside of this component. The button does whatever
openModalspecifies. Even a decision about whether it is enabled is based on props.Perhaps its just a case where we need to rename the props to
onClickinstead ofopenModaland replacevisualizerEnabledandisFileTableActiveto a singledisabledorenabledprop.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will look into how I can organize this better. The intent was to have
openModal/closeModalas fixed utilities which always do the same thing, but because they usestateyou can't export them that way, and have to be scoped within a component render/props pattern (which is intended to be mutable). So you get this sort of organizational conflict.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to use
disabled