Skip to content

Commit

Permalink
Merge pull request #129 from pughlab/qa
Browse files Browse the repository at this point in the history
Qa
  • Loading branch information
mickey-ng authored Feb 26, 2024
2 parents 85d0ccb + bc7c407 commit 785ed45
Show file tree
Hide file tree
Showing 47 changed files with 1,337 additions and 623 deletions.
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ ARG NEXTAUTH_SECRET
ARG REACT_APP_API_URL
ARG NEXTAUTH_URL
ARG NEXTAUTH_API_URL
ARG NEXT_PUBLIC_SIGNOUT_REDIRECT_URL

ENV NODE_ENV=production
ENV NEXTAUTH_SECRET=$NEXTAUTH_SECRET
ENV REACT_APP_API_URL=$REACT_APP_API_URL
ENV NEXTAUTH_URL=$NEXTAUTH_URL
ENV NEXTAUTH_API_URL=$NEXTAUTH_API_URL
ENV NEXT_PUBLIC_SIGNOUT_REDIRECT_URL=$NEXT_PUBLIC_SIGNOUT_REDIRECT_URL

#RUN npx nx run-many --target=build --all
RUN npx nx build web
Expand Down
1 change: 1 addition & 0 deletions apps/api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ KEYCLOAK_TOKEN_ENDPOINT=https://cbioportal.pmgenomics.ca/newauth/realms/UHN/prot
MM_API_URL=<matchminer-api-url>/api
PRISMA_FIELD_ENCRYPTION_KEY=<prisma_field_encryption_key>
CTIMS_ENV=production | development
CTIMS_API_VERSION=2.1
2 changes: 2 additions & 0 deletions apps/api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ ARG PRISMA_FIELD_ENCRYPTION_KEY
ARG MM_API_URL
ARG CTIMS_ENV
ARG MM_API_TOKEN
ARG CTIMS_API_VERSION

ENV KEYCLOAK_REALM=$KEYCLOAK_REALM
ENV KEYCLOAK_URL=$KEYCLOAK_URL
Expand All @@ -49,6 +50,7 @@ ENV PRISMA_FIELD_ENCRYPTION_KEY=$PRISMA_FIELD_ENCRYPTION_KEY
ENV MM_API_URL=$MM_API_URL
ENV CTIMS_ENV=$CTIMS_ENV
ENV MM_API_TOKEN=$MM_API_TOKEN
ENV CTIMS_API_VERSION=$CTIMS_API_VERSION

RUN yarn generate:build
#RUN yarn start:prod
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { UserModule } from './user/user.module';
import {AuthModule} from "./auth/auth.module";
import { EventModule } from "./event/event.module";
import { MatchminerModule } from './matchminer/matchminer.module';
import { InfoModule } from './info/info.module';

@Global()
@Module({
Expand All @@ -21,6 +22,7 @@ import { MatchminerModule } from './matchminer/matchminer.module';
UserModule,
MatchminerModule,
EventModule,
InfoModule,
],
controllers: [AppController],
providers: [AppService, PrismaService],
Expand Down
20 changes: 20 additions & 0 deletions apps/api/src/app/info/info.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Controller, Get } from '@nestjs/common';
import { InfoService } from './info.service';
import { ApiOperation, ApiTags } from '@nestjs/swagger';


@Controller('info')
@ApiTags('info')
export class InfoController {

constructor(private infoService: InfoService) {

}

@Get()
@ApiOperation({summary: "Get app info"})
getAppInfo() {
return this.infoService.getAppInfo();
}

}
9 changes: 9 additions & 0 deletions apps/api/src/app/info/info.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { InfoService } from './info.service';
import { InfoController } from './info.controller';

@Module({
controllers: [InfoController],
providers: [InfoService],
})
export class InfoModule {}
16 changes: 16 additions & 0 deletions apps/api/src/app/info/info.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Injectable, Logger } from '@nestjs/common';

@Injectable()
export class InfoService {

private CTIMS_API_VERSION = process.env.CTIMS_API_VERSION;

private readonly logger = new Logger(InfoService.name, { timestamp: true });

getAppInfo() {
let info = {
'version': this.CTIMS_API_VERSION,
}
return info;
}
}
5 changes: 3 additions & 2 deletions apps/api/src/app/trial/trial.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ export class TrialService implements OnModuleInit {
}
}
},
protocol_no: (typeof protocol_no === 'string') ? protocol_no : protocol_no.toString()
protocol_no: protocol_no === undefined ? '' :
(typeof protocol_no !== 'string' ? protocol_no.toString() : protocol_no)
}
});

