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

Overhaul of the cross section set edit form #996

Merged
merged 104 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
a2b40ea
Add table of references to edit form
daanboer Nov 30, 2023
353c3ef
Make references clickable
daanboer Dec 1, 2023
e6addf5
Add functionality to import a reference from its DOI
daanboer Dec 1, 2023
224f639
Move species tab component to separate module
daanboer Dec 1, 2023
c921977
Start developing the process tab
daanboer Dec 1, 2023
55e9ded
Use the new url for the set edit page
daanboer Feb 5, 2024
90f470b
Add `ProcessInfoItem` component
daanboer Feb 12, 2024
a9e4b65
Filter reference comments based on available references
daanboer Feb 13, 2024
77230d6
Add missing license headers
daanboer Feb 13, 2024
c058ec6
Add `@mantine/code-highlight` dependency
daanboer Feb 13, 2024
54b449b
Add rendered view of JSON document in set edit form
daanboer Feb 13, 2024
700a683
Use `mathrm` in `unspecified` species latex electronic descriptor
daanboer Feb 13, 2024
bbde5d9
Make species and process lists scrollable on overflow
daanboer Feb 13, 2024
5ff44c8
Override inner `display: table` style on `ScrollArea`
daanboer Feb 13, 2024
bdf9157
Unmount hidden tab panels
daanboer Feb 13, 2024
3336bd0
Start `ReactionBuilder` component
daanboer Feb 13, 2024
d84dfa0
Construct and use species and reference maps
daanboer Feb 13, 2024
e6f1dca
Make `LatexSelect` component growable
daanboer Feb 14, 2024
ad0651f
Add `SpeciesBuilder` component
daanboer Feb 14, 2024
e991fc1
Add `MultiSelect to edit type tags
daanboer Feb 14, 2024
6f12d77
Move `key` to parent component
daanboer Feb 14, 2024
e0815a1
Only export a single component
daanboer Feb 14, 2024
43a0297
Move the `ReactionBuilder` component to a separate module
daanboer Feb 14, 2024
f5ace4d
Present info objects in an accordion
daanboer Feb 14, 2024
ce0ebad
Do not render process item panels when invisible
daanboer Feb 14, 2024
a470b40
Render `ProcessItem` panels by default
daanboer Feb 14, 2024
08736b9
Use the `contained` variant of accordions for info objects
daanboer Feb 14, 2024
2f54a72
Add info object data section
daanboer Feb 14, 2024
e39efbd
Add missing license headers
daanboer Feb 14, 2024
8c89f2f
Increase scroll bar thumb z-index
daanboer Feb 14, 2024
fee16d2
Make button to add reaction entries smaller
daanboer Feb 16, 2024
059897c
Implement addition and removal of info objects
daanboer Feb 16, 2024
b7203c6
Fix filtering of references to deleted references
daanboer Feb 16, 2024
43c0284
Consistently use unique ids in `ProcessItem`
daanboer Feb 16, 2024
3e8a353
Use unique ids for `SpeciesBuilder` entries
daanboer Feb 16, 2024
c1ec2e0
Center bottom buttons on the species tab
daanboer Feb 16, 2024
b1237a3
Implement addition and removal of processes
daanboer Feb 16, 2024
43e6f79
Implement removal of species
daanboer Feb 16, 2024
62d83ca
Tie the submit button to an API call
daanboer Feb 19, 2024
197a81c
Make button labels more descriptive
daanboer Feb 19, 2024
e585c25
Add `Add process` button
daanboer Feb 19, 2024
ed2d3ab
Fix `author/scat-css` test
daanboer Feb 20, 2024
a26658c
Update newly added components to use the updated types
daanboer Mar 28, 2024
d928c33
Allow stripping all organizations in POST request
daanboer Apr 3, 2024
67314bb
Simplify species editing using `SpeciesInput`
daanboer Apr 4, 2024
011f783
Merge `byId` and `byIdJSON`
daanboer Apr 4, 2024
1e66fba
Remove unused `react-hook-form` code
daanboer Apr 4, 2024
eca56c2
Make `EditForm` accept `EditedLTPDocument`
daanboer Apr 4, 2024
4d0e1c0
Move the empty set constructor to a separate module
daanboer Apr 4, 2024
bd40050
Expect a commit message in `/api/author/scat-css` `POST`
daanboer Apr 4, 2024
509496d
Expect a commit message in `/api/author/scat-css/[id]`
daanboer Apr 4, 2024
e136063
Add commit message when deleting a draft set
daanboer Apr 4, 2024
20647da
Create a new set when no `_key` is provided
daanboer Apr 4, 2024
0c05175
Update the set `_key` on successful form submission
daanboer Apr 4, 2024
c317fda
Add the `/author/set/add` page
daanboer Apr 4, 2024
5512b40
Bind `Add` button to `/author/set/add`
daanboer Apr 4, 2024
60b7f78
Remove stray `only` call in `e2e` tests
daanboer Apr 4, 2024
125e950
Fix `isEqualProcess`
daanboer Apr 5, 2024
8f05e03
Add `getReferenceKeyByDoi` function
daanboer Apr 5, 2024
6465ede
Check whether a reference exists by using its `DOI`
daanboer Apr 5, 2024
60f50cd
Directly pass reference map to process tab
daanboer Apr 5, 2024
13b9e7b
Directly pass species map to process tab
daanboer Apr 5, 2024
cdfb6ca
Use database keys for existing references
daanboer Apr 5, 2024
24fcd02
Update the set retrieval query to include ref comments and published ref
daanboer Apr 5, 2024
b0d0dd2
Add a `Select` for the `publishedIn` ref
daanboer Apr 5, 2024
4539dda
Correctly treat DOI as optional
daanboer Apr 5, 2024
1e0cbf2
Fix `updateDraftSet`
daanboer Apr 8, 2024
db71e31
Fix remaining `@lxcat/database` tests
daanboer Apr 8, 2024
ed3ab95
Remove unused definitions
daanboer Apr 8, 2024
71dfde2
Fix type check using `@ts-nocheck` on soon-to-be deprecated code
daanboer Apr 8, 2024
7785e10
Add submit message on success
daanboer Apr 17, 2024
8262a34
Implement copy CSV from file and clipboard
daanboer May 2, 2024
517c397
Move `CommentSection` component to separate module
daanboer May 19, 2024
e598da7
Introduce the `ReferenceSection` component
daanboer May 19, 2024
3b2186a
Fix functionality of `Complete` checkbox in edit form
daanboer May 19, 2024
7be884a
Fix reference selection
daanboer May 19, 2024
7d0d3c0
Update table styling
daanboer May 20, 2024
21d8409
Correctly set `max-height` of `CodeHighlight`
daanboer May 21, 2024
f5a741a
Remove top border and radius in top-level accordions
daanboer May 21, 2024
7fbff7c
Fix `byOrgAndId` and `ByOwnerAndId` queries
daanboer May 21, 2024
8d76813
Fix `isEqualProcess`
daanboer May 21, 2024
0148fa7
Update `removeDraftUnchecked` to remove dangling entities
daanboer May 21, 2024
64eaea1
Update `removeDraftSetUnchecked` to correctly remove all dangling ent…
daanboer May 21, 2024
de81a83
Remove unused import
daanboer May 22, 2024
804b874
Fix `addraw` page for cross section sets
daanboer May 22, 2024
9943d59
Tighten testing of `removeDraftUnchecked`
daanboer May 29, 2024
0dc5453
Fix admin organizations panel
daanboer May 29, 2024
f56a039
Fix `Delete` button in set author panel
daanboer May 29, 2024
01b8aa6
Fix first batch of `author-css` e2e tests
daanboer May 29, 2024
5f39908
Correctly insert `InCompound` edges for compound states
daanboer May 30, 2024
155b0e9
Test the correct removal of compound constituents
daanboer May 30, 2024
0ad0a97
Update `removeDraftUnchecked` to treat compound states
daanboer May 30, 2024
b1daab9
Fix default values in edit form
daanboer May 30, 2024
7960f75
Fix `/author/set/add` end to end tests
daanboer May 30, 2024
cdf1630
Move `/author/scat-css` -> `author/set`
daanboer May 30, 2024
dac73df
Fix reuse compliance
daanboer May 30, 2024
e34864c
Create separate `CrossSectionParameters` definition
daanboer Jun 5, 2024
2980b0e
Add cross section parameter section to edit form
daanboer Jun 5, 2024
fb76b03
Remove unused legacy code
daanboer Jun 5, 2024
3c70447
Add input for energy loss value
daanboer Jun 5, 2024
d0469a4
Fix accordion styling
daanboer Jun 5, 2024
f7eb2b9
Add indicator that process references can be expanded
daanboer Jun 5, 2024
5c3155d
Make sure that icon and text are always on one line
daanboer Jun 5, 2024
8d1c78c
Remove unused `react-hook-form` packages
daanboer Jun 5, 2024
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
141 changes: 83 additions & 58 deletions app/e2e/author-css.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,26 @@ test("/api/author/scat-css", async ({ request }) => {
expect(data.items).toEqual([]);
});

test.describe.skip("/author/scat-css", () => {
test.describe("/author/set", () => {
test.beforeAll(async ({ browser }) => {
await uploadAndPublishDummySet(browser);
return db().dropNonUserCollections;
});

test.beforeEach(async ({ page }) => {
await page.goto("/author/scat-css");
await page.goto("/author/set");
await page.locator("button:text-is(\"Edit\")").click();
await page.locator("textarea[name=\"set\\.description\"]").fill(
await page.getByPlaceholder("Describe which changes have").fill(
"Edited description",
);
await page.locator("button:has-text(\"Submit\")").click();
await page.goto("/author/scat-css");
await page.getByRole("button", { name: "Submit" }).click();
await page.getByText("Saved set with id").waitFor({ state: "visible" });
await page.goto("/author/set");
});

// FIXME: Playwright is too fast in its actions, and the expect calls
// will receive incorrect data. We need to find a way to wait for all
// async calls (that e.g. reload the page data) to finish before
// continuing

test("A simple edit should result in a draft", async ({ page }) => {
await page.goto("/author/set");

const table = page.locator("table:has(thead th:text(\"Version\"))");

// Status = draft
Expand All @@ -68,6 +66,9 @@ test.describe.skip("/author/scat-css", () => {
.click();

const table = page.locator("table:has(thead th:text(\"Version\"))");
await page.locator("button:text-is(\"Delete\"):visible").waitFor({
state: "hidden",
});

// Status = published
expect(table.locator("td").nth(1)).toHaveText("published");
Expand All @@ -77,20 +78,20 @@ test.describe.skip("/author/scat-css", () => {
);
});

test.describe.skip("/author/scat-css/add", () => {
test.describe("/author/set/add", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/author/scat-css/add");
await page.goto("/author/set/add");
});
test.describe("give empty name field", () => {
test("after submit should show warning", async ({ page }) => {
// With form untouched

await page.locator("button:has-text(\"Submit\")").click();

const warning = page.locator(
"text=Name *must NOT have fewer than 1 characters",
const warning = page.getByText(
"String must contain at least 1 character(s)",
);
await expect(warning).toBeVisible();
await expect(warning).toHaveCount(3);
});
});

Expand All @@ -100,46 +101,59 @@ test.describe.skip("/author/scat-css/add", () => {
name,
);
await page.locator("button:has-text(\"Add\")").click();
await page.locator("li").getByText(name).waitFor({ state: "visible" });

await page.goto("/admin/users");
await page.waitForLoadState("domcontentloaded");
await page
.locator("[aria-label=\"Memberships of admin\\@ng\\.lxcat\\.net\"]")
.getByRole("row", { name: "admin [email protected]" }).locator("div")
.first()
.click();
await page.locator(`text=${name}`).click();
}

async function fillAddSetForm(page: Page) {
await page.goto("/author/scat-css/add");
await page.goto("/author/set/add");
// General
await page.locator("input[name=\"set\\.name\"]").fill("My name");
await page
.locator("select[name=\"set\\.contributor\"]")
.selectOption("MyOrg");
await page.getByLabel("Name *").fill("My name");
await page.getByLabel("Contributor").selectOption("MyOrg");
// States
await page.locator("button[role=\"tab\"]:has-text(\"States\")").click();
await page.locator("[aria-label=\"Add a state\"]").click();
await page.locator("input[name=\"set\\.states\\.s0\\.particle\"]").fill(
"Ar",
await page.getByRole("tab", { name: "Species" }).click();
await page.getByRole("button", { name: "+" }).click();
await page.locator("span.mantine-Accordion-label").first().click();
await page.getByLabel("Species definition").fill(
"{\"type\": \"simple\", \"particle\": \"Ar\", \"charge\": 0}",
);
await page.locator("input[name=\"set\\.states\\.s0\\.charge\"]").fill("0");
// Processes
await page.locator("button[role=\"tab\"]:has-text(\"Processes\")").click();
await page.locator("[aria-label=\"Add process\"]").click();
await page.locator("[aria-label=\"Add data row to process\"]").click();
await page
.locator("input[name=\"set\\.processes\\.0\\.data\\.0\\.0\"]")
.fill("1.2");
await page
.locator("input[name=\"set\\.processes\\.0\\.data\\.0\\.1\"]")
.fill("3.4e-5");
await page.locator("[aria-label=\"Add consumed reaction entry\"]").click();
await page.getByRole("tab", { name: "Processes" }).click();
await page.getByRole("button", { name: "Add process" }).click();
await page.locator("span.mantine-Accordion-label").first().click();

// Add reactant
await page.getByRole("group", { name: "Reactants" }).getByRole("button")
.click();
await page
.locator(
"[aria-controls=\"set\\.processes\\.0\\.reaction\\.lhs\\.0\\.state\"]",
)
.getByRole("group", { name: "Reactants" })
.locator("button.mantine-UnstyledButton-root")
.nth(2)
.click();
await page.getByRole("menuitem").click();

// Add product
await page.getByRole("group", { name: "Products" }).getByRole("button")
.click();
await page
.locator("button[role=\"menuitem\"]:has-text(\"\\mathrm{Ar}\")")
.getByRole("group", { name: "Products" })
.locator("button.mantine-UnstyledButton-root")
.nth(2)
.click();
await page.getByRole("menuitem").click();

// Add data entry
await page.getByRole("button", { name: "Add info object" }).click();
await page.getByRole("button", { name: "Cross section" }).click();
await page.locator("td").nth(1).locator("input").fill("1.2");
await page.locator("td").nth(2).locator("input").fill("3.4e-5");
}

test.describe("given minimal set", () => {
Expand All @@ -153,7 +167,7 @@ test.describe.skip("/author/scat-css/add", () => {
});

test("should have json document", async ({ page }) => {
await page.locator("button[role=\"tab\"]:has-text(\"JSON\")").click();
await page.getByRole("tab", { name: "JSON" }).click();
const json = await page.locator("pre").innerText();
const expected = {
name: "My name",
Expand All @@ -166,36 +180,47 @@ test.describe.skip("/author/scat-css/add", () => {
lhs: [
{
count: 1,
state: "s0",
state: expect.any(String),
},
],
rhs: [
{
count: 1,
state: expect.any(String),
},
],
rhs: [],
reversible: false,
type_tags: [],
typeTags: [],
},
threshold: 0,
type: "LUT",
labels: ["Energy", "CrossSection"],
units: ["eV", "m^2"],
data: [[1.2, 3.4e-5]],
parameters: {},
info: [
{
type: "CrossSection",
threshold: 0,
references: [],
data: {
type: "LUT",
labels: ["Energy", "Cross Section"],
units: ["eV", "m^2"],
values: [[1.2, 3.4e-5]],
},
},
],
},
],
states: {
s0: {
particle: "Ar",
charge: 0,
},
},
// TODO: This is not very strict, we can assert on the expected values.
states: expect.any(Object),
references: {},
};
expect(JSON.parse(json)).toEqual(expected);
});

test("after submit should have success message", async ({ page }) => {
await page.locator("button:has-text(\"Submit\")").click();
await page
.getByPlaceholder("Describe which changes have")
.fill("Initial upload");
await page.getByRole("button", { name: "Submit" }).click();

await expect(page.locator(".status")).toContainText("Adding successful");
await expect(page.getByText("Saved set with id")).toBeVisible();
});
});
});
5 changes: 2 additions & 3 deletions app/e2e/global-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ export async function uploadAndPublishDummySet(
await page.waitForSelector(`div:has-text("${org}")`);

// Add a set
await page.goto("/author/scat-css/addraw");
await page.goto("/author/set/addraw");
const dummySet = await readFile(
`../packages/database/src/test/seed/cross-sections/${file}`,
{ encoding: "utf8" },
Expand All @@ -148,8 +148,7 @@ export async function uploadAndPublishDummySet(
await page.waitForSelector("span:has-text(\"Upload successful\")");

// Publish set
await page.goto("/author/scat-css");
await page.reload(); // TODO sometimes no set is listed, use reload to give server some time as workaround
await page.goto("/author/set");
await page.waitForSelector("td:has-text(\"draft\")");
await page.locator("tbody button:has-text(\"Publish\")").click();
// Press publish in dialog
Expand Down
4 changes: 1 addition & 3 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@
"@citation-js/plugin-csl": "^0.7.11",
"@citation-js/plugin-doi": "^0.7.11",
"@citation-js/plugin-ris": "^0.7.11",
"@hookform/error-message": "^2.0.1",
"@hookform/resolvers": "^3.4.2",
"@lxcat/converter": "workspace:^",
"@lxcat/database": "workspace:^",
"@lxcat/schema": "workspace:^",
"@mantine/code-highlight": "^7.10.1",
"@mantine/core": "^7.10.1",
"@mantine/form": "^7.10.1",
"@mantine/hooks": "^7.10.1",
Expand Down Expand Up @@ -56,7 +55,6 @@
"plotly.js-basic-dist": "^2.33.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-hook-form": "^7.51.5",
"react-latex-next": "^3.0.0",
"react-plotly.js": "^2.6.0",
"react-schemaorg": "^2.0.0",
Expand Down
14 changes: 7 additions & 7 deletions app/src/app/api/author/scat-css/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { LXCatID } from "@/shared/lxcatid";
import { db } from "@lxcat/database";
import { EditedLTPDocument } from "@lxcat/schema";
import { z } from "zod";
import { object, string } from "zod";
import {
badRequestResponse,
forbiddenResponse,
Expand All @@ -17,14 +17,14 @@ import { hasAuthorRole, hasSessionOrAPIToken } from "../../../middleware/auth";
import { zodMiddleware } from "../../../middleware/zod";
import { RouteBuilder } from "../../../route-builder";

export const postSchema = z.object({
path: z.object({ id: LXCatID }),
body: z.object({ doc: EditedLTPDocument, message: z.string() }),
export const postSchema = object({
path: object({ id: LXCatID }),
body: object({ doc: EditedLTPDocument, message: string().min(1) }),
});

export const deleteSchema = z.object({
path: z.object({ id: LXCatID }),
body: z.object({ message: z.optional(z.string().min(1)) }),
export const deleteSchema = object({
path: object({ id: LXCatID }),
body: object({ message: string().min(1) }),
});

const postRouter = RouteBuilder
Expand Down
7 changes: 3 additions & 4 deletions app/src/app/api/author/scat-css/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,17 @@ const postRouter = RouteBuilder
.getAffiliations(ctx.user.email)
.then((affiliations) => affiliations.map(({ name }) => name));

const doc = ctx.parsedParams.body;
const { doc, message } = ctx.parsedParams.body;
if (affiliations.includes(doc.contributor)) {
// Add to CrossSectionSet with status=='draft' and version=='1'
const id = await db().createSet(doc, "draft");
const id = await db().createSet(doc, "draft", 1, message);
return okJsonResponse({ id });
} else {
return forbiddenResponse({
json: {
errors: [
{
message:
`You are not a member of the ${ctx.parsedParams.body.contributor} organization.`,
`You are not a member of the ${doc.contributor} organization.`,
},
],
},
Expand Down
6 changes: 3 additions & 3 deletions app/src/app/api/author/scat-css/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

import { EditedLTPDocument } from "@lxcat/schema";
import { z } from "zod";
import { object, string } from "zod";

export const querySchema = z.object({
body: EditedLTPDocument,
export const querySchema = object({
body: object({ doc: EditedLTPDocument, message: string().min(1) }),
});
2 changes: 1 addition & 1 deletion app/src/app/api/users/[user]/organizations/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ export const querySchema = z.object({
path: z.object({
user: z.string(),
}),
body: z.array(LXCatID).min(1),
body: z.array(LXCatID),
});
Loading
Loading