Skip to content

Batch edit for relationships #6283

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

Open
wants to merge 122 commits into
base: production
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
419e37c
Enable trees in queries
sharadsw Feb 5, 2025
93e2a0a
Use query construct code from #4929
sharadsw Feb 7, 2025
cff6f56
Update unit test
sharadsw Feb 7, 2025
7e478b9
Merge branch 'issue-5413' into issue-6127
sharadsw Feb 7, 2025
f7c30e1
Enable nested to-many in Workbench
sharadsw Feb 10, 2025
f6b6562
Update test
sharadsw Feb 12, 2025
7d7cdd0
Remove param_count
sharadsw Feb 13, 2025
b389372
Display tree name in query error
sharadsw Feb 14, 2025
0fa6fc8
Add upload plan changes
sharadsw Feb 14, 2025
82033cd
Update tests
sharadsw Feb 14, 2025
a56c65b
Lint code with ESLint and Prettier
sharadsw Feb 14, 2025
536fe0c
Merge remote-tracking branch 'origin/issue-5413' into issue-6127
sharadsw Feb 18, 2025
aa81431
Update TreeRankQuery to fix implicit ORs
sharadsw Feb 20, 2025
52e312f
Allow removing last row in Batch Edit
sharadsw Feb 24, 2025
444eb32
Make a missing rank info dialog which proceeds to dataset creation
sharadsw Feb 25, 2025
65f7d21
Augment tree queries with missing ranks for batch edit
sharadsw Feb 25, 2025
46fe370
Lint code with ESLint and Prettier
sharadsw Feb 25, 2025
59eb7ff
Adjust apply_batch_edit_pack for multiple trees
sharadsw Feb 25, 2025
79bdb27
Add a discipline type in tests
sharadsw Feb 25, 2025
350ee9c
Enable relationships
sharadsw Feb 26, 2025
2fc7842
Lint code with ESLint and Prettier
sharadsw Feb 26, 2025
e811142
Merge remote-tracking branch 'origin/issue-6127' into issue-2331
sharadsw Feb 26, 2025
b1ef1eb
Merge remote-tracking branch 'origin/issue-2331' into issue-6126
sharadsw Feb 26, 2025
c1f092d
Enable data mapper and batch edit preferences
sharadsw Feb 27, 2025
ec7424c
Fix localizations
sharadsw Feb 27, 2025
aee76e5
Consider remote to ones as to many in upload plan
sharadsw Feb 28, 2025
daabdc4
Add remote to ones method
sharadsw Feb 28, 2025
1720131
Un-enforce TreeRankRecord in upload plan
sharadsw Mar 3, 2025
4f161f5
Add loading action to missing ranks dialog
sharadsw Mar 3, 2025
18305a6
Move table name to same line in missing fields dialog
sharadsw Mar 3, 2025
06a4cc6
Merge branch 'issue-6127' into issue-2331
sharadsw Mar 3, 2025
78a6769
Handle case when rank name has spaces
sharadsw Mar 3, 2025
f1fa36e
Merge branch 'issue-6127' into issue-2331
sharadsw Mar 3, 2025
d65495f
Add a close button to missing ranks dialog
sharadsw Mar 3, 2025
5992ae5
Merge branch 'issue-2331' into issue-6126
sharadsw Mar 3, 2025
7f70cb4
Fix frontend missing field calculation
sharadsw Mar 4, 2025
9407376
Fix frontend to many tree error
sharadsw Mar 4, 2025
937e865
Lint code with ESLint and Prettier
sharadsw Mar 4, 2025
f4d02ca
Merge remote-tracking branch 'origin/issue-6127' into issue-6126
sharadsw Mar 4, 2025
ebd827f
Restrict to manys only for tree fields
sharadsw Mar 4, 2025
f666936
Merge remote-tracking branch 'origin/issue-6127' into issue-6127
sharadsw Mar 4, 2025
fc7be1f
Merge remote-tracking branch 'origin/issue-6127' into issue-6126
sharadsw Mar 4, 2025
d6c608c
Avoid cloning to-ones when committing
sharadsw Mar 4, 2025
246d394
Merge remote-tracking branch 'origin/issue-5413' into issue-6127
sharadsw Mar 6, 2025
5e7d844
Merge branch 'issue-5413' into issue-6127
sharadsw Mar 6, 2025
8574c50
Merge branch 'issue-6127' into issue-2331
sharadsw Mar 6, 2025
3c9b344
Merge branch 'issue-2331' into issue-6126
sharadsw Mar 6, 2025
82ec65c
Fix to many for tree in relationships
sharadsw Mar 6, 2025
019e932
Merge remote-tracking branch 'origin/issue-6126' into issue-6126
sharadsw Mar 6, 2025
8c6d897
Change revert to rollback in pref localization
sharadsw Mar 7, 2025
cc5cf55
Use TreeRankRecord in upload plan
sharadsw Mar 11, 2025
4e93d78
Fix multiple rank in row error
sharadsw Mar 11, 2025
bf153f9
Fix multiple rank in row error
sharadsw Mar 11, 2025
1550bb8
Merge remote-tracking branch 'origin/issue-6127' into issue-6127
sharadsw Mar 11, 2025
ae42fdd
Fix navigator
sharadsw Mar 12, 2025
2835687
Fix tests
sharadsw Mar 12, 2025
7f2149d
Group missing ranks by tree
sharadsw Mar 12, 2025
9c46e15
Lint code with ESLint and Prettier
sharadsw Mar 12, 2025
b1173ff
Pass filtered treedef ids to the backend
sharadsw Mar 13, 2025
1c29ec9
Merge remote-tracking branch 'origin/issue-6127' into issue-6127
sharadsw Mar 13, 2025
d09d325
Lint code with ESLint and Prettier
sharadsw Mar 13, 2025
e8d138e
Filter trees used when rewriting batch edit dataset
sharadsw Mar 13, 2025
1589ed8
Fix tests
sharadsw Mar 13, 2025
1382ed9
Merge remote-tracking branch 'origin/production' into issue-6127
sharadsw Mar 27, 2025
8ac0c4a
Use TreeRankRecord in upload plan
sharadsw Mar 11, 2025
06f5232
Remove unused string
sharadsw Mar 27, 2025
a8a2ad6
Fix visual order
sharadsw Mar 27, 2025
ca8b498
Revert "Fix visual order"
sharadsw Mar 28, 2025
f713380
Merge remote-tracking branch 'origin/issue-6127' into issue-2331
sharadsw Mar 28, 2025
f0822bf
Fix tests
sharadsw Mar 28, 2025
8f3891a
Lint code with ESLint and Prettier
sharadsw Mar 28, 2025
b3c4224
Merge remote-tracking branch 'origin/issue-2331' into issue-6126
sharadsw Mar 31, 2025
3945527
Handle (any rank) mapping for Batch Edit upload plans
sharadsw Apr 1, 2025
f8262cc
Lint code with ESLint and Prettier
sharadsw Apr 1, 2025
6130fd2
Disable spauditlog for BE
sharadsw Apr 2, 2025
70ebedc
Add title when batch edit is disabled
sharadsw Apr 2, 2025
a1ca3fc
Fix deleted cells for many-to-one dependents
sharadsw Apr 2, 2025
33436f2
Use variant permissions for creating record sets
sharadsw Apr 4, 2025
a321b9d
Fix undefined name error
sharadsw Apr 8, 2025
324c2f9
Disable changing batch edit prefs after upload
sharadsw Apr 11, 2025
b1b623c
Add validation error for scope change
sharadsw Apr 14, 2025
34a3459
Add localization for other WB errors
sharadsw Apr 14, 2025
823a5f3
Lint code with ESLint and Prettier
sharadsw Apr 14, 2025
54b57e5
Remove description for null record
sharadsw Apr 14, 2025
387a265
Ensure at least 1 to-many column gets added to batch edit datasets
sharadsw Apr 14, 2025
0c68d90
Merge remote-tracking branch 'origin/issue-6126' into issue-6126
sharadsw Apr 14, 2025
a6e0d4e
Flag to-many in tree only queries
sharadsw Apr 15, 2025
2367a75
Merge branch 'issue-6127' into issue-2331
sharadsw Apr 15, 2025
f6e9137
Merge branch 'issue-2331' into issue-6126
sharadsw Apr 15, 2025
f36521c
Merge branch 'production' into issue-6127
sharadsw Apr 15, 2025
f27581b
Merge branch 'issue-6127' into issue-2331
sharadsw Apr 15, 2025
f546fc4
Merge remote-tracking branch 'origin/issue-2331' into issue-6126
sharadsw Apr 15, 2025
b31b8a7
Lint code with ESLint and Prettier
sharadsw Apr 15, 2025
0647fa6
Merge remote-tracking branch 'origin/issue-6126' into issue-6126
sharadsw Apr 15, 2025
cbdd011
Lint code with ESLint and Prettier
sharadsw Apr 15, 2025
cc1f85b
Enable nested to-many in Workbench (#6216)
sharadsw Apr 15, 2025
97c66dd
Merge branch 'issue-6127' into issue-6126
sharadsw Apr 15, 2025
a81c95f
Lint code with ESLint and Prettier
sharadsw Apr 15, 2025
45bd49d
Disable editing any rank tree relationships
sharadsw Apr 15, 2025
1e393f0
Check for lowercase tree table names when rewriting tree rank row plan
sharadsw Apr 21, 2025
bcc4277
Merge remote-tracking branch 'origin/production' into issue-6127
sharadsw Apr 21, 2025
633a7da
Merge branch 'issue-6127' into issue-6126
sharadsw Apr 21, 2025
4116d45
Lint code with ESLint and Prettier
sharadsw Apr 21, 2025
3be9e53
Merge branch 'production' into issue-6127
sharadsw Apr 22, 2025
7fc7f89
Merge branch 'issue-6127' into issue-6126
sharadsw Apr 22, 2025
e593bc0
Handle None rank
sharadsw Apr 23, 2025
5235f7b
Merge remote-tracking branch 'origin/issue-6127' into issue-6127
sharadsw Apr 23, 2025
64583e1
Merge branch 'issue-6127' into issue-6126
sharadsw Apr 23, 2025
30ae8de
Batch edit: Disable editing dataset after rollback (#6428)
sharadsw Apr 25, 2025
8222246
Fix tree column order
sharadsw Apr 28, 2025
afe7be1
Fix tests
sharadsw Apr 28, 2025
9ad2984
Merge remote-tracking branch 'origin/production' into issue-6127
sharadsw Apr 28, 2025
ef752a2
Merge remote-tracking branch 'origin/issue-6127' into issue-6126
sharadsw Apr 28, 2025
17775e5
Merge remote-tracking branch 'origin/issue-6126' into issue-6126
sharadsw Apr 28, 2025
ff13159
Fix tests
sharadsw Apr 28, 2025
9aab7dd
Upgrade celery version (#6437)
sharadsw Apr 28, 2025
b273a60
Revert back to sort columns
sharadsw Apr 28, 2025
0956c47
Merge remote-tracking branch 'origin/issue-6127' into issue-6126
sharadsw Apr 28, 2025
5d6443d
Enable matched and changed when readonly
sharadsw Apr 29, 2025
c0d7373
Merge remote-tracking branch 'origin/production' into issue-6126
sharadsw May 1, 2025
695b142
Add missing import
sharadsw May 1, 2025
8142a51
Re-add lost code
sharadsw May 1, 2025
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
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ setuptools>=50.0.0
tzdata
wheel
backports.zoneinfo==0.2.1
kombu==5.2.4
celery[redis]==5.2.7
kombu==5.5.2
celery[redis]==5.5.1
Django==4.2.18
mysqlclient==2.1.1
SQLAlchemy==1.2.11
Expand All @@ -12,4 +12,4 @@ pycryptodome==3.21.0
PyJWT==2.3.0
django-auth-ldap==1.2.17
jsonschema==3.2.0
typing-extensions==4.3.0
typing-extensions==4.12.2
19 changes: 15 additions & 4 deletions specifyweb/frontend/js_src/lib/components/BatchEdit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,16 @@ export function BatchEditFromQuery({
})
);

const isDisabled =
queryFieldSpecs.some(containsSystemTables) ||
queryFieldSpecs.some(hasHierarchyBaseTable) ||
containsDisallowedTables(query);

return (
<>
<Button.Small
disabled={
queryFieldSpecs.some(containsSystemTables) ||
queryFieldSpecs.some(hasHierarchyBaseTable)
}
disabled={isDisabled}
title={isDisabled ? batchEditText.batchEditDisabled() : undefined}
onClick={() => {
loading(
treeRanksPromise.then(async () => {
Expand Down Expand Up @@ -205,5 +208,13 @@ const hasHierarchyBaseTable = (queryFieldSpec: QueryFieldSpec) =>
queryFieldSpec.baseTable.name.toLowerCase() as 'collection'
);

// Using tables.SpAuditLog here leads to an error in some cases where the tables data hasn't loaded correctly
const DISALLOWED_TABLES = ['spauditlog'];

const containsDisallowedTables = (query: SpecifyResource<SpQuery>) =>
DISALLOWED_TABLES.some(
(tableName) => query.get('contextName').toLowerCase() === tableName
);

// Error filters
const filters = [containsFaultyNestedToMany, containsSystemTables];
5 changes: 5 additions & 0 deletions specifyweb/frontend/js_src/lib/components/WbActions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export function WbActions({
useBooleanState();
const [operationCompleted, openOperationCompleted, closeOperationCompleted] =
useBooleanState();

const { mode, refreshInitiatorAborted, startUpload, triggerStatusComponent } =
useWbActions({
datasetId: dataset.id,
Expand Down Expand Up @@ -262,6 +263,10 @@ function useWbActions({
const refreshInitiatorAborted = React.useRef<boolean>(false);
const loading = React.useContext(LoadingContext);

/**
* NOTE: Only validate and upload use startUpload
* For rollback, we directly call the API inside the RollbackConfirmation component
*/
const startUpload = (newMode: WbStatus): void => {
workbench.validation.stopLiveValidation();
loading(
Expand Down
132 changes: 96 additions & 36 deletions specifyweb/frontend/js_src/lib/components/WbPlanView/Mapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import type { MappingElementProps } from './LineComponents';
import { getMappingLineProps, MappingLineComponent } from './LineComponents';
import { columnOptionsAreDefault } from './linesGetter';
import {
BatchEditPrefsView,
ChangeBaseTable,
EmptyDataSetDialog,
mappingOptionsMenu,
Expand Down Expand Up @@ -102,17 +103,36 @@ export type MappingState = State<
readonly autoMapperSuggestions?: RA<AutoMapperSuggestion>;
readonly openSelectElement?: SelectElementPosition;
readonly validationResults: RA<MappingPath>;
readonly batchEditPrefs?: BatchEditPrefs;
}
>;

export type ReadonlySpec = {
readonly mustMatch: boolean;
readonly columnOptions: boolean;
readonly batchEditPrefs: boolean;
};

export type BatchEditPrefs = {
readonly deferForNullCheck: boolean;
readonly deferForMatch: boolean;
};

export const DEFAULT_BATCH_EDIT_PREFS: BatchEditPrefs = {
deferForMatch: true,
deferForNullCheck: false,
} as const;

export const getDefaultMappingState = ({
changesMade,
lines,
mustMatchPreferences,
batchEditPrefs,
}: {
readonly changesMade: boolean;
readonly lines: RA<MappingLine>;
readonly mustMatchPreferences: IR<boolean>;
readonly batchEditPrefs?: BatchEditPrefs;
}): MappingState => ({
type: 'MappingState',
showHiddenFields: getCache('wbPlanViewUi', 'showHiddenFields') ?? false,
Expand All @@ -124,6 +144,7 @@ export const getDefaultMappingState = ({
focusedLine: 0,
changesMade,
mustMatchPreferences,
batchEditPrefs,
});

// REFACTOR: split component into smaller components
Expand All @@ -133,19 +154,23 @@ export function Mapper(props: {
readonly onChangeBaseTable: () => void;
readonly onSave: (
lines: RA<MappingLine>,
mustMatchPreferences: IR<boolean>
mustMatchPreferences: IR<boolean>,
batchEditPrefs?: BatchEditPrefs
) => Promise<void>;
// Initial values for the state:
readonly changesMade: boolean;
readonly lines: RA<MappingLine>;
readonly mustMatchPreferences: IR<boolean>;
readonly readonlySpec?: ReadonlySpec;
readonly batchEditPrefs?: BatchEditPrefs;
}): JSX.Element {
const [state, dispatch] = React.useReducer(
reducer,
{
changesMade: props.changesMade,
lines: props.lines,
mustMatchPreferences: props.mustMatchPreferences,
batchEditPrefs: props.batchEditPrefs,
},
getDefaultMappingState
);
Expand Down Expand Up @@ -264,7 +289,13 @@ export function Mapper(props: {
const validationResults = ignoreValidation ? [] : validate();
if (validationResults.length === 0) {
unsetUnloadProtect();
loading(props.onSave(state.lines, state.mustMatchPreferences));
loading(
props.onSave(
state.lines,
state.mustMatchPreferences,
state.batchEditPrefs
)
);
} else
dispatch({
type: 'ValidationAction',
Expand Down Expand Up @@ -294,6 +325,11 @@ export function Mapper(props: {
mappingPathIsComplete(state.mappingView) &&
getMappedFieldsBind(state.mappingView).length === 0;

const disableSave =
props.readonlySpec === undefined
? isReadOnly
: Object.values(props.readonlySpec).every(Boolean);

return (
<Layout
buttonsLeft={
Expand Down Expand Up @@ -337,38 +373,61 @@ export function Mapper(props: {
})
}
/>
<MustMatch
getMustMatchPreferences={(): IR<boolean> =>
getMustMatchTables({
baseTableName: props.baseTableName,
lines: state.lines,
mustMatchPreferences: state.mustMatchPreferences,
})
}
onChange={(mustMatchPreferences): void =>
dispatch({
type: 'MustMatchPrefChangeAction',
mustMatchPreferences,
})
}
onClose={(): void => {
/*
* Since setting table as must match causes all of its fields to
* be optional, we may have to rerun validation on
* mustMatchPreferences changes
*/
if (
state.validationResults.length > 0 &&
state.lines.some(({ mappingPath }) =>
mappingPathIsComplete(mappingPath)
)
)
{typeof props.batchEditPrefs === 'object' ? (
<ReadOnlyContext.Provider
value={
props.dataset.uploadresult?.success ??
props.readonlySpec?.batchEditPrefs ??
isReadOnly
}
>
<BatchEditPrefsView
prefs={props.batchEditPrefs}
onChange={(prefs) =>
dispatch({
type: 'ChangeBatchEditPrefs',
prefs,
})
}
/>
</ReadOnlyContext.Provider>
) : null}
<ReadOnlyContext.Provider
value={props.readonlySpec?.mustMatch ?? isReadOnly}
>
<MustMatch
getMustMatchPreferences={(): IR<boolean> =>
getMustMatchTables({
baseTableName: props.baseTableName,
lines: state.lines,
mustMatchPreferences: state.mustMatchPreferences,
})
}
onChange={(mustMatchPreferences): void =>
dispatch({
type: 'ValidationAction',
validationResults: validate(),
});
}}
/>
type: 'ChangeMustMatchPrefAction',
mustMatchPreferences,
})
}
onClose={(): void => {
/*
* Since setting table as must match causes all of its fields to
* be optional, we may have to rerun validation on
* mustMatchPreferences changes
*/
if (
state.validationResults.length > 0 &&
state.lines.some(({ mappingPath }) =>
mappingPathIsComplete(mappingPath)
)
)
dispatch({
type: 'ValidationAction',
validationResults: validate(),
});
}}
/>
</ReadOnlyContext.Provider>
{!isReadOnly && (
<Button.Small
className={
Expand Down Expand Up @@ -396,11 +455,12 @@ export function Mapper(props: {
>
{isReadOnly ? wbText.dataEditor() : commonText.cancel()}
</Link.Small>
{!isReadOnly && (
{!disableSave && (
<Button.Small
disabled={!state.changesMade}
variant={className.saveButton}
onClick={(): void => handleSave(false)}
// This is a bit complicated to resolve correctly. Each component should have its own validator..
onClick={(): void => handleSave(isReadOnly)}
>
{commonText.save()}
</Button.Small>
Expand Down Expand Up @@ -557,7 +617,7 @@ export function Mapper(props: {
customSelectSubtype: 'simple',
fieldsData: mappingOptionsMenu({
id: (suffix) => id(`column-options-${line}-${suffix}`),
isReadOnly,
isReadOnly: props.readonlySpec?.columnOptions ?? isReadOnly,
columnOptions,
onChangeMatchBehaviour: (matchBehavior) =>
dispatch({
Expand Down
Loading
Loading