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

administration: add overridable administration views #1161

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion invenio_rdm_records/administration/views/oai.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class OaiPmhListView(AdminResourceListView):
pid_path = "id"
icon = "exchange"
template = "invenio_rdm_records/oai-search.html"
app_id = "InvenioRdmRecords.AdministrationOaipmhListView"

display_search = True
display_delete = True
Expand Down Expand Up @@ -58,6 +59,7 @@ class OaiPmhEditView(AdminResourceEditView):
pid_path = "id"
api_endpoint = "/oaipmh/sets"
title = "Edit OAI-PMH set"
app_id = "InvenioRdmRecords.AdministrationOaipmhEditView"

list_view_name = "OAI-PMH"

Expand Down Expand Up @@ -98,6 +100,7 @@ class OaiPmhCreateView(AdminResourceCreateView):
pid_path = "id"
api_endpoint = "/oaipmh/sets"
title = "Create OAI-PMH set"
app_id = "InvenioRdmRecords.AdministrationOaipmhCreateView"

list_view_name = "OAI-PMH"

Expand Down Expand Up @@ -135,7 +138,7 @@ class OaiPmhDetailView(AdminResourceDetailView):
name = "OAI-PMH details"
resource_config = "oaipmh_server_resource"
title = "OAI-PMH Details"

app_id = "InvenioRdmRecords.AdministrationOaipmhDetailView"
template = "invenio_rdm_records/oai-details.html"
display_delete = True
display_edit = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import React from "react";
import ReactDOM from "react-dom";
import _get from "lodash/get";
import { OverridableContext, parametrize } from "react-overridable";
import { OverridableContext, parametrize, overrideStore } from "react-overridable";
import LinksTable from "./LinksTable";
import { AdminDetailsView, Edit, Delete } from "@js/invenio_administration";
import { i18next } from "@translations/invenio_rdm_records/i18next";
Expand All @@ -24,27 +24,30 @@ const apiEndpoint = _get(domContainer.dataset, "apiEndpoint");
const idKeyPath = JSON.parse(_get(domContainer.dataset, "pidPath", "pid"));
const listUIEndpoint = domContainer.dataset.listEndpoint;
const resourceSchema = JSON.parse(domContainer.dataset.resourceSchema);
const appName = JSON.parse(domContainer.dataset.appId);

const createdBySystem = (data) => data?.system_created;