Expand Down Expand Up @@ -164,7 +165,7 @@ export class TrialService implements OnModuleInit {
}
}
},
protocol_no: (typeof protocol_no === 'string') ? protocol_no : protocol_no.toString()
protocol_no: (typeof protocol_no === 'string') ? protocol_no : protocol_no?.toString()
},
});

Expand Down
1 change: 1 addition & 0 deletions apps/web/.env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ NEXTAUTH_SECRET=dAbxJF2DRzqwGYn+BWKdj8o9ieMri4FWsmIRn77r2F8=
REACT_APP_API_URL=http://localhost:3333/api
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_API_URL=http://localhost:3333/api
NEXT_PUBLIC_SIGNOUT_REDIRECT_URL=http://localhost:3000
19 changes: 19 additions & 0 deletions apps/web/components/Footer.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.versionContainer {
display: flex;
flex-direction: column;
align-self: stretch;
position: relative;
left: 0;
right: 0;
bottom: 0;

color: var(--text-subdued, rgba(0, 0, 0, 0.60));
text-align: center;
font-family: 'Inter', sans-serif;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px; /* 133.333% */
margin-top: 20px;
margin-bottom: 20px;
}
22 changes: 22 additions & 0 deletions apps/web/components/FooterComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useEffect } from 'react';
import useGetApiInfo from '../hooks/useGetApiInfo';
import styles from "./Footer.module.scss"
const FooterComponent = () => {

const {
error: getApiInfoError,
response: getApiInfoResponse,
loading: getApiInfoLoading,
operation: getApiInfoOperation
} = useGetApiInfo();

useEffect(() => {
getApiInfoOperation();
}, [])

return (
<div className={styles.versionContainer}>CTIMS version {getApiInfoResponse}</div>
);
};

export default FooterComponent;
63 changes: 61 additions & 2 deletions apps/web/components/IdleComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import useIdle, { IdleState } from "../hooks/useIdle";
import { Dialog } from 'primereact/dialog';
import {useRouter} from "next/router";
import useRefreshToken from "../hooks/useRefreshToken";
import useSaveTrial from "../hooks/useSaveTrial";
import {RootState, store} from "../store/store";

const IdleComponent = () => {
const { state: idleState, remaining, count } = useIdle(); // Get the idle state, remaining time, and count from the useIdle hook
Expand All @@ -11,6 +13,13 @@ const IdleComponent = () => {

const { error, response, loading, refreshTokenOperation } = useRefreshToken(); // Get the error, response, loading, and refreshTokenOperation from the useRefreshToken hook

const {
response: saveTrialResponse,
error: saveTrialError,
loading: saveTrialLoading,
saveTrialOperation
} = useSaveTrial();

const router = useRouter(); // Get the router object from the useRouter hook

const IDLE_TIMEOUT = 60; // Set the idle timeout to 60 seconds
Expand Down Expand Up @@ -43,8 +52,14 @@ const IdleComponent = () => {
if (interval) {
clearInterval(interval); // Clear the interval
}
localStorage.removeItem('ctims-accessToken') // Remove the access token from local storage
router.push('/'); // Redirect to the home page

// Auto save before timeout and logout
const currentState = store.getState();
const {trialModel, ctmlJson} = saveToServer(currentState)
saveTrialOperation(trialModel, ctmlJson).then(() => {
localStorage.removeItem('ctims-accessToken') // Remove the access token from local storage
router.push('/'); // Redirect to the home page
});
}

return () => {
Expand All @@ -55,6 +70,50 @@ const IdleComponent = () => {
};
}, [showDialog, remainingTime]); // Run the effect whenever the dialog visibility or remaining time changes

const saveToServer = (state: RootState) => {
const ctmlModel = state.finalModelAndErrors.ctmlModel;
if (!ctmlModel.trialInformation.trial_id) {
// @ts-ignore
toast.current.show({
severity:
'error',
summary: 'Error Saving',
detail: 'Trial ID is required',
});
return;
}

const getCtmlJsonOnly = () => {
let ctmlModelCopy;
const age_group = ctmlModel.age_group;
const trialInformation = ctmlModel.trialInformation;
ctmlModelCopy = {...ctmlModel, ...trialInformation, ...age_group};
delete ctmlModelCopy.age_group;
delete ctmlModelCopy.trialInformation;
delete ctmlModelCopy.ctml_status;
delete ctmlModelCopy.nickname;
return ctmlModelCopy;
}

const getTrialModelOnly = () => {
return {
nct_id: ctmlModel.trialInformation.trial_id,
nickname: ctmlModel.trialInformation.nickname,
principal_investigator: ctmlModel.trialInformation.principal_investigator,
status: ctmlModel.trialInformation.ctml_status,
protocol_no: ctmlModel.trialInformation.protocol_no,
}
}



const trialModel = getTrialModelOnly();
const ctmlJson = getCtmlJsonOnly();

return { trialModel, ctmlJson };

}

return (
<div>
<Dialog data-testid="dialog" header="Idle Warning" visible={showDialog} onHide={onHide} closable={false}>
Expand Down
23 changes: 23 additions & 0 deletions apps/web/components/Login.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,29 @@

}
}

