Skip to content

Commit 15e0742

Browse files
authored
Batch edit for multiple trees (#6196)
* Enable trees in queries * Use query construct code from #4929 * Update unit test * Remove param_count * Display tree name in query error * Update TreeRankQuery to fix implicit ORs - see: #6196 (comment) * Allow removing last row in Batch Edit * Make a missing rank info dialog which proceeds to dataset creation * Augment tree queries with missing ranks for batch edit * Lint code with ESLint and Prettier Triggered by 65f7d21 on branch refs/heads/issue-6127 * Adjust apply_batch_edit_pack for multiple trees * Add a discipline type in tests * Un-enforce TreeRankRecord in upload plan * Add loading action to missing ranks dialog * Move table name to same line in missing fields dialog * Handle case when rank name has spaces * Add a close button to missing ranks dialog * Fix frontend missing field calculation * Fix frontend to many tree error * Lint code with ESLint and Prettier Triggered by 9407376 on branch refs/heads/issue-6127 * Restrict to manys only for tree fields * Fix multiple rank in row error * Fix navigator * Fix tests * Group missing ranks by tree * Lint code with ESLint and Prettier Triggered by 7f2149d on branch refs/heads/issue-6127 * Pass filtered treedef ids to the backend - Adds checkboxes to tree names in missing ranks dialog - Splits the main batch edit file into 4 smaller files * Lint code with ESLint and Prettier Triggered by 1c29ec9 on branch refs/heads/issue-6127 * Filter trees used when rewriting batch edit dataset * Fix tests * Use TreeRankRecord in upload plan * Remove unused string * Fix visual order - For multiple trees, columns will be grouped by tree first * Revert "Fix visual order" This reverts commit a8a2ad6. * Flag to-many in tree only queries * Lint code with ESLint and Prettier Triggered by f36521c on branch refs/heads/issue-6127 * Enable nested to-many in Workbench (#6216) * Enable nested to-many in Workbench * Update test * Add upload plan changes * Update tests * Lint code with ESLint and Prettier Triggered by 82033cd on branch refs/heads/issue-2331 * Fix tests * Lint code with ESLint and Prettier Triggered by f0822bf on branch refs/heads/issue-2331 * Lint code with ESLint and Prettier Triggered by f27581b on branch refs/heads/issue-2331 * Lint code with ESLint and Prettier Triggered by cc1f85b on branch refs/heads/issue-6127 * Check for lowercase tree table names when rewriting tree rank row plan * Handle None rank * Fix tree column order * Fix tests * Revert back to sort columns
1 parent eb294ec commit 15e0742

24 files changed

Lines changed: 1385 additions & 735 deletions
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import React from 'react';
2+
3+
import { batchEditText } from '../../localization/batchEdit';
4+
import { commonText } from '../../localization/common';
5+
import { interactionsText } from '../../localization/interactions';
6+
import type { RA, RR } from '../../utils/types';
7+
import { H2, H3, Ul } from '../Atoms';
8+
import { Button } from '../Atoms/Button';
9+
import { Input, Label } from '../Atoms/Form';
10+
import { dialogIcons } from '../Atoms/Icons';
11+
import type { AnyTree } from '../DataModel/helperTypes';
12+
import { strictGetTable } from '../DataModel/tables';
13+
import { getTreeDefinitions } from '../InitialContext/treeRanks';
14+
import { Dialog } from '../Molecules/Dialog';
15+
import { TableIcon } from '../Molecules/TableIcon';
16+
17+
export type TreeDefinitionName = string;
18+
19+
export type MissingRanks = {
20+
// Query can contain relationship to multiple trees
21+
readonly [KEY in AnyTree['tableName']]: RR<TreeDefinitionName, RA<string>>;
22+
};
23+
24+
export function MissingRanksDialog({
25+
missingRanks,
26+
onSelectTreeDef,
27+
onContinue: handleContinue,
28+
onClose: handleClose,
29+
}: {
30+
readonly missingRanks: MissingRanks;
31+
readonly onSelectTreeDef: (
32+
treeTableName: AnyTree['tableName'],
33+
treeDefId: number
34+
) => void;
35+
readonly onContinue: () => void;
36+
readonly onClose: () => void;
37+
}): JSX.Element {
38+
return (
39+
<Dialog
40+
buttons={
41+
<>
42+
<Button.DialogClose>{commonText.close()}</Button.DialogClose>
43+
<Button.Info onClick={handleContinue}>
44+
{interactionsText.continue()}
45+
</Button.Info>
46+
</>
47+
}
48+
header={batchEditText.missingRanksInQuery()}
49+
icon={dialogIcons.info}
50+
onClose={handleClose}
51+
>
52+
<ShowMissingRanks
53+
missingRanks={missingRanks}
54+
onSelectTreeDef={onSelectTreeDef}
55+
/>
56+
</Dialog>
57+
);
58+
}
59+
60+
function ShowMissingRanks({
61+
missingRanks,
62+
onSelectTreeDef: handleSelectTreeDef,
63+
}: {
64+
readonly missingRanks: MissingRanks;
65+
readonly onSelectTreeDef: (
66+
treeTableName: AnyTree['tableName'],
67+
treeDefId: number
68+
) => void;
69+
}) {
70+
return (
71+
<div>
72+
<div className="mt-2 flex gap-2">
73+
<H2>{batchEditText.addTreeRank()}</H2>
74+
</div>
75+
{Object.entries(missingRanks).map(([treeTable, ranks]) => {
76+
const hasMultipleTreeDefs = Object.values(ranks).length > 1;
77+
const treeDefinitions = getTreeDefinitions(treeTable, 'all');
78+
79+
return (
80+
<div key={treeTable}>
81+
<div className="flex gap-2">
82+
<TableIcon
83+
label={strictGetTable(treeTable).label}
84+
name={treeTable}
85+
/>
86+
<H2>{strictGetTable(treeTable).label}</H2>
87+
</div>
88+
{hasMultipleTreeDefs && (
89+
<span>{batchEditText.pickTreesToFilter()}</span>
90+
)}
91+
<div>
92+
{Object.entries(ranks).map(([treeDefName, rankNames]) => {
93+
const treeDefId = treeDefinitions.find(
94+
({ definition }) => definition.name === treeDefName
95+
)?.definition.id;
96+
return (
97+
<div key={treeDefName}>
98+
<Label.Inline>
99+
{hasMultipleTreeDefs && treeDefId !== undefined ? (
100+
<Input.Checkbox
101+
onChange={() =>
102+
handleSelectTreeDef(treeTable, treeDefId)
103+
}
104+
/>
105+
) : undefined}
106+
<H3>{`${treeDefName}:`}</H3>
107+
</Label.Inline>
108+
<Ul>
109+
{rankNames.map((rank) => (
110+
<li className="px-8" key={rank}>
111+
{rank}
112+
</li>
113+
))}
114+
</Ul>
115+
</div>
116+
);
117+
})}
118+
</div>
119+
</div>
120+
);
121+
})}
122+
</div>
123+
);
124+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react';
2+
3+
import { batchEditText } from '../../localization/batchEdit';
4+
import { commonText } from '../../localization/common';
5+
import type { RA } from '../../utils/types';
6+
import { H2, H3 } from '../Atoms';
7+
import { dialogIcons } from '../Atoms/Icons';
8+
import { Dialog } from '../Molecules/Dialog';
9+
10+
export type QueryError = {
11+
readonly invalidFields: RA<string>;
12+
};
13+
14+
export function ErrorsDialog({
15+
errors,
16+
onClose: handleClose,
17+
}: {
18+
readonly errors: QueryError;
19+
readonly onClose: () => void;
20+
}): JSX.Element {
21+
return (
22+
<Dialog
23+
buttons={commonText.close()}
24+
header={batchEditText.errorInQuery()}
25+
icon={dialogIcons.error}
26+
onClose={handleClose}
27+
>
28+
<ShowInvalidFields error={errors.invalidFields} />
29+
</Dialog>
30+
);
31+
}
32+
33+
function ShowInvalidFields({
34+
error,
35+
}: {
36+
readonly error: QueryError['invalidFields'];
37+
}) {
38+
const hasErrors = error.length > 0;
39+
return hasErrors ? (
40+
<div>
41+
<div>
42+
<H2>{batchEditText.removeField()}</H2>
43+
</div>
44+
{error.map((singleError) => (
45+
<H3>{singleError}</H3>
46+
))}
47+
</div>
48+
) : null;
49+
}

0 commit comments

Comments
 (0)