const overridenComponents = {
"InvenioAdministration.EditAction": parametrize(Edit, {
const defaultComponents = {
[`${appName}.EditAction`]: parametrize(Edit, {
disable: createdBySystem,
disabledMessage: i18next.t(
"This set is not editable as it was created by the system."
),
}),
"InvenioAdministration.DeleteAction": parametrize(Delete, {
[`${appName}.DeleteAction`]: parametrize(Delete, {
disable: createdBySystem,
disabledMessage: i18next.t(
"This set is not deletable as it was created by the system."
),
}),
};

const overriddenComponents = overrideStore.getAll();
console.log("asdad appname: ", appName);
domContainer &&
ReactDOM.render(
<OverridableContext.Provider value={overridenComponents}>
<OverridableContext.Provider value={{ ...defaultComponents, ...overriddenComponents }}>
<AdminDetailsView
title={title}
actions={actions}
Expand All @@ -57,6 +60,7 @@ domContainer &&
resourceName={resourceName}
listUIEndpoint={listUIEndpoint}
resourceSchema={resourceSchema}
appNmae={appName}
>
<LinksTable />
</AdminDetailsView>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,10 @@ import React, { Component } from "react";
import { Table } from "semantic-ui-react";
import isEmpty from "lodash/isEmpty";
import { withState } from "react-searchkit";
import { Actions, Edit, Delete } from "@js/invenio_administration";
import { Actions } from "@js/invenio_administration";
import { AdminUIRoutes } from "@js/invenio_administration";
import { OverridableContext, parametrize } from "react-overridable";
import { DeleteModal } from "./DeleteModal";
import Formatter from "@js/invenio_administration/src/components/Formatter";
import { i18next } from "@translations/invenio_rdm_records/i18next";

const overridenComponents = {
"InvenioAdministration.DeleteModal.layout": DeleteModal,
};

class SearchResultItemComponent extends Component {
refreshAfterAction = () => {
Expand Down Expand Up @@ -62,80 +56,61 @@ class SearchResultItemComponent extends Component {
apiEndpoint,
idKeyPath,
listUIEndpoint,
appName
} = this.props;

const resourceHasActions =
displayEdit || displayDelete || !isEmpty(actions);

overridenComponents["InvenioAdministration.EditAction"] = parametrize(
Edit,
{
disable: () => result.system_created,
disabledMessage: i18next.t(
"This set is not editable as it was created by the system."
),
}
);

overridenComponents["InvenioAdministration.DeleteAction"] = parametrize(
Delete,
{
disable: () => result.system_created,
disabledMessage: i18next.t(
"This set is not deletable as it was created by the system."
),
}
);

return (
<OverridableContext.Provider value={overridenComponents}>
<Table.Row>
{columns.map(([property, { text, order }], index) => {
return (
<Table.Cell
key={`${text}-${order}`}
data-label={text}
className="word-break-all"
>
{index === 0 ? (
<a
href={AdminUIRoutes.detailsView(
listUIEndpoint,
result,
idKeyPath
)}
>
{this.displayAsPre(result, property)}
</a>
) : (
this.displayAsPre(result, property)
)}
</Table.Cell>
);
})}
{resourceHasActions && (
<Table.Cell>
<Actions
title={title}
resourceName={resourceName}
apiEndpoint={apiEndpoint}
actions={actions}
editUrl={AdminUIRoutes.editView(
listUIEndpoint,
result,
idKeyPath
)}
displayEdit={displayEdit}
displayDelete={displayDelete}
resource={result}
idKeyPath={idKeyPath}
successCallback={this.refreshAfterAction}
listUIEndpoint={listUIEndpoint}
/>
<Table.Row>
{columns.map(([property, { text, order }], index) => {
return (
<Table.Cell
key={`${text}-${order}`}
data-label={text}
className="word-break-all"
>
{index === 0 ? (
<a
href={AdminUIRoutes.detailsView(
listUIEndpoint,
result,
idKeyPath
)}
>
{this.displayAsPre(result, property)}
</a>
) : (
this.displayAsPre(result, property)
)}
</Table.Cell>
)}
</Table.Row>
</OverridableContext.Provider>
);
})}
{resourceHasActions && (
<Table.Cell>
<Actions
title={title}
resourceName={resourceName}
apiEndpoint={apiEndpoint}
actions={actions}
editUrl={AdminUIRoutes.editView(
listUIEndpoint,
result,
idKeyPath
)}
displayEdit={displayEdit}
displayDelete={displayDelete}
resource={result}
idKeyPath={idKeyPath}
successCallback={this.refreshAfterAction}
listUIEndpoint={listUIEndpoint}
appName={appName}
/>
</Table.Cell>
)}
</Table.Row>
);
}
}
Expand All @@ -154,13 +129,15 @@ SearchResultItemComponent.propTypes = {
idKeyPath: PropTypes.string.isRequired,
listUIEndpoint: PropTypes.string.isRequired,
resourceSchema: PropTypes.object.isRequired,
appName: PropTypes.string,
};

SearchResultItemComponent.defaultProps = {
displayDelete: true,
displayEdit: true,
apiEndpoint: undefined,
actions: {},
appName: "",
};

export const SearchResultItem = withState(SearchResultItemComponent);
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@
// Invenio RDM is free software; you can redistribute it and/or modify it
// under the terms of the MIT License; see LICENSE file for more details.

import { initDefaultSearchComponents } from "@js/invenio_administration";
import React from "react";
import { initDefaultSearchComponents, Edit, Delete, DeleteModalTrigger } from "@js/invenio_administration";
import { createSearchAppInit } from "@js/invenio_search_ui";
import { SearchResultItem } from "./SearchResultItem";
import { parametrize } from "react-overridable";
import { parametrize, overrideStore } from "react-overridable";
import _get from "lodash/get";
import { NotificationController } from "@js/invenio_administration";
import { DeleteModal } from "./DeleteModal";
import { i18next } from "@translations/invenio_rdm_records/i18next";
import { Popup, Button, Icon } from "semantic-ui-react";

const domContainer = document.getElementById("invenio-search-config");

const appName = "InvenioRdmRecords.AdministrationOaipmhListView";

const sortColumns = (columns) =>
Object.entries(columns).sort((a, b) => a[1].order - b[1].order);
const title = JSON.parse(domContainer.dataset.title);
Expand All @@ -28,7 +34,7 @@ const idKeyPath = JSON.parse(_get(domContainer.dataset, "pidPath", "pid"));
const listUIEndpoint = domContainer.dataset.listEndpoint;
const resourceSchema = JSON.parse(domContainer.dataset.resourceSchema);

const defaultComponents = initDefaultSearchComponents(domContainer);
const defaultComponents = initDefaultSearchComponents(domContainer, appName);
const SearchResultItemWithConfig = parametrize(SearchResultItem, {
title: title,
resourceName: resourceName,
Expand All @@ -41,17 +47,113 @@ const SearchResultItemWithConfig = parametrize(SearchResultItem, {
idKeyPath: idKeyPath,
listUIEndpoint: listUIEndpoint,
resourceSchema: resourceSchema,
appName: appName,
});

const overridenComponents = {
const createdBySystem = (data) => data?.system_created;


// const EditSet = parametrize(
// Edit,
// {
// disable: createdBySystem,
// disabledMessage: i18next.t(
// "This set is not editable as it was created by the system."
// ),
// // appName: appName,
// }
// );

const EditSet = (props) => {
const { display, editUrl, disabled, resource, appName } = props;
const disabledMessage = i18next.t(
"This set is not editable as it was created by the system."
)
return (
<Popup
content={disabledMessage}
disabled={!createdBySystem(resource)}
trigger={
<span className="mr-5">
<Button
as="a"
disabled={createdBySystem(resource)}
href={editUrl}
icon
labelPosition="left"
>
<Icon name="pencil" />
{i18next.t("Edit")}
</Button>
</span>
}
/>
)
}

// const DeleteSet = parametrize(
// Delete,
// {
// disable: createdBySystem,
// disabledMessage: i18next.t(
// "This set is not deletable as it was created by the system."
// ),
// appName: appName,
// }
// );

const DeleteSet = (props) => {
const {
disable,
title,
resourceName,
successCallback,
idKeyPath,
resource,
appName
} = props
const disabledMessage = i18next.t(
"This set is not deletable as it was created by the system."
)
return (
<Popup
content={disabledMessage}
disabled={!disable}
trigger={
<span>
<DeleteModalTrigger
title={title}
resourceName={resourceName}
resource={resource}
successCallback={successCallback}
idKeyPath={idKeyPath}
disabled={createdBySystem(resource)}
apiEndpoint={_get(resource, "links.self")}
disabledDeleteMessage={disabledMessage}
appName={appName}
/>
</span>
}
/>
)

}


const overriddenDefaultComponents = {
...defaultComponents,
"ResultsList.item": SearchResultItemWithConfig,
[`${appName}.ResultsList.item`]: SearchResultItemWithConfig,
[`${appName}.EditAction.layout`]: EditSet,
[`${appName}.DeleteAction.layout`]: DeleteSet,
[`${appName}.DeleteModal.layout`]: DeleteModal,
};

const overriddenComponents = overrideStore.getAll();

createSearchAppInit(
overridenComponents,
{ ...overriddenDefaultComponents, ...overriddenComponents },
true,
"invenio-search-config",
false,
true,
NotificationController
);