Skip to content

Commit

Permalink
Merge pull request #158 from i-VRESSE/todos
Browse files Browse the repository at this point in the history
Todos
  • Loading branch information
sverhoeven authored Oct 8, 2024
2 parents 32307b3 + aa575a0 commit 7b72707
Show file tree
Hide file tree
Showing 25 changed files with 169 additions and 89 deletions.
1 change: 0 additions & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ on:
tags:
- v*
pull_request:
# TODO have way to rebuild bartender image when it and its deps have updated

jobs:
bartender:
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ node_modules

/app/styles/tailwind.css
/coverage
/docs/demo
14 changes: 14 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,17 @@ Then run the app in production mode:
export $(cat .env |grep -v '#' |xargs)
npm start
```

## Creating a release

If you made changes to the webapp and want to create a new release, follow these steps:

1. Update the version in `package.json`
2. Goto the [releases page](https://github.com/i-VRESSE/haddock3-webapp/releases)
3. Copy the first line in the description of the latest release to you clipboard.
4. Click on the `Draft a new release` button
5. Paste the line from the clipboard into the `Tag version` field
6. Set tag and title to same version used in `package.json` with a `v` prefix.
7. Press `Generate release notes` button
8. Adjust description if needed
9. Press `Publish release` button
2 changes: 0 additions & 2 deletions app/auth.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ if (
userAgent: "Haddock3WebApp",
},
async ({ profile }) => {
// TODO store users display name in database for more personal greeting
const primaryEmail = profile.emails[0].value;
const photo = profile.photos[0].value ?? undefined;
const userId = await oauthregister(primaryEmail, photo);
Expand Down Expand Up @@ -181,7 +180,6 @@ if (
});
const profile = await profileResponse.json();
const emails = await this.userEmails(profile.sub);
// TODO store Orcid id into database
return {
...profile,
emails,
Expand Down
1 change: 0 additions & 1 deletion app/browse/OutputReport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ export const OutputReport = ({
</div>
<details>
<summary className="cursor-pointer">Files</summary>
{/* TODO should we hide io.json and params.cfg? */}
<ListFiles files={module.output} jobid={jobid} />
</details>
</li>
Expand Down
1 change: 0 additions & 1 deletion app/builder/Form.css
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ Btn classes are copied from app/components/ui/button.tsx

.workflow-builder-app .array-item-add,
.workflow-builder-app .object-property-expand {
/* TODO full width + center plus sign */
@apply m-4 !w-auto;
}

Expand Down
36 changes: 35 additions & 1 deletion app/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
import { useInPortalMode } from "~/portal";

function PortalFooter() {
// Copied from frontend/src/Components/Footer.tsx
// TODO add PoweredBy component on certain page
const currentYear = new Date().getFullYear();
const firstYear = 2008;
return (
<footer className="bottom-0 left-0 right-0 bg-slate-200 text-white p-2">
<div className="text-center text-xs flex-col space-y-1 container mx-auto flex justify-center items-center">
<div>
<p className=" text-gray-400">
{firstYear}-{currentYear} &copy; Computational Structural Biology
group (Utrecht University). All rights reserved.
</p>
</div>
<div className="flex items-center">
<a href="/conditions" className="text-blue-500 hover:underline">
Terms and Conditions
</a>
<div className="h-4 bg-gray-600 w-px mx-4"></div>
<a href="/privacy" className="text-blue-500 hover:underline">
Privacy
</a>
</div>
</div>
</footer>
);
}

export function Footer() {
// TODO in portal mode mimic the footer from the portal
const inPortalMode = useInPortalMode();
if (inPortalMode) {
return <PortalFooter />;
}

return (
<footer className="bg-primary p-1 text-center text-primary-foreground">
<p className="text-sm">
Expand Down
1 change: 0 additions & 1 deletion app/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const LoggedInButton = () => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
{/* TODO button is not vertically centered */}
<Button
variant="outline"
size="icon"
Expand Down
73 changes: 69 additions & 4 deletions app/routes/jobs.$id._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,30 @@ import {
type LoaderFunctionArgs,
ActionFunctionArgs,
} from "@remix-run/node";
import { useLoaderData, useRevalidator } from "@remix-run/react";
import {
Link,
useFetcher,
useLoaderData,
useRevalidator,
useSubmit,
} from "@remix-run/react";

import {
deleteJob,
getJobById,
jobIdFromParams,
HADDOCK3WEBAPP_REFRESH_RATE_MS,
listInputFiles,
} from "~/models/job.server";
import { getUser } from "~/auth.server";
import { JobStatus } from "~/components/JobStatus";
import { getBartenderTokenByUser } from "~/bartender-client/token.server";
import DotsLoader from "~/components/ui/DotsLoader";
import { ListFiles } from "~/browse/ListFiles";
import { WORKFLOW_CONFIG_FILENAME } from "~/bartender-client/constants";
import { prefix } from "~/prefix";
import { DirectoryItem } from "~/bartender-client/types";
import { Button } from "~/components/ui/button";

export const loader = async ({ params, request }: LoaderFunctionArgs) => {
const jobId = jobIdFromParams(params);
Expand All @@ -30,12 +42,25 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
return redirect("browse");
}
}
let inputFiles: DirectoryItem = {
path: "",
name: "",
is_file: false,
is_dir: true,
children: [],
};
try {
inputFiles = await listInputFiles(jobId, token);
} catch (error) {
// Do nothing, users can look in log files for more information
}

return json({
job,
// provide refresh rate from env or default of 5 sec.
HADDOCK3WEBAPP_REFRESH_RATE_MS,
lastCheckedOn: new Date().toISOString(),
inputFiles,
});
};

Expand All @@ -47,11 +72,15 @@ export const action = async ({ params, request }: ActionFunctionArgs) => {
const user = await getUser(request);
const token = await getBartenderTokenByUser(user);
await deleteJob(jobId, token);
if (request.headers.get("referer") === request.url) {
return redirect(prefix);
}
return null;
};

export default function JobPage() {
const { job, HADDOCK3WEBAPP_REFRESH_RATE_MS, lastCheckedOn } =
const submit = useSubmit();
const { job, HADDOCK3WEBAPP_REFRESH_RATE_MS, lastCheckedOn, inputFiles } =
useLoaderData<typeof loader>();
const { revalidate } = useRevalidator();

Expand Down Expand Up @@ -80,10 +109,23 @@ export default function JobPage() {
};
}, [HADDOCK3WEBAPP_REFRESH_RATE_MS, revalidate, job.state]);

const hasWorkflow = inputFiles.children?.some(
(file) => file.is_file && file.name === WORKFLOW_CONFIG_FILENAME,
);

return (
<main className="flex gap-16">
<div>
<JobStatus job={job} lastStateCheckOn={lastCheckedOn} />
{(job.state === "queued" || job.state === "running") && (
<Button
variant="outline"
title="Cancel job"
onClick={() => deleteJobConfirm(submit)}
>
Cancel
</Button>
)}
{/* show dots loader indicating we monitor state change */}
{job.state !== "error" && job.state !== "ok" ? (
<DotsLoader
Expand All @@ -93,8 +135,31 @@ export default function JobPage() {
/>
) : null}
</div>
{/* TODO allow to read input files when job is not completed */}
{/* TODO allow job to be cancelled, need bartender support first */}
{inputFiles.children && inputFiles.children.length > 0 && (
<div>
<h2 className="text-2xl">Input</h2>
<ListFiles files={inputFiles!} jobid={job.id} />
<p>
<a href={`${prefix}jobs/${job.id}/input.zip`}>
&#128230; Download archive
</a>
</p>
{hasWorkflow && job.state === "error" && (
<p>
<Link to={`${prefix}jobs/${job.id}/edit`}>&#128393; Edit</Link>
</p>
)}
</div>
)}
</main>
);
}

type Submit = ReturnType<typeof useFetcher>["submit"];

function deleteJobConfirm(submit: Submit): void {
if (window.confirm("Are you sure you want to cancel job?") === false) {
return;
}
submit({}, { method: "delete" });
}
2 changes: 0 additions & 2 deletions app/routes/jobs.$id.report.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import { CaprievalReport } from "~/caprieval/CaprievalReport.client";
import { JobName } from "~/components/JobName";
import { buttonVariants } from "~/components/ui/button";
import { prefix } from "~/prefix";
// TODO rescore is not used here, so imports should not be from this module
// move to a separate module called ~/model/modules and ~/models/caprieval

export const loader = async ({ params, request }: LoaderFunctionArgs) => {
const jobid = jobIdFromParams(params);
Expand Down
9 changes: 0 additions & 9 deletions app/routes/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,6 @@ export default function Page() {
setTheme(t === "" ? null : (t as Theme));
}}
>
{/*
TODO system is not yet supported by remix-themes,
but issue by author was created on 2 feb 2024.
<div className="flex items-center space-x-2">
<RadioGroupItem value="" id="system" />
<Label htmlFor="system">System</Label>
</div>
*/}
<div className="flex items-center space-x-2">
<RadioGroupItem value={Theme.LIGHT} id={Theme.LIGHT} />
<Label htmlFor={Theme.LIGHT}>Light</Label>
Expand Down
1 change: 0 additions & 1 deletion app/routes/scenarios.protein-dna.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
export const action = uploadaction;

const Schema = object({
// TODO check content of pdb files are valid
protein: instance(File, "Protein structure as PDB file"),
dna: instance(File, "DNA structure as PDB file"),
nrSelectedProteinResidues: pipe(
Expand Down
4 changes: 0 additions & 4 deletions app/routes/scenarios.protein-glycan.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,6 @@ export default function ProteinProteinScenario() {
targetChain="A"
preprocessPipeline="delhetatmkeepcoord"
/>
{/* TODO treat glycan as glycan,
disable surface calculation (example fails calc),
only active as restraints flavour kind,
render as ball+stick */}
{/* TODO molstar has carbohydrate representation, check if there is equiv in ngl */}
<GlycanMoleculeSubForm
name="glycan"
Expand Down
1 change: 0 additions & 1 deletion app/routes/scenarios.protein-protein.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
export const action = uploadaction;

const Schema = object({
// TODO check content of pdb files are valid
protein1: instance(File, "First protein structure as PDB file"),
protein2: instance(File, "Second protein structure as PDB file"),
nrSelectedProtein1Residues: pipe(
Expand Down
7 changes: 5 additions & 2 deletions app/scenarios/BindingMoleculeSubForm.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { ResidueHeaderItem } from "@i-vresse/haddock3-ui/toggles/ResidueHeader";

import { ActPassSelection } from "./ActPassSelection";
import { BIG_MOLECULE } from "./constants";
import { toggleResidue } from "./toggleResidue";
import { PreprocessPipeline } from "./restraints";
import { Label } from "~/components/ui/label";
import { Spinner } from "~/components/ui/spinner";
Expand All @@ -29,6 +28,7 @@ import {
ResidueCheckbox,
ResidueNeighbourSelection,
ResidueSelection,
toggleResidue,
useResidueChangeHandler,
} from "@i-vresse/haddock3-ui/toggles";

Expand Down Expand Up @@ -207,7 +207,10 @@ function BindingResiduesSubForm({
) {
return;
}
const newSelection = toggleResidue(resno, "act", actpass);
const newSelection = toggleResidue(resno, "act", {
act: actpass.active,
pass: actpass.passive,
});
handle2DResidueChange(newSelection);
}

Expand Down
8 changes: 5 additions & 3 deletions app/scenarios/GlycanMoleculeSubForm.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Residue,
ResidueCheckbox,
ResidueSelection,
toggleResidue,
useResidueChangeHandler,
} from "@i-vresse/haddock3-ui/toggles";
import { useTheme } from "remix-themes";
Expand All @@ -20,7 +21,6 @@ import {
} from "./AtomStructureSubForm.client";
import { PreprocessPipeline } from "./restraints";
import { LabeledRadioGroup } from "./LabeledRadioGroup";
import { toggleResidue } from "./toggleResidue";
import { ImportResidues, PickIn3D } from "./ResiduesSelect";
import { useSafeFile } from "./useSafeFile";
import { Spinner } from "~/components/ui/spinner";
Expand Down Expand Up @@ -86,7 +86,6 @@ export function GlycanResiduesSelect({
key={r.resno}
resno={r.resno}
resname={r.resname}
// TODO render resname as seq is always uninformative 'X'
seq={r.seq}
highlight={highlight === r.resno}
activeChecked={selected.act.includes(r.resno)}
Expand Down Expand Up @@ -179,7 +178,10 @@ function ResiduesSubForm({
if (molecule.targetChain !== chain) {
return;
}
const newSelection = toggleResidue(resno, picker3D, actpass);
const newSelection = toggleResidue(resno, picker3D, {
act: actpass.active,
pass: actpass.passive,
});
handle2DResidueChange(newSelection);
}

Expand Down
12 changes: 9 additions & 3 deletions app/scenarios/MacroMoleculeSubForm.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ import {
Molecule,
ResidueSubFormProps,
} from "./AtomStructureSubForm.client";
import { toggleResidue } from "./toggleResidue";
import { BIG_MOLECULE } from "./constants";
import { useSurfaceCutoff } from "./useSurfaceCutoff";
import { computeNeighbours, useNeighbourRadius } from "./useNeighbourRadius";
import { useSafeFile } from "./useSafeFile";
import { useTheme } from "remix-themes";
import { Viewer } from "@i-vresse/haddock3-ui";
import { ActPass, ResidueSelection } from "@i-vresse/haddock3-ui/toggles";
import {
ActPass,
ResidueSelection,
toggleResidue,
} from "@i-vresse/haddock3-ui/toggles";

export function ResiduesSubForm({
molecule,
Expand Down Expand Up @@ -157,7 +160,10 @@ export function ResiduesSubForm({
) {
return;
}
const newSelection = toggleResidue(resno, picker3D, actpass);
const newSelection = toggleResidue(resno, picker3D, {
act: actpass.active,
pass: actpass.passive,
});
handle2DResidueChange(newSelection);
}

Expand Down
Loading

0 comments on commit 7b72707

Please sign in to comment.