Skip to content

Commit

Permalink
Merge pull request #418 from Smithsonian/develop
Browse files Browse the repository at this point in the history
v0.9.11 Release Candidate 7
  • Loading branch information
jahjedtieson authored Jun 27, 2022
2 parents 6e11d27 + 430b866 commit 92aac26
Show file tree
Hide file tree
Showing 46 changed files with 2,264 additions and 1,228 deletions.
84 changes: 53 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,74 @@
Data Repository and Workflow Management for 3D data captures, models, and scenes

## Setup instructions (Development):
**Note**: *the setup instructions below are **out of date**. Updates are expected by 6/15/2022*

*Note: `.env.dev` is required and it follows `.env.template`*

### Development:

#### Prerequisites:
It is recommended to install [Volta](https://volta.sh/) which keeps node version in check. The versions can be specified in `package.json` and when switched to the directory of the project, volta automatically switches to the correct node version.
* It is recommended to install [Volta](https://volta.sh/) which keeps node version in check. The versions can be specified in `package.json` and when switched to the directory of the project, volta automatically switches to the correct node version.
* It is also recommended to use [Yarn](https://yarnpkg.com/) as the primary package manager for Packrat.


```
cd ~
curl https://get.volta.sh | bash
volta install node
volta install yarn
```
Now when you switch to the `dpo-packrat` repo, your node version would automatically pinned to the correct version by volta.
When switching to the `dpo-packrat` repo, the node version will automatically be pinned to the correct version by volta.


1. Install the dependencies:
#### Steps:
1. Install the dependencies *(at the root level)*. [Lerna](https://lerna.js.org/) will ensure the subdirectories’ packages are also installed.

```
yarn
```

2. Build the docker images, if they're already available then this would just start them (if you're on a mac then make sure Docker for mac is running):
2. Export the environment variables *(at the root level)* after `.env.dev` has been configured.
```
export $(grep -v ‘^#’ .env.dev | xargs)
```

```
3. Generate GraphQL and Prisma code *(in the server directory)*.
*Note: make sure to generate them whenever changes have been made to the GraphQL schemas.*

```
cd server
yarn generate
```

4. If using Docker, build the Docker images and containers *(at the root)*. If they're already available then issuing the following command would start the containers.
*Note: if building the images and containers, this process can take an upwards of 20 minutes.*

**If setting up Packrat without Docker, skip to step 9**

```
cd ..
yarn dev
```

3. Now the docker containers should start in 10s-20s. The client should be reachable at `http://localhost:3000` and server should be reachable at `http://localhost:4000` or the ports you specified in `.env.dev` following `.env.template`
5. Once the Docker images and containers are built, they should start in 10s-20s. The client should be reachable at `http://localhost:3000` and server should be reachable at `http://localhost:4000`, or the ports specified in `.env.dev`.

6. To follow debug logs for `client` or `server` container, run `yarn log:client` or `yarn log:server` *(at the root)*.

7. To log in and use Packrat, the database must be first initialized with data and user info *(in the server directory)*.

```
cd server
yarn initdbdock
```

8. After the database has been initialized, Solr enterprise-search needs to be indexed in order to populate the repository.
Navigate to `localhost:4000/solrindex` in the browser and wait for the result to appear. Once Solr finishes indexing, set up via Docker is complete!

*Note: sometimes a failure message will appear even upon successful indexing. Successful indexing can be seen in the server container logs and by visiting the repository and finding the newly populated entries.*

4. If you want to follow debug logs for `client` or `server` container then just run `yarn log:client` or `yarn log:server`
9. If setting up Packrat without Docker, compile the typescript code in a separate terminal *(for the common directory)*.
```
cd common
yarn start
```

5. If not using docker run each command in a separate terminal for the package you're developing:
10. Run each command in separate terminals *(at the root level)*:

**For client:**

Expand All @@ -50,10 +83,16 @@ yarn start:client
yarn start:server
```

11. Setting up Packrat without Docker gives users the flexbility to install and configure their own database and Solr caching as needed.


**Congratulations, Packrat is now ready for use!**


# Alternative docker workflow:

```
# If step 2. wasn't working, follow this alternative instead.
# If step 4 for building and starting the docker containers are failing, follow this alternative instead.
# Creates Devbox for packrat
yarn devbox:up
# Creates DB for devbox
Expand Down Expand Up @@ -107,20 +146,3 @@ sudo mount /tmp -o remount,exec
5. Wait for the images to be build/updated, then use `./conf/scripts/cleanup.sh` script to cleanup any residual docker images are left (optional)

6. Make sure nginx is active using `sudo service nginx status --no-pager`

## Start databases (Production server only):

1. Start `dev` or `prod` databases using `./conf/scripts/initdb.sh` script
```
MYSQL_ROOT_PASSWORD=<your_mysql_password> ./conf/scripts/initdb.sh dev
```
*Note: `MYSQL_ROOT_PASSWORD` be same what you mentioned in the `.env.dev` or `.env.prod` file for that particular environment. Mostly would be used for `dev` environment.*

## Update production nginx configuration (Production server only):

1. Make the changes to production nginx configuration is located at `scripts/proxy/nginx.conf`

2. Use `conf/scripts/refreshProxy.sh` script to restart/update nginx service
```
./conf/scripts/refreshProxy.sh
```
6 changes: 4 additions & 2 deletions client/src/pages/Admin/components/AdminUsersView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ function AdminUsersView(): React.ReactElement {
active: User_Status.EAll,
search: ''
}
}
},
fetchPolicy: 'no-cache'
});
const {
data: {
Expand All @@ -70,7 +71,8 @@ function AdminUsersView(): React.ReactElement {
active: newActive,
search: newSearchText
}
}
},
fetchPolicy: 'no-cache'
});
const {
data: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { StateFolder, VocabularyOption } from '../../../../../store';
import { palette } from '../../../../../theme';
import { ViewableProps } from '../../../../../types/repository';
import { getNullableSelectEntries } from '../../../../../utils/controls';
import { updatedFieldStyling } from '../../../../Repository/components/DetailsView/DetailsTab/CaptureDataDetails';

export const useStyles = makeStyles(({ palette, typography, breakpoints }) => ({
emptyFolders: {
Expand Down Expand Up @@ -47,12 +48,13 @@ export const useStyles = makeStyles(({ palette, typography, breakpoints }) => ({

interface AssetContentsProps extends ViewableProps {
folders: StateFolder[];
originalFolders: StateFolder[];
options: VocabularyOption[];
onUpdate: (id: number, variantType: number) => void;
}

function AssetContents(props: AssetContentsProps): React.ReactElement {
const { folders, options, onUpdate, disabled = false } = props;
const { folders, options, onUpdate, disabled = false, originalFolders } = props;
const classes = useStyles();
return (
<TableContainer component={Paper} className={classes.tableContainer} elevation={0}>
Expand All @@ -72,7 +74,7 @@ function AssetContents(props: AssetContentsProps): React.ReactElement {
</TableRow>
{folders.length > 0 && (folders.map(({ id, name, variantType }: StateFolder, index: number) => {
const update = ({ target }) => onUpdate(id, target.value);

const originalFolder = originalFolders.find((folder) => folder.name === name);
return (
<TableRow key={index}>
<TableCell className={classes.paddedCell} style={{ paddingTop: index === 0 ? 5 : 1 }}>
Expand All @@ -92,6 +94,7 @@ function AssetContents(props: AssetContentsProps): React.ReactElement {
disableUnderline
className={classes.select}
SelectDisplayProps={{ style: { paddingLeft: '10px', paddingRight: '10px', borderRadius: '5px' } }}
style={{ ...updatedFieldStyling(originalFolder?.variantType !== variantType) }}
>
{getNullableSelectEntries(options, 'idVocabulary', 'Term').map(({ value, label }, index) => <MenuItem key={index} value={value}>{label}</MenuItem>)}
</Select>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ function Photogrammetry(props: PhotogrammetryProps): React.ReactElement {

<AssetContents
folders={photogrammetry.folders}
originalFolders={[...photogrammetry.folders]}
options={getEntries(eVocabularySetID.eCaptureDataFileVariantType)}
onUpdate={updateFolderVariant}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { Box, MenuItem, Select, Typography, Table, TableBody, TableCell, TableContainer, TableRow, Paper, Checkbox } from '@material-ui/core';
import React, { useEffect } from 'react';
import { DateInputField, Loader } from '../../../../../components';
import { parseFoldersToState, useVocabularyStore } from '../../../../../store';
import { parseFoldersToState, StateFolder, useVocabularyStore } from '../../../../../store';
import { eVocabularySetID, eSystemObjectType } from '@dpo-packrat/common';
import { isFieldUpdated } from '../../../../../utils/repository';
import { withDefaultValueNumber } from '../../../../../utils/shared';
Expand Down Expand Up @@ -166,6 +166,10 @@ function CaptureDataDetails(props: DetailComponentProps): React.ReactElement {
const cdMethods = getEntries(eVocabularySetID.eCaptureDataCaptureMethod);
const captureMethodidVocabulary = withDefaultValueNumber(CaptureDataDetails?.captureMethod, getInitialEntry(eVocabularySetID.eCaptureDataCaptureMethod));
const captureMethod = cdMethods.find(method => method.idVocabulary === captureMethodidVocabulary);

const cdDetailsDate = new Date(CaptureDataDetails.dateCaptured as string);
const cdDataDate = new Date(captureDataData?.dateCaptured as string);

return (
<Box>
<Description
Expand Down Expand Up @@ -198,7 +202,7 @@ function CaptureDataDetails(props: DetailComponentProps): React.ReactElement {
</TableCell>
<TableCell className={classes.tableCell}>
<DateInputField
updated={isFieldUpdated(CaptureDataDetails, captureDataData, 'dateCaptured')}
updated={`${cdDataDate.getMonth()}/${cdDataDate.getDate()}/${cdDataDate.getFullYear()}` !== `${cdDetailsDate.getMonth()}/${cdDetailsDate.getDate()}/${cdDetailsDate.getFullYear()}`}
value={new Date(CaptureDataDetails?.dateCaptured ?? Date.now())}
disabled={disabled}
onChange={(_, value) => setDateField('dateCaptured', value)}
Expand Down Expand Up @@ -235,6 +239,7 @@ function CaptureDataDetails(props: DetailComponentProps): React.ReactElement {
folders={parseFoldersToState(CaptureDataDetails?.folders ?? [])}
options={getEntries(eVocabularySetID.eCaptureDataFileVariantType)}
onUpdate={updateFolderVariant}
originalFolders={data?.getDetailsTabDataForObject?.CaptureData?.folders as StateFolder[]}
/>

<Box className={classes.fieldTableBoxContainer}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export interface ItemDetailFields extends SubjectDetailFields {
}

function ItemDetails(props: DetailComponentProps): React.ReactElement {
const { data, loading, disabled, onUpdateDetail, objectType, subtitle, onSubtitleUpdate } = props;
const { data, loading, disabled, onUpdateDetail, objectType, subtitle, onSubtitleUpdate, originalSubtitle } = props;

const [ItemDetails, updateDetailField] = useDetailTabStore(state => [state.ItemDetails, state.updateDetailField]);

useEffect(() => {
Expand Down Expand Up @@ -50,6 +51,7 @@ function ItemDetails(props: DetailComponentProps): React.ReactElement {
disabled={disabled}
onChange={onSetField}
subtitle={subtitle}
originalSubtitle={originalSubtitle}
onSubtitleUpdate={onSubtitleUpdate}
isItemView
setCheckboxField={setCheckboxField}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { DetailComponentProps } from './index';
import { useStyles as useSelectStyles, SelectFieldProps } from '../../../../../components/controls/SelectField';
import { DebounceInput } from 'react-debounce-input';
import ObjectMeshTable from '../../../../Ingestion/components/Metadata/Model/ObjectMeshTable';
import { updatedFieldStyling } from './CaptureDataDetails';
import { isFieldUpdated } from '../../../../../utils/repository';

export const useStyles = makeStyles(({ palette, typography }) => ({
notRequiredFields: {
Expand Down Expand Up @@ -85,7 +87,7 @@ export const useStyles = makeStyles(({ palette, typography }) => ({

function ModelDetails(props: DetailComponentProps): React.ReactElement {
const classes = useStyles();
const { data, loading, onUpdateDetail, objectType, subtitle, onSubtitleUpdate } = props;
const { data, loading, onUpdateDetail, objectType, subtitle, onSubtitleUpdate, originalSubtitle } = props;

const { ingestionModel, modelObjects } = extractModelConstellation(data?.getDetailsTabDataForObject?.Model);
const [ModelDetails, updateDetailField] = useDetailTabStore(state => [state.ModelDetails, state.updateDetailField]);
Expand Down Expand Up @@ -132,7 +134,7 @@ function ModelDetails(props: DetailComponentProps): React.ReactElement {
</Typography>
</div>
<div style={{ gridColumnStart: 2, gridColumnEnd: 3 }}>
<DebounceInput value={subtitle} onChange={onSubtitleUpdate} className={classes.input} />
<DebounceInput value={subtitle} onChange={onSubtitleUpdate} className={classes.input} style={{ ...updatedFieldStyling(subtitle !== originalSubtitle) }} />
</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '120px calc(100% - 120px)', gridColumnGap: 5, padding: '3px 10px 3px 10px', height: 20 }}>
Expand All @@ -141,8 +143,8 @@ function ModelDetails(props: DetailComponentProps): React.ReactElement {
Date Created
</Typography>
</div>
<div style={{ gridColumnStart: 2, gridColumnEnd: 3 }}>
<DateInputField value={ModelDetails.DateCreated} onChange={date => setDateField(date)} dateHeight='22px' />
<div style={{ gridColumnStart: 2, gridColumnEnd: 3 }} >
<DateInputField value={ModelDetails.DateCreated} onChange={date => setDateField(date)} dateHeight='22px' updated={new Date(ingestionModel.DateCreated).toString() !== new Date(ModelDetails?.DateCreated as string)?.toString()} />
</div>
</div>
<SelectField
Expand All @@ -155,6 +157,7 @@ function ModelDetails(props: DetailComponentProps): React.ReactElement {
selectHeight='24px'
valueLeftAligned
selectFitContent
updated={isFieldUpdated(ModelDetails, ingestionModel, 'idVCreationMethod')}
/>
<SelectField
required
Expand All @@ -166,6 +169,7 @@ function ModelDetails(props: DetailComponentProps): React.ReactElement {
selectHeight='24px'
valueLeftAligned
selectFitContent
updated={isFieldUpdated(ModelDetails, ingestionModel, 'idVModality')}
/>

<SelectField
Expand All @@ -178,6 +182,7 @@ function ModelDetails(props: DetailComponentProps): React.ReactElement {
selectHeight='24px'
valueLeftAligned
selectFitContent
updated={isFieldUpdated(ModelDetails, ingestionModel, 'idVUnits')}
/>

<SelectField
Expand All @@ -190,6 +195,7 @@ function ModelDetails(props: DetailComponentProps): React.ReactElement {
selectHeight='24px'
valueLeftAligned
selectFitContent
updated={isFieldUpdated(ModelDetails, ingestionModel, 'idVPurpose')}
/>

<SelectField
Expand All @@ -202,6 +208,7 @@ function ModelDetails(props: DetailComponentProps): React.ReactElement {
selectHeight='24px'
valueLeftAligned
selectFitContent
updated={isFieldUpdated(ModelDetails, ingestionModel, 'idVFileType')}
/>
</Box>

Expand Down Expand Up @@ -235,7 +242,7 @@ export default ModelDetails;


function SelectField(props: SelectFieldProps): React.ReactElement {
const { value, name, options, onChange, disabled = false, label } = props;
const { value, name, options, onChange, disabled = false, label, updated = false } = props;
const classes = useSelectStyles(props);

return (
Expand All @@ -253,7 +260,7 @@ function SelectField(props: SelectFieldProps): React.ReactElement {
disabled={disabled}
disableUnderline
inputProps={{ 'title': `${name} select`, style: { width: '100%' } }}
style={{ minWidth: '100%', width: 'fit-content' }}
style={{ minWidth: '100%', width: 'fit-content', ...updatedFieldStyling(updated) }}
SelectDisplayProps={{ style: { paddingLeft: '10px', borderRadius: '5px' } }}
>
{options.map(({ idVocabulary, Term }, index) => (
Expand Down
Loading

0 comments on commit 92aac26

Please sign in to comment.