Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
# Install dependencies only when needed
FROM node:14-alpine AS builder
FROM node:14-alpine AS deps

# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat

WORKDIR /app
COPY package.json yarn.lock ./

# Install all dependencies (including dev)
RUN yarn install --frozen-lockfile

# Build stage
FROM node:14-alpine AS builder

RUN apk add --no-cache libc6-compat

WORKDIR /app

# Copy deps from deps stage
COPY --from=deps /app/node_modules ./node_modules
COPY package.json yarn.lock ./

# Copy source code
COPY . .

# Build
RUN yarn install --frozen-lockfile
RUN yarn build

# Install only production dependencies in a clean directory
RUN rm -rf node_modules
# Production dependencies stage
FROM deps AS prod-deps

# Install only production dependencies
RUN yarn install --production --frozen-lockfile

# Production image, copy all the files and run next
Expand All @@ -28,7 +46,7 @@ RUN adduser -S nextjs -u 1001
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=prod-deps /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

USER nextjs
Expand Down
99 changes: 62 additions & 37 deletions frontend/components/Submit/ChooseCollection/ChooseCollection.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { faInfoCircle, faPlus } from '@fortawesome/free-solid-svg-icons';
import { faInfoCircle, faPlus, faSearch } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { setPromptNewCollection } from '../../../redux/actions';
Expand All @@ -24,48 +24,73 @@ export default function ChooseCollection(properties) {
state => state.collectionCreate.promptNewCollection
);

// Handle forceNewCollection prop - only update if it doesn't match current state
useEffect(() => {
if (properties.forceNewCollection === true && !promptNewCollection) {
dispatch(setPromptNewCollection(true));
} else if (properties.forceNewCollection === false && promptNewCollection) {
dispatch(setPromptNewCollection(false));
}
}, [properties.forceNewCollection, promptNewCollection, dispatch]);

// Don't show the label if it's empty
const showLabel = properties.label && properties.label.trim() !== '';

// Don't show create button if showCreateButton is false
const showCreateButton = properties.showCreateButton !== false;

