Skip to content

Commit

Permalink
share tab: improve performance
Browse files Browse the repository at this point in the history
* avoid fetching data of each tab pane on opening of the modal
* fetch only the data of the opened pane
* add missing error handlings
  • Loading branch information
anikachurilova authored and ntarocco committed May 7, 2024
1 parent 0d99664 commit 8d13662
Show file tree
Hide file tree
Showing 14 changed files with 813 additions and 582 deletions.
16 changes: 16 additions & 0 deletions invenio_app_rdm/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# under the terms of the MIT License; see LICENSE file for more details.

"""Invenio Research Data Management."""
import warnings

from flask import request
from flask_menu import current_menu
Expand All @@ -23,6 +24,21 @@ def _is_branded_community():
def finalize_app(app):
"""Finalize app."""
init_menu(app)
init_config(app)


def init_config(app):
"""Initialize configuration."""
if "COMMUNITIES_GROUPS_ENABLED" in app.config:
warnings.warn(
"COMMUNITIES_GROUPS_ENABLED config variable is deprecated. Please use USERS_RESOURCES_GROUPS_ENABLED "
"instead. For now, COMMUNITIES_GROUPS_ENABLED value will be taken into account and features related to "
"groups will be disabled if this was the intention.",
DeprecationWarning,
)

if not app.config["COMMUNITIES_GROUPS_ENABLED"]:
app.config["USERS_RESOURCES_GROUPS_ENABLED"] = False