.version {
display: flex;
flex-direction: column;
align-items: center;
padding: 0px;

position: absolute;
width: 1280px;
height: 18px;
left: 50%;
top: 95%;
transform: translate(-50%, -50%);


color: rgba(255, 255, 255, 0.65);
text-align: center;
font-family: 'Inter', sans-serif;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px; /* 133.333% */
}
}


13 changes: 11 additions & 2 deletions apps/web/components/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styles from './Login.module.scss';
import { InputText } from "primereact/inputtext";
import React, { useState, useRef } from "react";
import React, { useState, useRef, useEffect } from "react";
import {NextRouter, useRouter} from "next/router";
import useHasMounted from "../hooks/useHasMounted";
import Layout from "./Layout";
Expand All @@ -12,6 +12,7 @@ import {Password} from "primereact/password";
import { Toast } from "primereact/toast";
import { Dialog } from "primereact/dialog";
import strings from "../data/strings.json";
import useGetApiInfo from '../hooks/useGetApiInfo';

const Login = () => {
const hasMounted = useHasMounted();
Expand All @@ -28,6 +29,13 @@ const Login = () => {

const [dialogVisible, setDialogVisible] = useState(false);

const { error, response, loading, operation} = useGetApiInfo();

useEffect(() => {
operation();
}, [])


const componentStrings = strings.components.Login;

const showDialog = () => {
Expand Down Expand Up @@ -139,9 +147,10 @@ const Login = () => {
<Button label="Sign In" onClick={(e) => handleLogin(e)} />
<div className={styles.forgotPassword} onClick={handleForgotPassword}>Forgot Password</div>
</form>

</div>

</div>
<div className={styles.version}>CTIMS version {response}</div>
</div>
</Layout>
);
Expand Down
4 changes: 3 additions & 1 deletion apps/web/components/editor/ExportCtmlDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ const ExportCtmlDialog = (props: ExportCtmlDialogProps) => {
let errorObjList: RJSFValidationError[] = errorSchema.errors;
const filteredErrorObjList = errorObjList.filter((errorObj: RJSFValidationError) => {
return errorObj.message !== 'must be object';
})
}).filter((err_two: RJSFValidationError) => {
return err_two.property !== '.trialInformation.phase';
});
if (!isObjectEmpty(errorSchema)) {
const viewModelErrors = extractErrors(filteredErrorObjList);
setErrors(viewModelErrors)
Expand Down
1 change: 1 addition & 0 deletions apps/web/components/trials/Results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ const Results = () => {
{label: "Left Partner Gene", key: "left_partner_gene"},
{label: "Right Partner Gene", key: "right_partner_gene"},
{label: "CNV Call", key: "cnv_call"},
{label: "MS Status", key: "ms_status"},
];
// csv download link ref
const csvLink = useRef()
Expand Down
8 changes: 7 additions & 1 deletion apps/web/components/trials/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ import {Menu} from "primereact/menu";
import {useRef} from "react";
import styles from './TopBar.module.scss';
import {signOut, useSession} from "next-auth/react";
import * as process from "process";
import {useRouter} from "next/router";

const TopBar = () => {

const menu = useRef(null);
const router = useRouter();

const {data} = useSession();

Expand All @@ -14,9 +17,12 @@ const TopBar = () => {
label: 'Sign Out',
icon: 'pi pi-sign-out',
command: () => {
signOut({callbackUrl: '/', redirect: true}).then(() => {
// signOut({callbackUrl: '/', redirect: true}).then(() => {
signOut({redirect: false}).then(() => {
localStorage.removeItem('ctims-accessToken');
router.push(process.env.NEXT_PUBLIC_SIGNOUT_REDIRECT_URL)
});

}
}
]
Expand Down
Loading

0 comments on commit 785ed45

Please sign in to comment.