Skip to content
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

Releasing Staging Branch #23

Merged
merged 7 commits into from
May 31, 2024
Merged
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
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ REACT_APP_API_EXAMPLES=$REACT_APP_API_URL/text/examples
REACT_APP_API_PARSE=$REACT_APP_API_URL/text/parse
REACT_APP_API_MATCH=$REACT_APP_API_URL/text/match
REACT_APP_API_VERSION=$REACT_APP_API_URL/info/version
REACT_APP_API_MODELS=$REACT_APP_API_URL/info/list-models
REACT_APP_ABSOLUTE_URL_PREFIX=https://harmonydata.github.io
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ REACT_APP_API_EXAMPLES=$REACT_APP_API_URL/text/examples
REACT_APP_API_PARSE=$REACT_APP_API_URL/text/parse
REACT_APP_API_MATCH=$REACT_APP_API_URL/text/match
REACT_APP_API_VERSION=$REACT_APP_API_URL/info/version
REACT_APP_API_MODELS=$REACT_APP_API_URL/info/list-models
REACT_APP_ABSOLUTE_URL_PREFIX=https://harmonydata.github.io
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ You can access Harmony in your browser at `http://localhost:3000/app#/`.

## How to run this front end and connect to localhost API

[Watch a video tutorial on how to run the Harmony front end locally and connect to Harmony API on localhost](https://youtu.be/1xp3Uh6dptg?si=g2CkXGEJCtevgdzY)

Run the [Harmony API](https://github.com/harmonydata/harmonyapi) app in Python.

Open `.env` and change `REACT_APP_API_URL` to `http://localhost:8000` and change `REACT_APP_ABSOLUTE_URL_PREFIX` to `http://localhost:8000/app` (so that the front end knows that it's running on localhost and that it should connect to a localhost API)
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
"mui-nested-menu": "^3.2.1",
"nth-check": ">=2.1.1",
"pdfjs-dist": "^4.0.269",
"react": "^18.2.0",
"react": "^18.3.1",
"react-card-flip": "^1.2.0",
"react-circular-progressbar": "^2.1.0",
"react-cookie-consent": "^8.0.1",
"react-dom": "^18.2.0",
"react-dom": "^18.3.1",
"react-drag-drop-files": "^2.3.10",
"react-ga4": "^2.1.0",
"react-pdf": "^7.6.0",
Expand Down
98 changes: 87 additions & 11 deletions src/components/AppBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import {
Menu,
Container,
Divider,
FormControl,
InputLabel,
OutlinedInput,
ListItemText,
} from "@mui/material";
import { Logout, JoinInner } from "@mui/icons-material/";
import { useAuth } from "../contexts/AuthContext";
Expand All @@ -28,6 +32,7 @@ const SettingsIcons = {
function HarmonyAppBar() {
const [anchorUser, setAnchorUser] = React.useState(null);
const [apiVersion, setApiVersion] = React.useState(null);
const [allModels, setAllModels] = React.useState();
const [error, setError] = React.useState(null);
const {
currentUser,
Expand All @@ -36,7 +41,7 @@ function HarmonyAppBar() {
signInWithGitHub,
signInWithTwitter,
} = useAuth();
const { getVersion } = useData();
const { getVersion, getModels, currentModel, setCurrentModel } = useData();

React.useEffect(() => {
getVersion()
Expand All @@ -46,6 +51,24 @@ function HarmonyAppBar() {
.catch((e) => setError("ERROR: API unreachable"));
}, [getVersion]);

React.useEffect(() => {
getModels()
.then((models) => {
setAllModels(models);
})
.catch((e) => setError("ERROR: API unreachable"));
}, [getModels]);

const handleModelSelect = (event) => {
const model = event.target.value;
if (
model.framework !== currentModel.framework ||
model.model !== currentModel.model
) {
setCurrentModel(model);
}
};

const handleOpenUserMenu = (event) => {
setAnchorUser(event.currentTarget);
};
Expand Down Expand Up @@ -80,15 +103,27 @@ function HarmonyAppBar() {
>
<Container sx={{ maxWidth: "100%!important" }}>
<Toolbar disableGutters>
<Box sx={{ flexGrow: 1, textAlign: "right", paddingRight: 2 }}>
{apiVersion && (
<Typography>Harmony API version: {apiVersion}</Typography>
)}
{error && (
<Typography sx={{ color: "red", fontWeight: 900 }}>
{error}
</Typography>
)}
<Box
sx={{
flexGrow: 1,

textAlign: "right",
paddingRight: 2,
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyItems: "flex-end",
}}
>
{error && (
<Typography sx={{ color: "red", fontWeight: 900 }}>
{error}
</Typography>
)}
</Box>
</Box>

<Box sx={{ flexGrow: 0 }}>
Expand All @@ -105,7 +140,7 @@ function HarmonyAppBar() {
</Avatar>
</Tooltip>
<Menu
sx={{ mt: "45px" }}
sx={{ mt: "45px", maxWidth: "50%" }}
id="menu-appbar"
anchorEl={anchorUser}
anchorOrigin={{
Expand Down Expand Up @@ -134,6 +169,41 @@ function HarmonyAppBar() {
<MenuItem value={"PT"}>Portuguese</MenuItem>
</Select>
</MenuItem>
<MenuItem key="model">
<FormControl sx={{ margin: "auto" }}>
<InputLabel id="models">Model</InputLabel>
<Select
size="small"
labelId="models"
id="modelcombo"
value={currentModel}
onChange={handleModelSelect}
input={
<OutlinedInput
sx={{ overflow: "hidden" }}
label="Model"
/>
}
renderValue={(selected) =>
selected.framework + " (" + selected.model + ")"
}
>
{allModels &&
allModels.map(
(model) =>
model.available && (
<MenuItem key={model.model} value={model}>
<ListItemText
primary={
model.framework + " (" + model.model + ")"
}
/>
</MenuItem>
)
)}
</Select>
</FormControl>
</MenuItem>
<Divider />

{settings.map((setting) => (
Expand Down Expand Up @@ -189,6 +259,12 @@ function HarmonyAppBar() {
</Typography>
</MenuItem>
)}
<Divider />
{apiVersion && (
<Typography sx={{ mx: 1 }}>
Harmony API version: {apiVersion}
</Typography>
)}
</Menu>
</Box>
</Toolbar>
Expand Down
19 changes: 19 additions & 0 deletions src/components/GoogleDriveImport.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";
import { Box, Button } from "@mui/material";

function GoogleDriveImport({ filesReceiver, sx }) {
return (
<Box sx={sx}>
<Button variant="contained" size="large" sx={{ mx: "auto" }}>
<img
style={{ height: "2rem", marginRight: 10 }}
src={require("../img/google-drive.png")}
alt="Google Drive"
/>
Import Forms, Sheets or Documents from Google Drive
</Button>
</Box>
);
}

export default GoogleDriveImport;
33 changes: 15 additions & 18 deletions src/components/ThemeToggle.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,36 @@
import React from 'react';
import { IconButton, Box } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import Brightness4Icon from '@mui/icons-material/Brightness4';
import Brightness7Icon from '@mui/icons-material/Brightness7';
import { ColorModeContext } from "../contexts/ColorModeContext"
import React from "react";
import { IconButton, Box } from "@mui/material";
import { useTheme } from "@mui/material/styles";
import Brightness4Icon from "@mui/icons-material/Brightness4";
import Brightness7Icon from "@mui/icons-material/Brightness7";
import { ColorModeContext } from "../contexts/ColorModeContext";

export default function ThemeToggle() {
const theme = useTheme();
const colorMode = React.useContext(ColorModeContext);

return (
<Box
onClick={colorMode.toggleColorMode}
sx={{
display: 'flex',
width: '100%',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'background.default',
display: "flex",
width: "100%",
alignItems: "center",
justifyContent: "center",
bgcolor: "background.default",
color: theme.palette.text.primary,
borderRadius: 1,
p: 0,
}}
>
{theme.palette.mode} mode
<IconButton
sx={{ ml: 1 }}
onClick={colorMode.toggleColorMode}
color="inherit"
>
{theme.palette.mode === 'dark' ? (
<IconButton sx={{ ml: 1 }} color="inherit">
{theme.palette.mode === "dark" ? (
<Brightness7Icon />
) : (
<Brightness4Icon />
)}
</IconButton>
</Box>
);
}
}
54 changes: 44 additions & 10 deletions src/components/Upload.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useRef, memo, useMemo, useCallback } from "react";
import DragDrop from "./DragDrop";
import GoogleDriveImport from "./GoogleDriveImport";
import { useData } from "../contexts/DataContext";
import {
Box,
Expand Down Expand Up @@ -29,6 +30,7 @@ import { simplifyApi } from "../utilities/simplifyApi";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import pdfTableExtractor from "../utilities/pdf-table-extractor";
import { useAuth } from "../contexts/AuthContext";

export default function Upload({
appFileInfos,
Expand All @@ -37,6 +39,7 @@ export default function Upload({
existingInstruments,
ReactGA,
}) {
const { currentUser } = useAuth();
const [loading, setLoading] = useState(false);
const [parseError, setParseError] = useState(false);
const [matchError, setMatchError] = useState(false);
Expand All @@ -56,11 +59,22 @@ export default function Upload({
return dirty.current ? localFileInfos.current || [] : appFileInfos || [];
}, [appFileInfos]);

const setFileInfos = useCallback((fi) => {
console.log("setting local FI " + JSON.stringify(fi));
dirty.current = dirty.current + 1;
localFileInfos.current = fi;
}, []);
const setFileInfos = useCallback(
(fi, forceExpanded) => {
console.log("setting local FI " + JSON.stringify(fi));
dirty.current = dirty.current + 1;
localFileInfos.current = fi;
if (forceExpanded) {
setExpanded(forceExpanded);
} else if (
fi.length &&
!(expanded && fi.map((i) => i.instrument_id).includes(expanded))
) {
setExpanded(fi[0].instrument_id);
}
},
[expanded, setExpanded]
);

const syncFileInfos = useCallback(() => {
console.log("syncing fileinfo");
Expand Down Expand Up @@ -222,18 +236,18 @@ export default function Upload({
const after = fileInfos.findIndex(
(f) => f.instrument_id === after_instrument_id
);
const instrument_id = "ManuallyCreated" + String(new Date().getTime());
const newFileInfos = fileInfos
.slice(0, after + 1)
.concat([
{
instrument_id: String(new Date().getTime()),
instrument_id: instrument_id,
instrument_name: "",
questions: [{ question_no: "", question_text: "" }],
},
])
.concat(fileInfos.slice(after + 1));
console.log(newFileInfos);
setFileInfos(newFileInfos);
setFileInfos(newFileInfos, instrument_id);
syncFileInfos();
};

Expand Down Expand Up @@ -375,7 +389,7 @@ export default function Upload({
key={instrument_id}
expanded={expanded === instrument_id}
onChange={(e, ex) => {
setExpanded(ex ? instrument_id : false);
if (ex) setExpanded(instrument_id);
syncFileInfos();
}}
>
Expand All @@ -399,6 +413,16 @@ export default function Upload({
}}
>
<TextField
error={
fi.questions.reduce((a, q) => (a = a + q.question_text), "")
.length === 0
}
helperText={
fi.questions.reduce((a, q) => (a = a + q.question_text), "")
.length === 0
? "You must add questions before this will be harmonised"
: false
}
variant="standard"
sx={{
pointerEvents: "auto",
Expand Down Expand Up @@ -500,7 +524,17 @@ export default function Upload({
setState={setMatchError}
/>

<DragDrop filesReceiver={filesReceiver} sx={{ margin: "2rem" }} />
<DragDrop filesReceiver={filesReceiver} sx={{ mt: "2rem" }} />
{currentUser &&
currentUser.providerData &&
currentUser.providerData
.map((p) => p.providerId)
.includes("google.com") && (
<GoogleDriveImport
filesReceiver={filesReceiver}
sx={{ display: "flex", width: "100%", mt: "1rem" }}
/>
)}
<Stack
direction={"row"}
spacing={1}
Expand Down
Loading
Loading