return (
<div>
<MajorLabel
text={properties.label}
link="https://wiki.synbiohub.org/userdocumentation/managingsubmitting/"
/>
<div className={styles.inputandcreatecontainer}>
<input
type="text"
value={filter}
className={`${styles.collectionfilter} ${
promptNewCollection ? styles.collpasefilter : ''
} ${selectedCollection ? styles.collectionfilteraactive : ''}`}
placeholder={
selectedCollection
? `${selectedCollection.name}, version ${selectedCollection.version}`
: 'Filter by name, display ID, description, or version'
}
onChange={event => setFilter(event.target.value)}
{showLabel && (
<MajorLabel
text={properties.label}
link="https://wiki.synbiohub.org/userdocumentation/managingsubmitting/"
/>
<div
className={`${styles.newcollectionbutton} ${
promptNewCollection ? styles.newcollectionbuttonactive : ''
}`}
role="button"
onClick={() => {
setFilter('');
dispatch(setPromptNewCollection(true));
}}
>
<FontAwesomeIcon
icon={!promptNewCollection ? faPlus : faInfoCircle}
size="1x"
className={styles.createcollectionbuttonicon}
/>
{createCollectionButtonText}
</div>
)}
<div className={styles.inputandcreatecontainer}>
{!promptNewCollection && (
<div className={styles.searchInputWrapper}>
<FontAwesomeIcon
icon={faSearch}
className={styles.searchIcon}
/>
<input
type="text"
value={filter}
className={`${styles.collectionfilter} ${
promptNewCollection ? styles.collpasefilter : ''
} ${selectedCollection ? styles.collectionfilteraactive : ''}`}
placeholder={
selectedCollection
? `${selectedCollection.name}, version ${selectedCollection.version}`
: 'Filter by name, display ID, description, or version'
}
onChange={event => setFilter(event.target.value)}
/>
</div>
)}
{showCreateButton && !promptNewCollection && (
<div
className={styles.newcollectionbutton}
role="button"
onClick={() => {
setFilter('');
dispatch(setPromptNewCollection(true));
}}
>
<FontAwesomeIcon
icon={faPlus}
size="1x"
className={styles.createcollectionbuttonicon}
/>
{createCollectionButtonText}
</div>
)}
</div>
{!promptNewCollection ? (
<CollectionDisplay filter={filter} setFilter={setFilter} />
) : (
<NewCollectionForm />
<NewCollectionForm hideCancel={properties.hideCancel} />
)}
</div>
);
Expand Down
32 changes: 17 additions & 15 deletions frontend/components/Submit/NewCollection/NewCollectionButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,23 @@ export default function NewCollectionButtons(properties) {
const dispatch = useDispatch();
return (
<div className={styles.createcollectionbuttons}>
<div
className={`${styles.createcollectionbutton} ${styles.cancelbutton}`}
role="button"
onClick={() => {
dispatch(getCanSubmitTo());
dispatch(setPromptNewCollection(false));
}}
>
<FontAwesomeIcon
icon={faArrowCircleLeft}
size="1x"
className={styles.cancelbuttonicon}
/>
Cancel
</div>
{!properties.hideCancel && (
<div
className={`${styles.createcollectionbutton} ${styles.cancelbutton}`}
role="button"
onClick={() => {
dispatch(getCanSubmitTo());
dispatch(setPromptNewCollection(false));
}}
>
<FontAwesomeIcon
icon={faArrowCircleLeft}
size="1x"
className={styles.cancelbuttonicon}
/>
Cancel
</div>
)}
<div
className={`${styles.createcollectionbutton} ${styles.createbutton} ${
properties.needsVerification ? '' : styles.createbuttonenabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export default function NewCollectionForm(properties) {
needsVerification={needsVerification}
postCollection={postCollection}
title="Create"
hideCancel={properties.hideCancel}
/>
</div>
);
Expand Down
42 changes: 21 additions & 21 deletions frontend/components/Submit/OverwriteObjects.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useEffect, useState } from 'react';

import styles from '../../styles/submit.module.css';
Expand Down Expand Up @@ -28,35 +26,37 @@ export default function OverwriteObjects(properties) {
}
}, []);

const handleContainerClick = () => {
if (!properties.checked && enablePrompt) {
setWarnUser(true);
} else {
properties.setChecked(!properties.checked);
}
};

return (
<div className={styles.overwritecontainer}>
<div className={styles.overwriteinputcontainer}>
<div
className={styles.overwriteinputcontainer}
onClick={handleContainerClick}
role="button"
tabIndex={0}
onKeyPress={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleContainerClick();
}
}}
>
<input
type="checkbox"
checked={properties.checked}
onChange={event => {
if (event.target.checked && enablePrompt) setWarnUser(true);
else properties.setChecked(event.target.checked);
}}
onChange={() => {}} // Controlled by container click
readOnly
/>
<div className={styles.overwritemessage}>
Overwrite Existing Collection
</div>
</div>
<div>
<a
href="https://wiki.synbiohub.org/userdocumentation/managingsubmitting#411-creating-a-new-collection"
target="_blank"
rel="noreferrer"
>
<FontAwesomeIcon
icon={faInfoCircle}
size="1x"
className={`${styles.submitinfoicon} ${styles.enlargeicononhover}`}
color="#00A1E4"
/>
</a>
</div>
{warnUser && enablePrompt ? (
<Message
message="Are you sure you want to overwrite existing objects in the collection? All objects currently existing in the collection will be lost."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export default function InputField(properties) {
<Input
type={properties.customType || 'text'}
name={properties.inputName}
id={properties.inputName}
value={properties.value}
checked={properties.value}
onChange={event => properties.onChange(event)}
Expand Down
6 changes: 3 additions & 3 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "git rev-parse HEAD > ./public/commitHash.txt; next dev -p 3333",
"devNextGen": "git rev-parse HEAD > ./public/commitHash.txt; NODE_OPTIONS=--openssl-legacy-provider next dev -p 3333",
"dev": "git rev-parse HEAD > ./public/commitHash.txt; next dev -p ${PORT:-3333}",
"devNextGen": "git rev-parse HEAD > ./public/commitHash.txt; NODE_OPTIONS=--openssl-legacy-provider next dev -p ${PORT:-3333}",
"build": "git rev-parse HEAD > ./public/commitHash.txt; next build",
"buildNextGen": "git rev-parse HEAD > ./public/commitHash.txt; NODE_OPTIONS=--openssl-legacy-provider next build",
"testbuild": "NODE_OPTIONS=--openssl-legacy-provider next build",
"start": "next start -p 3333",
"start": "next start -p ${PORT:-3333}",
"lint": "eslint '*/**/*.{js,jsx}'",
"lint.fix": "eslint '*/**/*.{js,jsx}' --fix",
"test": "jest"
Expand Down
17 changes: 17 additions & 0 deletions frontend/pages/_document.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Document, { Html, Head, Main, NextScript } from 'next/document';

class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}

export default MyDocument;
Loading
Loading