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

Change link/unlink behaviour to directly apply changes without showing modal or message #2523

Merged
merged 9 commits into from
Sep 4, 2024
123 changes: 57 additions & 66 deletions src/components/record/related-table-actions.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,48 @@
import { MouseEvent, useState, useRef, useLayoutEffect } from 'react';
import { MouseEvent, useLayoutEffect, useRef, useState } from 'react';

// components
import DisplayValue from '@isrd-isi-edu/chaise/src/components/display-value';
import ChaiseTooltip from '@isrd-isi-edu/chaise/src/components/tooltip';
import RecordsetModal from '@isrd-isi-edu/chaise/src/components/modals/recordset-modal';
import DeleteConfirmationModal, { DeleteConfirmationModalTypes } from '@isrd-isi-edu/chaise/src/components/modals/delete-confirmation-modal';
import RecordsetModal from '@isrd-isi-edu/chaise/src/components/modals/recordset-modal';
import ChaiseTooltip from '@isrd-isi-edu/chaise/src/components/tooltip';
import Dropdown from 'react-bootstrap/Dropdown';
// hooks
import useRecord from '@isrd-isi-edu/chaise/src/hooks/record';
import useAuthn from '@isrd-isi-edu/chaise/src/hooks/authn';
import useAlert from '@isrd-isi-edu/chaise/src/hooks/alerts';
import useAuthn from '@isrd-isi-edu/chaise/src/hooks/authn';
import useError from '@isrd-isi-edu/chaise/src/hooks/error';
import useRecord from '@isrd-isi-edu/chaise/src/hooks/record';

// models
import { CommentDisplayModes } from '@isrd-isi-edu/chaise/src/models/displayname';
import { LogActions, LogParentActions, LogReloadCauses, LogStackPaths, LogStackTypes } from '@isrd-isi-edu/chaise/src/models/log';
import { RecordRelatedModel } from '@isrd-isi-edu/chaise/src/models/record';
import { LogActions, LogParentActions, LogReloadCauses } from '@isrd-isi-edu/chaise/src/models/log';
import {
RecordsetConfig,
RecordsetDisplayMode,
RecordsetProps,
RecordsetSelectMode,
SelectedRow,
} from '@isrd-isi-edu/chaise/src/models/recordset';
import { LogStackPaths, LogStackTypes } from '@isrd-isi-edu/chaise/src/models/log';
import { CommentDisplayModes } from '@isrd-isi-edu/chaise/src/models/displayname';

// providers
import { ChaiseAlertType } from '@isrd-isi-edu/chaise/src/providers/alerts';

// services
import { LogService } from '@isrd-isi-edu/chaise/src/services/log';
import { CookieService } from '@isrd-isi-edu/chaise/src/services/cookie';
import { ConfigService } from '@isrd-isi-edu/chaise/src/services/config';
import { CookieService } from '@isrd-isi-edu/chaise/src/services/cookie';
import { LogService } from '@isrd-isi-edu/chaise/src/services/log';

// utils
import { addQueryParamsToURL } from '@isrd-isi-edu/chaise/src/utils/uri-utils';
import {
CUSTOM_EVENTS,
RECORDSET_DEFAULT_PAGE_SIZE,
} from '@isrd-isi-edu/chaise/src/utils/constants';
import { getRandomInt } from '@isrd-isi-edu/chaise/src/utils/math-utils';
import {
allowCustomModeRelated,
displayCustomModeRelated,
getPrefillCookieObject,
} from '@isrd-isi-edu/chaise/src/utils/record-utils';
import {
RECORDSET_DEFAULT_PAGE_SIZE,
CUSTOM_EVENTS,
} from '@isrd-isi-edu/chaise/src/utils/constants';
import { windowRef } from '@isrd-isi-edu/chaise/src/utils/window-ref';
import { getRandomInt } from '@isrd-isi-edu/chaise/src/utils/math-utils';
import { fireCustomEvent } from '@isrd-isi-edu/chaise/src/utils/ui-utils';
import Q from 'q';
import { addQueryParamsToURL } from '@isrd-isi-edu/chaise/src/utils/uri-utils';
import { windowRef } from '@isrd-isi-edu/chaise/src/utils/window-ref';
import ResizeSensor from 'css-element-queries/src/ResizeSensor';