def init_menu(app):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class AccessDropdown extends Component {
this.setState({ loading: false, actionSuccess: true, error: undefined });

handleUpdate = async (permission) => {
const { updateEndpoint } = this.props;
const { updateEndpoint, onPermissionChanged, result, entityType } = this.props;
const data = { permission: permission };
this.setState({ loading: true, actionSuccess: false });
this.cancellableAction = withCancel(http.patch(updateEndpoint, data));
Expand All @@ -44,6 +44,11 @@ export class AccessDropdown extends Component {
this.cancellableAction.promise,
]);
this.onSuccess();
onPermissionChanged(
result?.subject?.id ?? result.id,
data.permission,
entityType
);
} catch (error) {
if (error === "UNMOUNTED") return;
this.setState({
Expand Down Expand Up @@ -83,4 +88,6 @@ AccessDropdown.propTypes = {
result: PropTypes.object.isRequired,
dropdownOptions: PropTypes.array.isRequired,
updateEndpoint: PropTypes.string.isRequired,
entityType: PropTypes.string.isRequired,
onPermissionChanged: PropTypes.func.isRequired,
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,23 @@ import { timestampToRelativeTime } from "../../../utils";
import { AccessDropdown } from "./AccessDropdown";
import _truncate from "lodash/truncate";
import { isEmpty } from "lodash";
import { withCancel, http, dropdownOptionsGenerator } from "react-invenio-forms";
import {
withCancel,
http,
dropdownOptionsGenerator,
ErrorMessage,
} from "react-invenio-forms";
import { dropdownOptions } from "./LinksSearchResultContainer";

export const LinksSearchItem = ({ result, record, fetchData }) => {
export const LinksSearchItem = ({
result,
record,
onItemAddedOrDeleted,
onPermissionChanged,
}) => {
const [copied, setCopied] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(undefined);
var cancellableAction = undefined;

useEffect(() => {
Expand All @@ -35,9 +46,10 @@ export const LinksSearchItem = ({ result, record, fetchData }) => {
try {
await cancellableAction.promise;
setLoading(false);
fetchData();
onItemAddedOrDeleted(record.links.access_links, "links");
} catch (error) {
setLoading(false);
setError(error);
console.error(error);
}
};
Expand Down Expand Up @@ -66,67 +78,84 @@ export const LinksSearchItem = ({ result, record, fetchData }) => {

return (
<Table.Row key={result.id}>
<Table.Cell width={3} data-label="Link title">
{isEmpty(result.description)
? "-"
: _truncate(result.description, { length: 60 })}
</Table.Cell>
<Table.Cell width={3} data-label="Created">
{timestampToRelativeTime(result.created_at)}
</Table.Cell>
<Table.Cell width={3} data-label="Expires at">
{isEmpty(result.expires_at)
? i18next.t("Never")
: `${timestampToRelativeTime(result.expires_at)} (${result.expires_at})`}
</Table.Cell>
<Table.Cell width={3} data-label="Access">
<AccessDropdown
updateEndpoint={`${record.links.access_links}/${result.id}`}
dropdownOptions={dropdownOptionsGenerator(dropdownOptions)}
result={result}
/>
</Table.Cell>
<Table.Cell width={4}>
<Button
loading={loading}
disabled={loading}
onClick={handleDelete}
icon
labelPosition="left"
{error && (
<ErrorMessage
header={i18next.t("Something went wrong")}
content={error?.response?.data?.message || error.message}
icon="exclamation"
negative
size="small"
>
<Icon name="trash" />
{i18next.t("Delete")}
</Button>
<Popup
position="top center"
content={i18next.t("Copied!")}
inverted
open={copied}
on="click"
size="small"
trigger={
size="mini"
/>
)}

{!error && (
<>
<Table.Cell width={3} data-label="Link title">
{isEmpty(result.description)
? "-"
: _truncate(result.description, { length: 60 })}
</Table.Cell>
<Table.Cell width={3} data-label="Created">
{timestampToRelativeTime(result.created_at)}
</Table.Cell>
<Table.Cell width={3} data-label="Expires at">
{isEmpty(result.expires_at)
? i18next.t("Never")
: `${timestampToRelativeTime(result.expires_at)} (${result.expires_at})`}
</Table.Cell>
<Table.Cell width={3} data-label="Access">
<AccessDropdown
updateEndpoint={`${record.links.access_links}/${result.id}`}
dropdownOptions={dropdownOptionsGenerator(dropdownOptions)}
result={result}
onPermissionChanged={onPermissionChanged}
entityType="links"
/>
</Table.Cell>
<Table.Cell width={4}>
<Button
ref={copyButtonRef}
onClick={() => copyAccessLink(result?.id)}
aria-label={i18next.t("Copy link")}
size="small"
loading={loading}
disabled={loading}
onClick={handleDelete}
icon
labelPosition="left"
negative
size="small"
>
<Icon name="copy outline" />
{i18next.t("Copy link")}
<Icon name="trash" />
{i18next.t("Delete")}
</Button>
}
/>
</Table.Cell>
<Popup
position="top center"
content={i18next.t("Copied!")}
inverted
open={copied}
on="click"
size="small"
trigger={
<Button
ref={copyButtonRef}
onClick={() => copyAccessLink(result?.id)}
aria-label={i18next.t("Copy link")}
size="small"
icon
labelPosition="left"
>
<Icon name="copy outline" />
{i18next.t("Copy link")}
</Button>
}
/>
</Table.Cell>
</>
)}
</Table.Row>
);
};

LinksSearchItem.propTypes = {
result: PropTypes.object.isRequired,
record: PropTypes.object.isRequired,
fetchData: PropTypes.func.isRequired,
onItemAddedOrDeleted: PropTypes.func.isRequired,
onPermissionChanged: PropTypes.func.isRequired,
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,30 @@ export const dropdownOptions = [
{
key: "view",
name: "view",
text: i18next.t("Can view"),
title: i18next.t("Can view"),
text: i18next.t("Can view all versions"),
title: i18next.t("Can view all versions"),
value: "view",
description: i18next.t("Can view restricted records/files."),
description: i18next.t("Can view restricted files of all versions of this record."),
},
{
key: "preview",
name: "preview",
text: i18next.t("Can preview"),
title: i18next.t("Can preview"),
text: i18next.t("Can preview all drafts"),
title: i18next.t("Can preview all drafts"),
value: "preview",
description: i18next.t("Can view drafts and restricted records/files."),
description: i18next.t(
"Can view drafts and restricted files of all versions of this record."
),
},
{
key: "edit",
name: "edit",
text: i18next.t("Can edit"),
title: i18next.t("Can edit"),
text: i18next.t("Can edit all versions"),
title: i18next.t("Can edit all versions"),
value: "edit",
description: i18next.t("Can edit drafts and view restricted records/files."),
description: i18next.t(
"Can edit drafts and view restricted files of all versions of this record."
),
},
];

Expand Down Expand Up @@ -92,7 +96,7 @@ export class LinksSearchResultContainer extends Component {
};

handleCreation = async (permission, expiresAt, description) => {
const { fetchData, record } = this.props;
const { onItemAddedOrDeleted, record } = this.props;
this.setState({ loading: true });
try {
const data = {
Expand All @@ -102,7 +106,7 @@ export class LinksSearchResultContainer extends Component {
};
this.cancellableAction = withCancel(http.post(record.links.access_links, data));
await this.cancellableAction.promise;
fetchData();
onItemAddedOrDeleted(record.links.access_links, "links");
this.setState({ loading: false, error: undefined });
} catch (error) {
if (error === "UNMOUNTED") return;
Expand All @@ -115,7 +119,7 @@ export class LinksSearchResultContainer extends Component {
};

render() {
const { results, record, fetchData } = this.props;
const { results, record, onItemAddedOrDeleted, onPermissionChanged } = this.props;
const { loading, error } = this.state;
return (
<>
Expand Down Expand Up @@ -148,7 +152,8 @@ export class LinksSearchResultContainer extends Component {
key={result.id}
result={result}
record={record}
fetchData={fetchData}
onItemAddedOrDeleted={onItemAddedOrDeleted}
onPermissionChanged={onPermissionChanged}
/>
))
) : (
Expand All @@ -174,5 +179,6 @@ export class LinksSearchResultContainer extends Component {
LinksSearchResultContainer.propTypes = {
results: PropTypes.array.isRequired,
record: PropTypes.object.isRequired,
fetchData: PropTypes.func.isRequired,
onItemAddedOrDeleted: PropTypes.func.isRequired,
onPermissionChanged: PropTypes.func.isRequired,
};
Loading

0 comments on commit 8d13662

Please sign in to comment.