type RelatedTableActionsProps = {
Expand Down Expand Up @@ -420,12 +415,6 @@ const RelatedTableActions = ({
.create(submissionRows, logObj)
.then(() => {
setAddPureBinaryModalProps(null);
addAlert(
<>
<code><DisplayValue value={usedRef.displayname}></DisplayValue></code> records have been successfully linked.
</>,
ChaiseAlertType.SUCCESS
);

const details = relatedModel.recordsetProps.config.containerDetails!;
updateRecordPage(true, undefined, [
Expand Down Expand Up @@ -519,45 +508,49 @@ const RelatedTableActions = ({
setShowPureBinarySpinner(true);

validateSessionBeforeMutation(() => {
const deleteResponse = (response: any) => {
setShowPureBinarySpinner(false);

// Show modal popup summarizing total # of deletions succeeded and failed
response.clickOkToDismiss = true;

// TODO: - improve partial success and use TRS to check delete rights before giving a checkbox
// - some errors could have been because of row level security
dispatchError({
jrchudy marked this conversation as resolved.
Show resolved Hide resolved
error: response,
isDismissible: true,
closeBtnCallback: () => {
// ask recordset to update the modal
if (!!containerRef.current) {
// NOTE: This feels very against React but the complexity of our flow control provider seems to warrant doing this
fireCustomEvent(CUSTOM_EVENTS.FORCE_UPDATE_RECORDSET, containerRef.current, {
cause: LogReloadCauses.ENTITY_BATCH_UNLINK,
pageStates: { updateResult: true, updateCount: true, updateFacets: true },
response: response,
const deleteTuples = () => {
leafReference
.deleteBatchAssociationTuples(relatedModel.recordsetProps.parentTuple, selectedRows)
.then((response: any) => {
setShowPureBinarySpinner(false);
if (response.failedTupleData.length > 0) {
response.clickOkToDismiss = true;

// TODO: - improve partial success and use TRS to check delete rights before giving a checkbox
// - some errors could have been because of row level security
dispatchError({
error: response,
isDismissible: true,
closeBtnCallback: () => {
// ask recordset to update the modal
if (!!containerRef.current) {
// NOTE: This feels very against React but the complexity of our flow control provider seems to warrant doing this
fireCustomEvent(CUSTOM_EVENTS.FORCE_UPDATE_RECORDSET, containerRef.current, {
cause: LogReloadCauses.ENTITY_BATCH_UNLINK,
pageStates: { updateResult: true, updateCount: true, updateFacets: true },
response: response,
});
}
},
});
}
},
});
};

const deleteError = (err: any) => {
setShowPureBinarySpinner(false);
// errors that land here would be execution of code errors
// if a deletion fails/errors, that delete request is caught by ermrestJS and returned
// as part of the deleteErrors object in the success cb
// NOTE: if one of the identifying values is empty or null, an error is thrown here
dispatchError({ error: err, isDismissible: true });
else {
setUnlinkPureBinaryModalProps(null);
updateRecordPage(true, LogReloadCauses.RELATED_BATCH_UNLINK);
}
})
.catch((err: Error) => {
setShowPureBinarySpinner(false);
// errors that land here would be execution of code errors
// if a deletion fails/errors, that delete request is caught by ermrestJS and returned
// as part of the deleteErrors object in the success cb
// NOTE: if one of the identifying values is empty or null, an error is thrown here
dispatchError({ error: err, isDismissible: true });
})
};

if (!CONFIRM_DELETE) {
jrchudy marked this conversation as resolved.
Show resolved Hide resolved
return leafReference
.deleteBatchAssociationTuples(relatedModel.recordsetProps.parentTuple, selectedRows)
.then(deleteResponse)
.catch(deleteError);
return deleteTuples();
}

logRecordClientAction(LogActions.UNLINK_INTEND);
Expand All @@ -574,10 +567,7 @@ const RelatedTableActions = ({
title: 'Confirm Unlink',
onConfirm: () => {
setShowDeleteConfirmationModal(null);
return leafReference
.deleteBatchAssociationTuples(relatedModel.recordsetProps.parentTuple, selectedRows)
.then(deleteResponse)
.catch(deleteError);
return deleteTuples();
},
onCancel: () => {
setShowDeleteConfirmationModal(null);
Expand All @@ -588,6 +578,7 @@ const RelatedTableActions = ({
});
});
};

setUnlinkPureBinarySubmitCB(() => submitCB);

setUnlinkPureBinaryModalProps({
Expand All @@ -613,7 +604,7 @@ const RelatedTableActions = ({

let pureAndBinaryTitleComment;
if (usedRef.comment && usedRef.comment.displayMode === CommentDisplayModes.TOOLTIP) {
pureAndBinaryTitleComment= usedRef.comment;
pureAndBinaryTitleComment = usedRef.comment;
}

const mainTable = (
Expand Down
30 changes: 9 additions & 21 deletions test/e2e/specs/all-features/record/related-table.spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { expect, Page, test } from '@playwright/test';
import moment from 'moment';
import { test, expect, Page } from '@playwright/test';

//locators
import ModalLocators from '@isrd-isi-edu/chaise/test/e2e/locators/modal';
import RecordsetLocators from '@isrd-isi-edu/chaise/test/e2e/locators/recordset';
import RecordLocators from '@isrd-isi-edu/chaise/test/e2e/locators/record';
import RecordeditLocators, { RecordeditInputType } from '@isrd-isi-edu/chaise/test/e2e/locators/recordedit';
import RecordsetLocators from '@isrd-isi-edu/chaise/test/e2e/locators/recordset';

//utils
import { getCatalogID, getEntityRow, importACLs } from '@isrd-isi-edu/chaise/test/e2e/utils/catalog-utils';
import { APP_NAMES, RESTRICTED_USER_STORAGE_STATE } from '@isrd-isi-edu/chaise/test/e2e/utils/constants';
import { testTooltip } from '@isrd-isi-edu/chaise/test/e2e/utils/page-utils';
import {
testAddAssociationTable, testAddRelatedTable, testBatchUnlinkAssociationTable,
testRelatedTablePresentation, testShareCiteModal
} from '@isrd-isi-edu/chaise/test/e2e/utils/record-utils';
import { APP_NAMES, RESTRICTED_USER_STORAGE_STATE } from '@isrd-isi-edu/chaise/test/e2e/utils/constants';
import { testRecordsetTableRowValues, testTotalCount } from '@isrd-isi-edu/chaise/test/e2e/utils/recordset-utils';
import { testTooltip } from '@isrd-isi-edu/chaise/test/e2e/utils/page-utils';


const testParams = {
schemaName: 'product-unordered-related-tables-links',
Expand Down Expand Up @@ -414,23 +419,6 @@ test.describe('Related tables', () => {
await okBtn.click();
await expect.soft(confirmModal).not.toBeAttached();

// make sure summary modal shows up
const summaryModal = ModalLocators.getErrorModal(page);
await expect.soft(summaryModal).toBeVisible();
await expect.soft(ModalLocators.getModalTitle(summaryModal)).toHaveText('Batch Unlink Summary');
await expect.soft(ModalLocators.getModalText(summaryModal)).toHaveText(params.successPostDeleteMessage);

// close the summary modal
await ModalLocators.getCloseBtn(summaryModal).click();
await expect.soft(summaryModal).not.toBeAttached();

// make sure the recordset modal rows update
await expect.soft(RecordsetLocators.getRows(rsModal)).toHaveCount(params.rowValuesAfter.length);

// close the recordset modal
await ModalLocators.getCloseBtn(rsModal).click();
await expect.soft(rsModal).not.toBeAttached();

// make sure correct values are displayed
const currentEl = RecordLocators.getRelatedTableAccordion(page, params.displayname);
await testRecordsetTableRowValues(currentEl, params.rowValuesAfter, true);
Expand Down
23 changes: 3 additions & 20 deletions test/e2e/utils/record-utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Locator, Page, TestInfo, expect, test } from '@playwright/test';

// locators
import RecordLocators from '@isrd-isi-edu/chaise/test/e2e/locators/record';
import RecordsetLocators from '@isrd-isi-edu/chaise/test/e2e/locators/recordset';
import ModalLocators from '@isrd-isi-edu/chaise/test/e2e/locators/modal';
import RecordLocators from '@isrd-isi-edu/chaise/test/e2e/locators/record';
import RecordeditLocators, { RecordeditInputType } from '@isrd-isi-edu/chaise/test/e2e/locators/recordedit';
import RecordsetLocators from '@isrd-isi-edu/chaise/test/e2e/locators/recordset';

import { getCatalogID, getEntityRow, EntityRowColumnValues } from '@isrd-isi-edu/chaise/test/e2e/utils/catalog-utils';
import { EntityRowColumnValues, getCatalogID, getEntityRow } from '@isrd-isi-edu/chaise/test/e2e/utils/catalog-utils';
import { APP_NAMES, PW_PROJECT_NAMES } from '@isrd-isi-edu/chaise/test/e2e/utils/constants';
import {
clickAndVerifyDownload, clickNewTabLink, getClipboardContent,
Expand Down Expand Up @@ -733,23 +733,6 @@ export const testBatchUnlinkAssociationTable = async (page: Page, params: BatchU
await okBtn.click();
await expect.soft(confirmModal).not.toBeAttached();

// make sure summary modal shows up
const summaryModal = ModalLocators.getErrorModal(page);
await expect.soft(summaryModal).toBeVisible();
await expect.soft(ModalLocators.getModalTitle(summaryModal)).toHaveText('Batch Unlink Summary');
await expect.soft(ModalLocators.getModalText(summaryModal)).toHaveText(params.postDeleteMessage);

// close the summary modal
await ModalLocators.getCloseBtn(summaryModal).click();
await expect.soft(summaryModal).not.toBeAttached();

// make sure the recordset modal rows update
await expect.soft(RecordsetLocators.getRows(rsModal)).toHaveCount(params.rowValuesAfter.length);

// close the recordset modal
await ModalLocators.getCloseBtn(rsModal).click();
await expect.soft(rsModal).not.toBeAttached();

// make sure correct values are displayed
const currentEl = RecordLocators.getRelatedTableContainer(page, params.displayname, params.isInline);
await testRecordsetTableRowValues(currentEl, params.rowValuesAfter, true);
Expand Down