From b2ea485e439a2a287b4a389b223863817631dd4a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Wed, 29 May 2024 11:00:22 +0200
Subject: [PATCH 01/73] Request detail init
---
.gitignore | 6 +++--
oarepo_requests/resolvers/ui.py | 21 +++++++++---------
.../ui/{__init__.py => __init__ .py} | 0
.../oarepo_requests_ui/RequestDetail.jinja | 15 +++++++++++++
.../request-detail/index.js | 11 ++++++++++
oarepo_requests/ui/theme/webpack.py | 1 +
oarepo_requests/ui/views.py | 22 +++++++++++++++++--
setup.cfg | 2 +-
8 files changed, 62 insertions(+), 16 deletions(-)
rename oarepo_requests/ui/{__init__.py => __init__ .py} (100%)
create mode 100644 oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/index.js
diff --git a/.gitignore b/.gitignore
index a5f3201c..398fc710 100644
--- a/.gitignore
+++ b/.gitignore
@@ -90,5 +90,7 @@ dist/
tests/thesis
thesis
-**/ui/theme/**/todo.md
-node_modules
\ No newline at end of file
+todo.md
+node_modules
+
+dummy-record.js
\ No newline at end of file
diff --git a/oarepo_requests/resolvers/ui.py b/oarepo_requests/resolvers/ui.py
index 73c5a95a..4c3c3426 100644
--- a/oarepo_requests/resolvers/ui.py
+++ b/oarepo_requests/resolvers/ui.py
@@ -76,10 +76,10 @@ def _get_id(self, result):
def _search_many(self, identity, values, *args, **kwargs):
result = []
- for user in values:
+ for group in values:
try:
- user = current_groups_service.read(identity, user)
- result.append(user)
+ group = current_groups_service.read(identity, group)
+ result.append(group)
except PermissionDeniedError:
pass
return result
@@ -87,23 +87,22 @@ def _search_many(self, identity, values, *args, **kwargs):
def _search_one(self, identity, reference, *args, **kwargs):
value = list(reference.values())[0]
try:
- user = current_groups_service.read(identity, value)
- return user
+ group = current_groups_service.read(identity, value)
+ return group
except PermissionDeniedError:
return None
def _resolve(self, record, reference):
- # todo; this is copyied from user
- if record.data["username"] is None: # username undefined?
- if "email" in record.data:
- label = record.data["email"]
+ if record.data["name"] is None:
+ if "id" in record.data:
+ label = record.data["id"]
else:
label = fallback_label_result(reference)
else:
- label = record.data["username"]
+ label = record.data["name"]
ret = {
"reference": reference,
- "type": "user",
+ "type": "group",
"label": label,
}
if "links" in record.data and "self" in record.data["links"]:
diff --git a/oarepo_requests/ui/__init__.py b/oarepo_requests/ui/__init__ .py
similarity index 100%
rename from oarepo_requests/ui/__init__.py
rename to oarepo_requests/ui/__init__ .py
diff --git a/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja b/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja
new file mode 100644
index 00000000..07a0a960
--- /dev/null
+++ b/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja
@@ -0,0 +1,15 @@
+{#def record #}
+
+{%- extends config.BASE_TEMPLATE %}
+
+{%- block javascript %}
+ {{super()}}
+ {{webpack["oarepo_requests_ui_request_detail.js"]}}
+ {{webpack["oarepo_requests_ui_components.js"]}}
+ {{webpack["oarepo_requests_ui_components.css"]}}
+{%- endblock javascript %}
+
+{%- block page_body %}
+ {{ record | pprint }}
+
+{%- endblock page_body %}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/index.js b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/index.js
new file mode 100644
index 00000000..f0ab6728
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/index.js
@@ -0,0 +1,11 @@
+import React from "react";
+import ReactDOM from "react-dom";
+
+const recordRequestsAppDiv = document.getElementById("request-detail");
+
+let request = JSON.parse(recordRequestsAppDiv.dataset?.request);
+
+ReactDOM.render(
+ Hello World!
,
+ recordRequestsAppDiv
+);
\ No newline at end of file
diff --git a/oarepo_requests/ui/theme/webpack.py b/oarepo_requests/ui/theme/webpack.py
index 7dbcd021..530ef1d9 100644
--- a/oarepo_requests/ui/theme/webpack.py
+++ b/oarepo_requests/ui/theme/webpack.py
@@ -8,6 +8,7 @@
"semantic-ui": dict(
entry={
"oarepo_requests_ui_record_requests": "./js/oarepo_requests_ui/record-requests/index.js",
+ "oarepo_requests_ui_request_detail": "./js/oarepo_requests_ui/request-detail/index.js",
"oarepo_requests_ui_components": "./js/oarepo_requests_ui/custom-components.js",
},
dependencies={},
diff --git a/oarepo_requests/ui/views.py b/oarepo_requests/ui/views.py
index 9c2a462b..082e851e 100644
--- a/oarepo_requests/ui/views.py
+++ b/oarepo_requests/ui/views.py
@@ -1,3 +1,21 @@
-from flask import Blueprint
+from oarepo_ui.resources.config import RecordsUIResourceConfig
+from oarepo_ui.resources.resource import RecordsUIResource
-blueprint = Blueprint("oarepo_requests_ui", __name__, template_folder="templates")
+class RequestUIResourceConfig(RecordsUIResourceConfig):
+ url_prefix = "/requests"
+ blueprint_name = "oarepo_requests_ui"
+ template_folder = "templates"
+ templates = {
+ "detail": "RequestDetail",
+ }
+ api_service = "requests"
+ ui_serializer_class = "oarepo_requests.resources.ui.OARepoRequestsUIJSONSerializer"
+
+
+class RequestUIResource(RecordsUIResource):
+ pass
+
+
+def create_blueprint(app):
+ """Register blueprint for this resource."""
+ return RequestUIResource(RequestUIResourceConfig()).as_blueprint()
diff --git a/setup.cfg b/setup.cfg
index bff81c10..ba9391b2 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -42,7 +42,7 @@ invenio_base.api_blueprints =
invenio_base.blueprints =
oarepo_requests = oarepo_requests.views.app:create_app_blueprint
oarepo_requests_events = oarepo_requests.views.app:create_app_events_blueprint
- oarepo_requests_ui = oarepo_requests.ui.views:blueprint
+ oarepo_requests_ui = oarepo_requests.ui.views:create_blueprint
invenio_assets.webpack =
oarepo_requests_ui_theme = oarepo_requests.ui.theme.webpack:theme
invenio_i18n.translations =
From 1fd93174b7b961c271a551b94e656104086d47b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Wed, 29 May 2024 13:37:23 +0200
Subject: [PATCH 02/73] Initial UI
---
.../oarepo_requests_ui/RequestDetail.jinja | 14 ++-
.../record-requests/components/index.js | 3 +-
.../components/RequestDetail.jsx | 104 +++++++++++++++++
.../components/SideRequestInfo.jsx | 46 ++++++++
.../request-detail/components/index.js | 2 +
.../request-detail/index.js | 8 +-
.../request-detail/types.d.ts | 107 ++++++++++++++++++
7 files changed, 274 insertions(+), 10 deletions(-)
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/types.d.ts
diff --git a/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja b/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja
index 07a0a960..7ebbec5b 100644
--- a/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja
+++ b/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja
@@ -1,6 +1,13 @@
{#def record #}
-{%- extends config.BASE_TEMPLATE %}
+{%- set title = _("Request") ~ " | " ~ _("NR Document repository") %}
+
+{% extends "oarepo_ui/detail.html" %}
+
+{%- block page_body %}
+
+ {{ record | pprint }}
+{%- endblock page_body %}
{%- block javascript %}
{{super()}}
@@ -8,8 +15,3 @@
{{webpack["oarepo_requests_ui_components.js"]}}
{{webpack["oarepo_requests_ui_components.css"]}}
{%- endblock javascript %}
-
-{%- block page_body %}
- {{ record | pprint }}
-
-{%- endblock page_body %}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/index.js b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/index.js
index 9272a0c3..1387b4f8 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/index.js
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/index.js
@@ -5,4 +5,5 @@ export { RecordRequests } from "./RecordRequests";
export { RequestModalContent } from "./RequestModalContent";
export { CreateRequestModalContent } from "./CreateRequestModalContent";
export { RequestList } from "./RequestList";
-export { ModalContentSideInfo } from "./ModalContentSideInfo";
\ No newline at end of file
+export { ModalContentSideInfo } from "./ModalContentSideInfo";
+export * from "./common";
\ No newline at end of file
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
new file mode 100644
index 00000000..08c517d3
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
@@ -0,0 +1,104 @@
+import React from "react";
+import PropTypes from "prop-types";
+
+import { i18next } from "@translations/oarepo_requests_ui/i18next";
+import { Button, Grid, List, Form, Divider, Comment, Header, Container, Icon } from "semantic-ui-react";
+import _isEmpty from "lodash/isEmpty";
+import _sortBy from "lodash/sortBy";
+
+import { ReadOnlyCustomFields } from "@js/oarepo_requests/components";
+import { SideRequestInfo } from ".";
+
+export const RequestDetail = ({ request }) => {
+ const requestModalHeader = !_isEmpty(request?.title) ? request.title : (!_isEmpty(request?.name) ? request.name : request.type);
+ const renderReadOnlyData = !_isEmpty(request?.payload);
+
+ return (
+
+
+
+
+ {request?.description &&
+
+ {request.description}
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ {renderReadOnlyData &&
+
+ {Object.keys(request.payload).map(key => (
+
+
+ {key}
+ import(`../components/common/${widget}.jsx`),
+ (widget) => import(`react-invenio-forms`)
+ ]}
+ />
+
+
+ ))}
+
+ }
+ {/* If events are enabled for this request type, you can see the timeline of events and create new events. */}
+ {/* {!_isEmpty(eventTypes) &&
+ <>
+ {i18next.t("Timeline")}
+ {!_isEmpty(events) &&
+
+ {events.map(event => {
+ const eventPayloadUI = eventTypes.filter(eventType => eventType.id === event.type_code)[0]?.payload_ui;
+ return (
+
+
+ {event.created_by.label}
+
+ {event?.created}
+
+
+ import(`./${widget}.jsx`),
+ (widget) => import(`react-invenio-forms`)
+ ]}
+ // fieldPathPrefix="payload"
+ />
+
+
+
+ )
+ })}
+
+ }
+ {eventTypes.map(event => (
+ } />
+ ))}
+ >
+ } */}
+
+
+
+
+
+
+ );
+}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
new file mode 100644
index 00000000..1347815c
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
@@ -0,0 +1,46 @@
+import React from "react";
+
+import { i18next } from "@translations/oarepo_requests_ui/i18next";
+import { List } from "semantic-ui-react";
+
+/**
+ * @typedef {import("../types").Request} Request
+ */
+
+/** @param {{ request: Request }} props */
+export const SideRequestInfo = ({ request }) => {
+ return (
+
+
+
+ {i18next.t("Creator")}
+ {request.created_by?.link && {request.created_by.label} || request.created_by?.label}
+
+
+
+
+ {i18next.t("Receiver")}
+ {request.receiver?.link && {request.receiver?.label} || request.receiver?.label}
+
+
+
+
+ {i18next.t("Request type")}
+ {request?.type}
+
+
+
+
+ {i18next.t("Status")}
+ {request?.status}
+
+
+
+
+ {i18next.t("Created")}
+ {request?.created}
+
+
+
+ )
+};
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
new file mode 100644
index 00000000..838d5e7c
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
@@ -0,0 +1,2 @@
+export { RequestDetail } from './RequestDetail';
+export { SideRequestInfo } from './SideRequestInfo';
\ No newline at end of file
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/index.js b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/index.js
index f0ab6728..427e81cb 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/index.js
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/index.js
@@ -1,11 +1,13 @@
import React from "react";
import ReactDOM from "react-dom";
+import { RequestDetail } from "./components";
+
const recordRequestsAppDiv = document.getElementById("request-detail");
-let request = JSON.parse(recordRequestsAppDiv.dataset?.request);
+let request = recordRequestsAppDiv.dataset?.request ? JSON.parse(recordRequestsAppDiv.dataset.request) : {};
ReactDOM.render(
- Hello World!
,
+ ,
recordRequestsAppDiv
-);
\ No newline at end of file
+);
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/types.d.ts b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/types.d.ts
new file mode 100644
index 00000000..593fcc45
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/types.d.ts
@@ -0,0 +1,107 @@
+export interface Request {
+ name: string;
+ description: string;
+ id: string;
+ title: string;
+ type: string;
+ links: Links;
+ created_by: Creator;
+ receiver: Receiver;
+ topic: Receiver;
+ created: string; // Datetime
+ updated: string; // Datetime
+ events?: Event[];
+}
+
+export interface Links {
+ actions?: RequestActions;
+ self: string;
+ self_html?: string;
+ events?: string;
+}
+
+export interface RequestActions {
+ create?: string;
+ submit?: string;
+ cancel?: string;
+ accept?: string;
+ decline?: string;
+ expire?: string;
+ delete?: string;
+}
+
+export interface Creator {
+ reference: string;
+ type: string;
+ label: string;
+ link: string;
+}
+
+export interface Receiver {
+ reference: Reference;
+ type: string;
+ label: string;
+ link: string;
+}
+
+export interface Reference {
+ id: string;
+}
+
+export interface RequestType {
+ name: string;
+ description: string;
+ id: string;
+ links: Links;
+ fast_approve?: boolean;
+ payload_ui?: PayloadUI[];
+ event_types?: EventType[];
+}
+
+export interface PayloadUI {
+ section: string;
+ fields: Field[];
+}
+
+export interface Field {
+ field: string;
+ ui_widget: "Input" | "NumberInput" | "MultiInput" | "RichInput" | "TextArea" | "Dropdown" | "AutocompleteDropdown" | "BooleanCheckbox";
+ visible: ("requestor" | "approver")[];
+ editable: ("requestor" | "approver")[];
+ props: React.ComponentProps;
+}
+
+export interface EventType {
+ name: string;
+ description: string;
+ id: string;
+ links: Links;
+ payload_ui?: PayloadUI[];
+}
+
+export interface Event {
+ payload: any;
+ created: string; // Datetime
+ created_by: Creator;
+ updated: string; // Datetime
+ revision_id: number;
+ id: string;
+ type_code: string;
+ type: string;
+ links: Links;
+ permissions: Permissions;
+}
+
+export interface Permissions {
+ can_update_comment: boolean;
+ can_delete_comment: boolean;
+}
+
+export enum RequestTypeEnum {
+ CREATE = "create",
+ SUBMIT = "submit",
+ CANCEL = "cancel",
+ ACCEPT = "accept",
+ DECLINE = "decline",
+ SAVE = "save",
+}
From 9b998c32105e5c64c4002053628525ea23393552 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Wed, 29 May 2024 17:20:47 +0200
Subject: [PATCH 03/73] UI changes
---
.../components/ActionButtons.jsx | 64 +++++++++
.../components/ConfirmModal.jsx | 127 ++++++++++++++++++
.../components/RequestDetail.jsx | 6 +-
.../components/SideRequestInfo.jsx | 79 ++++++-----
.../request-detail/components/index.js | 4 +-
5 files changed, 242 insertions(+), 38 deletions(-)
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ActionButtons.jsx
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ActionButtons.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ActionButtons.jsx
new file mode 100644
index 00000000..10c0804d
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ActionButtons.jsx
@@ -0,0 +1,64 @@
+import React from "react";
+import PropTypes from "prop-types";
+
+import { i18next } from "@translations/oarepo_requests_ui/i18next";
+import { Button, Grid, List, Form, Divider, Comment, Header, Container, Icon } from "semantic-ui-react";
+import _isEmpty from "lodash/isEmpty";
+import _sortBy from "lodash/sortBy";
+import _has from "lodash/has";
+import axios from "axios";
+
+// import { isDeepEmpty } from "@js/oarepo_requests/utils";
+import { ConfirmModal } from ".";
+
+const callApi = async (url, method = "GET", data = null) => {
+ if (_isEmpty(url)) {
+ console.log("URL parameter is missing or invalid.");
+ }
+ data = { data: data };
+ if (_isEmpty(data.data?.payload?.content)) {
+ data = null;
+ }
+ return axios({
+ url: url,
+ method: method,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/vnd.inveniordm.v1+json'
+ },
+ ...data
+})};
+
+export const ActionButtons = ({ request }) => {
+ return (
+ <>
+ {request.links?.actions?.accept &&
+ callApi(request.links.actions.accept, "POST", values)}
+ triggerButton={
+
+ }
+ />
+ }
+ {request.links?.actions?.cancel &&
+ callApi(request.links.actions.cancel, "POST", values)}
+ triggerButton={
+
+ }
+ submitButton={
+
+ }
+ />
+ }
+ {request.links?.actions?.decline &&
+ callApi(request.links.actions.decline, "POST", values)}
+ triggerButton={
+
+ }
+ />
+ }
+ >
+ );
+}
\ No newline at end of file
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
new file mode 100644
index 00000000..4ba7676f
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
@@ -0,0 +1,127 @@
+import React, { useState, useEffect, useRef } from "react";
+import PropTypes from "prop-types";
+
+import { i18next } from "@translations/oarepo_requests_ui/i18next";
+import { Dimmer, Loader, Modal, Button, Icon, Message, Divider, FormTextArea, FormField } from "semantic-ui-react";
+import _isEmpty from "lodash/isEmpty";
+import _isFunction from "lodash/isFunction";
+
+import { Formik, Field, Form, ErrorMessage } from "formik";
+import * as Yup from 'yup';
+import { delay } from "bluebird";
+
+/**
+ * @typedef {import("../types").Request} Request
+ * @typedef {import("../types").RequestType} RequestType
+ * @typedef {import("../types").RequestTypeEnum} RequestTypeEnum
+ * @typedef {import("react").ReactElement} ReactElement
+ * @typedef {import("semantic-ui-react").ConfirmProps} ConfirmProps
+ */
+
+/** @param {{ request: Request, requestModalHeader: string, handleSubmit: (v) => Promise, triggerButton: ReactElement, submitButton: ReactElement }} props */
+export const ConfirmModal = ({ request, requestModalHeader, handleSubmit, triggerButton, submitButton }) => {
+ const [modalOpen, setModalOpen] = useState(false);
+ const [error, setError] = useState(null);
+
+ const errorMessageRef = useRef(null);
+
+ useEffect(() => {
+ if (error) {
+ errorMessageRef.current?.scrollIntoView({ behavior: "smooth" });
+ }
+ }, [error]);
+
+ const onClose = () => {
+ setModalOpen(false);
+ setError(null);
+ };
+
+ const onSubmit = async (values, { setSubmitting }) => {
+ try {
+ console.log("Sending request");
+ await delay(1000);
+ _isFunction(handleSubmit) && await handleSubmit(values);
+ } catch (error) {
+ setError(error);
+ } finally {
+ setSubmitting(false);
+ }
+ }
+
+ const PayloadSchema = Yup.object().shape({
+ payload: Yup.object().shape({
+ content: Yup.string()
+ .min(1, 'Too Short!')
+ })
+ });
+
+ return (
+ setModalOpen(true)}
+ open={modalOpen}
+ trigger={triggerButton || }
+ closeOnDocumentClick={false}
+ closeOnDimmerClick={false}
+ role="dialog"
+ aria-labelledby="request-modal-header"
+ >
+
+ {({ isSubmitting, errors, touched }) => (
+ <>
+
+
+
+
+
+ {error &&
+
+ {i18next.t("Error")}
+ {error?.message}
+
+ }
+
+
+
+
+ {submitButton ?? React.cloneElement(triggerButton, { type: "submit", form: "submit-request-form" })}
+
+ >
+ )}
+
+
+ );
+};
+
+ConfirmModal.propTypes = {
+ request: PropTypes.object.isRequired,
+ requestModalHeader: PropTypes.string,
+ handleSubmit: PropTypes.func,
+ triggerButton: PropTypes.element,
+ submitButton: PropTypes.element,
+};
\ No newline at end of file
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
index 08c517d3..a56f7521 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
@@ -7,7 +7,7 @@ import _isEmpty from "lodash/isEmpty";
import _sortBy from "lodash/sortBy";
import { ReadOnlyCustomFields } from "@js/oarepo_requests/components";
-import { SideRequestInfo } from ".";
+import { SideRequestInfo, ActionButtons } from ".";
export const RequestDetail = ({ request }) => {
const requestModalHeader = !_isEmpty(request?.title) ? request.title : (!_isEmpty(request?.name) ? request.name : request.type);
@@ -25,9 +25,7 @@ export const RequestDetail = ({ request }) => {
}
-
-
-
+
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
index 1347815c..eba50182 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
@@ -1,7 +1,7 @@
import React from "react";
import { i18next } from "@translations/oarepo_requests_ui/i18next";
-import { List } from "semantic-ui-react";
+import { Header, Divider, Icon, Label } from "semantic-ui-react";
/**
* @typedef {import("../types").Request} Request
@@ -10,37 +10,50 @@ import { List } from "semantic-ui-react";
/** @param {{ request: Request }} props */
export const SideRequestInfo = ({ request }) => {
return (
-
-
-
- {i18next.t("Creator")}
- {request.created_by?.link && {request.created_by.label} || request.created_by?.label}
-
-
-
-
- {i18next.t("Receiver")}
- {request.receiver?.link && {request.receiver?.label} || request.receiver?.label}
-
-
-
-
- {i18next.t("Request type")}
- {request?.type}
-
-
-
-
- {i18next.t("Status")}
- {request?.status}
-
-
-
-
- {i18next.t("Created")}
- {request?.created}
-
-
-
+ <>
+
+ {i18next.t("Creator")}
+
+
+
+
+
+
+ {i18next.t("Receiver")}
+
+
+
+
+
+
+ {i18next.t("Request type")}
+
+
+
+
+
+
+ {i18next.t("Status")}
+
+
+
+ {request?.status}
+
+
+
+
+
+ {i18next.t("Created")}
+
+ {request?.created}
+
+
+ >
)
};
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
index 838d5e7c..875bc427 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
@@ -1,2 +1,4 @@
export { RequestDetail } from './RequestDetail';
-export { SideRequestInfo } from './SideRequestInfo';
\ No newline at end of file
+export { SideRequestInfo } from './SideRequestInfo';
+export { ActionButtons } from './ActionButtons';
+export { ConfirmModal } from './ConfirmModal';
\ No newline at end of file
From 1e15f70890ea3bdd476066fe170ec9a33b69af59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Mon, 3 Jun 2024 12:16:59 +0200
Subject: [PATCH 04/73] Menu switch
---
.../components/ConfirmModal.jsx | 2 +-
.../components/MainRequestDetails.jsx | 86 +++++++++++++++++
.../components/RequestDetail.jsx | 93 +++++--------------
.../request-detail/components/index.js | 3 +-
4 files changed, 110 insertions(+), 74 deletions(-)
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
index 4ba7676f..475cbe5e 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
@@ -78,7 +78,7 @@ export const ConfirmModal = ({ request, requestModalHeader, handleSubmit, trigge
validationSchema={PayloadSchema}
onSubmit={onSubmit}
>
- {({ isSubmitting, errors, touched }) => (
+ {({ isSubmitting }) => (
<>
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
new file mode 100644
index 00000000..7fe3376b
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
@@ -0,0 +1,86 @@
+import React, { useState } from "react";
+import PropTypes from "prop-types";
+
+import { i18next } from "@translations/oarepo_requests_ui/i18next";
+import { Button, Grid, List, Form, Divider, Comment, Header, Container, Icon, Menu } from "semantic-ui-react";
+import _isEmpty from "lodash/isEmpty";
+import _sortBy from "lodash/sortBy";
+
+import { ReadOnlyCustomFields } from "@js/oarepo_requests/components";
+import { SideRequestInfo } from ".";
+
+export const MainRequestDetails = ({ request }) => {
+ const renderReadOnlyData = !_isEmpty(request?.payload);
+
+ return (
+
+
+
+
+
+ {renderReadOnlyData &&
+
+ {Object.keys(request.payload).map(key => (
+
+
+ {key}
+ import(`@js/oarepo_requests/components/common/${widget}.jsx`),
+ (widget) => import(`react-invenio-forms`)
+ ]}
+ />
+
+
+ ))}
+
+ }
+ {/* If events are enabled for this request type, you can see the timeline of events and create new events. */}
+ {/* {!_isEmpty(eventTypes) &&
+ <>
+ {i18next.t("Timeline")}
+ {!_isEmpty(events) &&
+
+ {events.map(event => {
+ const eventPayloadUI = eventTypes.filter(eventType => eventType.id === event.type_code)[0]?.payload_ui;
+ return (
+
+
+ {event.created_by.label}
+
+ {event?.created}
+
+
+ import(`./${widget}.jsx`),
+ (widget) => import(`react-invenio-forms`)
+ ]}
+ // fieldPathPrefix="payload"
+ />
+
+
+
+ )
+ })}
+
+ }
+ {eventTypes.map(event => (
+ } />
+ ))}
+ >
+ } */}
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
index a56f7521..0f7186d8 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
@@ -1,17 +1,17 @@
-import React from "react";
+import React, { useState } from "react";
import PropTypes from "prop-types";
import { i18next } from "@translations/oarepo_requests_ui/i18next";
-import { Button, Grid, List, Form, Divider, Comment, Header, Container, Icon } from "semantic-ui-react";
+import { Button, Grid, List, Form, Divider, Comment, Header, Container, Icon, Menu } from "semantic-ui-react";
import _isEmpty from "lodash/isEmpty";
import _sortBy from "lodash/sortBy";
-import { ReadOnlyCustomFields } from "@js/oarepo_requests/components";
-import { SideRequestInfo, ActionButtons } from ".";
+import { ActionButtons, MainRequestDetails } from ".";
export const RequestDetail = ({ request }) => {
+ const [activeTab, setActiveTab] = useState("details");
+
const requestModalHeader = !_isEmpty(request?.title) ? request.title : (!_isEmpty(request?.name) ? request.name : request.type);
- const renderReadOnlyData = !_isEmpty(request?.payload);
return (
@@ -28,75 +28,24 @@ export const RequestDetail = ({ request }) => {
-
-
-
-
-
- {renderReadOnlyData &&
-
- {Object.keys(request.payload).map(key => (
-
-
- {key}
- import(`../components/common/${widget}.jsx`),
- (widget) => import(`react-invenio-forms`)
- ]}
- />
-
-
- ))}
-
- }
- {/* If events are enabled for this request type, you can see the timeline of events and create new events. */}
- {/* {!_isEmpty(eventTypes) &&
- <>
- {i18next.t("Timeline")}
- {!_isEmpty(events) &&
-
- {events.map(event => {
- const eventPayloadUI = eventTypes.filter(eventType => eventType.id === event.type_code)[0]?.payload_ui;
- return (
-
-
- {event.created_by.label}
-
- {event?.created}
-
-
- import(`./${widget}.jsx`),
- (widget) => import(`react-invenio-forms`)
- ]}
- // fieldPathPrefix="payload"
- />
-
-
-
- )
- })}
-
- }
- {eventTypes.map(event => (
- } />
- ))}
- >
- } */}
-
-
-
+
+
+
+ {activeTab === 'details' && }
+ {activeTab === 'record' && Record}
);
}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
index 875bc427..d1ceec27 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
@@ -1,4 +1,5 @@
export { RequestDetail } from './RequestDetail';
export { SideRequestInfo } from './SideRequestInfo';
export { ActionButtons } from './ActionButtons';
-export { ConfirmModal } from './ConfirmModal';
\ No newline at end of file
+export { ConfirmModal } from './ConfirmModal';
+export { MainRequestDetails } from './MainRequestDetails';
\ No newline at end of file
From 3e13916936f241d96c1dca6ee0e5e24411692ea6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Mon, 3 Jun 2024 12:41:01 +0200
Subject: [PATCH 05/73] switch statusIcon based on status_code
---
.../components/SideRequestInfo.jsx | 23 ++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
index eba50182..1e62dec9 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
@@ -9,6 +9,27 @@ import { Header, Divider, Icon, Label } from "semantic-ui-react";
/** @param {{ request: Request }} props */
export const SideRequestInfo = ({ request }) => {
+ const statusIcon = (function () {
+ switch (request?.status_code.toLowerCase()) {
+ case "created":
+ return "clock outline";
+ case "submitted":
+ return "clock";
+ case "cancelled":
+ return "square";
+ case "accepted":
+ return "check circle";
+ case "declined":
+ return "close";
+ case "expired":
+ return "hourglass end";
+ case "deleted":
+ return "trash";
+ default:
+ return null;
+ }
+ })();
+
return (
<>
@@ -42,7 +63,7 @@ export const SideRequestInfo = ({ request }) => {
{i18next.t("Status")}
-
+ {statusIcon && }
{request?.status}
From a305a4021734f78ee22f349b79b0cdd7980f5b4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Mon, 3 Jun 2024 13:50:59 +0200
Subject: [PATCH 06/73] submit button, minor changes
---
.../semantic-ui/oarepo_requests_ui/RequestDetail.jinja | 4 +++-
.../request-detail/components/ActionButtons.jsx | 8 ++++++++
.../request-detail/components/ConfirmModal.jsx | 2 +-
.../request-detail/components/MainRequestDetails.jsx | 10 +++++++---
4 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja b/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja
index 7ebbec5b..157c0963 100644
--- a/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja
+++ b/oarepo_requests/ui/templates/semantic-ui/oarepo_requests_ui/RequestDetail.jinja
@@ -1,4 +1,4 @@
-{#def record #}
+{#def record, extra_context, ui #}
{%- set title = _("Request") ~ " | " ~ _("NR Document repository") %}
@@ -7,6 +7,8 @@
{%- block page_body %}
{{ record | pprint }}
+ {# {{ extra_context | pprint }}
+ {{ ui | pprint }}
#}
{%- endblock page_body %}
{%- block javascript %}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ActionButtons.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ActionButtons.jsx
index 10c0804d..35167907 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ActionButtons.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ActionButtons.jsx
@@ -32,6 +32,14 @@ const callApi = async (url, method = "GET", data = null) => {
export const ActionButtons = ({ request }) => {
return (
<>
+ {request.links?.actions?.submit &&
+ callApi(request.links.actions.accept, "POST", values)}
+ triggerButton={
+
+ }
+ />
+ }
{request.links?.actions?.accept &&
callApi(request.links.actions.accept, "POST", values)}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
index 475cbe5e..2dc7b094 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
@@ -51,7 +51,7 @@ export const ConfirmModal = ({ request, requestModalHeader, handleSubmit, trigge
const PayloadSchema = Yup.object().shape({
payload: Yup.object().shape({
content: Yup.string()
- .min(1, 'Too Short!')
+ .min(1, i18next.t("Comment must be at least 1 character long."))
})
});
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
index 7fe3376b..06f01dfe 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
@@ -2,7 +2,7 @@ import React, { useState } from "react";
import PropTypes from "prop-types";
import { i18next } from "@translations/oarepo_requests_ui/i18next";
-import { Button, Grid, List, Form, Divider, Comment, Header, Container, Icon, Menu } from "semantic-ui-react";
+import { Button, Grid, List, Form, Divider, Comment, Header, Container, Icon, Menu, Message } from "semantic-ui-react";
import _isEmpty from "lodash/isEmpty";
import _sortBy from "lodash/sortBy";
@@ -18,7 +18,7 @@ export const MainRequestDetails = ({ request }) => {
- {renderReadOnlyData &&
+ {renderReadOnlyData ?
{Object.keys(request.payload).map(key => (
@@ -36,7 +36,11 @@ export const MainRequestDetails = ({ request }) => {
))}
-
+ :
+
+ {i18next.t("No events to submit")}
+ {i18next.t("No events, i.e. messages or timeline, available for this request.")}
+
}
{/* If events are enabled for this request type, you can see the timeline of events and create new events. */}
{/* {!_isEmpty(eventTypes) &&
From a8918f5565bb3527128d63d4fd63dd63b833ccec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Mon, 3 Jun 2024 16:34:52 +0200
Subject: [PATCH 07/73] Add RichEditor and remove request_type from sidebar
---
.../components/ConfirmModal.jsx | 20 +++++++++++++++++--
.../components/SideRequestInfo.jsx | 4 ++--
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
index 2dc7b094..7d145845 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/ConfirmModal.jsx
@@ -5,6 +5,10 @@ import { i18next } from "@translations/oarepo_requests_ui/i18next";
import { Dimmer, Loader, Modal, Button, Icon, Message, Divider, FormTextArea, FormField } from "semantic-ui-react";
import _isEmpty from "lodash/isEmpty";
import _isFunction from "lodash/isFunction";
+import {
+ RichEditor,
+} from "react-invenio-forms";
+import { sanitizeInput } from "@js/oarepo_ui";
import { Formik, Field, Form, ErrorMessage } from "formik";
import * as Yup from 'yup';
@@ -78,7 +82,7 @@ export const ConfirmModal = ({ request, requestModalHeader, handleSubmit, trigge
validationSchema={PayloadSchema}
onSubmit={onSubmit}
>
- {({ isSubmitting }) => (
+ {({ isSubmitting, values, setFieldValue, setFieldTouched }) => (
<>
@@ -97,7 +101,19 @@ export const ConfirmModal = ({ request, requestModalHeader, handleSubmit, trigge
-
+ {
+ const cleanedContent = sanitizeInput(
+ editor.getContent(),
+ null
+ );
+ setFieldValue("payload.content", cleanedContent);
+ setFieldTouched("payload.content", true);
+ }}
+ {...field}
+ />
)}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
index 1e62dec9..8d5c7ba3 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/SideRequestInfo.jsx
@@ -52,12 +52,12 @@ export const SideRequestInfo = ({ request }) => {
-
+ {/*
{i18next.t("Request type")}
-
+ */}
{i18next.t("Status")}
From d2876d878ec6f91e5fd1c31dabd796c14fa810ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Tue, 4 Jun 2024 10:56:34 +0200
Subject: [PATCH 08/73] Impl TopicPreview using iframe
---
.../components/RequestDetail.jsx | 4 +-
.../components/TopicPreview.jsx | 50 +++++++++++++++++++
.../request-detail/components/index.js | 3 +-
3 files changed, 54 insertions(+), 3 deletions(-)
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/TopicPreview.jsx
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
index 0f7186d8..629da090 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
@@ -6,7 +6,7 @@ import { Button, Grid, List, Form, Divider, Comment, Header, Container, Icon, Me
import _isEmpty from "lodash/isEmpty";
import _sortBy from "lodash/sortBy";
-import { ActionButtons, MainRequestDetails } from ".";
+import { ActionButtons, MainRequestDetails, TopicPreview } from ".";
export const RequestDetail = ({ request }) => {
const [activeTab, setActiveTab] = useState("details");
@@ -45,7 +45,7 @@ export const RequestDetail = ({ request }) => {
{activeTab === 'details' && }
- {activeTab === 'record' && Record}
+ {activeTab === 'record' && }
);
}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/TopicPreview.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/TopicPreview.jsx
new file mode 100644
index 00000000..e3822364
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/TopicPreview.jsx
@@ -0,0 +1,50 @@
+import React, { useRef, useEffect } from "react";
+import PropTypes from "prop-types";
+
+import { i18next } from "@translations/oarepo_requests_ui/i18next";
+import { Button, Grid, List, Form, Divider, Comment, Header, Container, Icon, Menu, Loader, Segment } from "semantic-ui-react";
+import _isEmpty from "lodash/isEmpty";
+import _sortBy from "lodash/sortBy";
+
+import { ActionButtons, MainRequestDetails } from ".";
+
+export const TopicPreview = ({ request }) => {
+ const iframeRef = useRef(null);
+ const [height, setHeight] = React.useState("0px");
+ const [loading, setLoading] = React.useState(true);
+
+ const iframeOnLoad = () => {
+ setHeight(iframeRef.current.contentWindow.document.body.scrollHeight + "px");
+ setLoading(false);
+ }
+
+ const selfHtml = request.topic.link.replace("/api", "");
+
+
+ return (
+
+
+ {loading &&
+
+
+
+ }
+
+
+
+ );
+}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
index d1ceec27..4b2481a2 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
@@ -2,4 +2,5 @@ export { RequestDetail } from './RequestDetail';
export { SideRequestInfo } from './SideRequestInfo';
export { ActionButtons } from './ActionButtons';
export { ConfirmModal } from './ConfirmModal';
-export { MainRequestDetails } from './MainRequestDetails';
\ No newline at end of file
+export { MainRequestDetails } from './MainRequestDetails';
+export { TopicPreview } from './TopicPreview';
\ No newline at end of file
From f4a53620f4c1c755cc4c1e90c85b8919110a1f6d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Tue, 4 Jun 2024 11:11:43 +0200
Subject: [PATCH 09/73] Update RequestDetail component to use i18next for tab
names
---
.../request-detail/components/RequestDetail.jsx | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
index 629da090..33885ee5 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/RequestDetail.jsx
@@ -33,19 +33,21 @@ export const RequestDetail = ({ request }) => {
{activeTab === 'details' && }
- {activeTab === 'record' && }
+ {activeTab === 'topic' && }
);
}
From 97fc1af0015be23f6fa0a8269e28c37d246b5777 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Tue, 4 Jun 2024 15:35:23 +0200
Subject: [PATCH 10/73] Add jsconfig.json and Timeline component to request
detail page
---
.gitignore | 3 +-
.../components/MainRequestDetails.jsx | 7 +-
.../request-detail/components/Timeline.jsx | 90 +++++++++++++++++++
.../request-detail/components/index.js | 3 +-
4 files changed, 98 insertions(+), 5 deletions(-)
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/Timeline.jsx
diff --git a/.gitignore b/.gitignore
index 398fc710..5d4f1e92 100644
--- a/.gitignore
+++ b/.gitignore
@@ -93,4 +93,5 @@ thesis
todo.md
node_modules
-dummy-record.js
\ No newline at end of file
+dummy-record.js
+jsconfig.json
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
index 06f01dfe..fdb0731c 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
@@ -7,7 +7,7 @@ import _isEmpty from "lodash/isEmpty";
import _sortBy from "lodash/sortBy";
import { ReadOnlyCustomFields } from "@js/oarepo_requests/components";
-import { SideRequestInfo } from ".";
+import { SideRequestInfo, Timeline } from ".";
export const MainRequestDetails = ({ request }) => {
const renderReadOnlyData = !_isEmpty(request?.payload);
@@ -38,10 +38,11 @@ export const MainRequestDetails = ({ request }) => {
))}
:
- {i18next.t("No events to submit")}
- {i18next.t("No events, i.e. messages or timeline, available for this request.")}
+ {i18next.t("No request data")}
+ {i18next.t("No data available for this request.")}
}
+
{/* If events are enabled for this request type, you can see the timeline of events and create new events. */}
{/* {!_isEmpty(eventTypes) &&
<>
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/Timeline.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/Timeline.jsx
new file mode 100644
index 00000000..346c9619
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/Timeline.jsx
@@ -0,0 +1,90 @@
+import React, { useState, useEffect } from "react";
+import PropTypes from "prop-types";
+
+import { i18next } from "@translations/oarepo_requests_ui/i18next";
+import { Button, Grid, List, Form, Divider, Comment, Header, Container, Icon, Menu, Message, Feed, Dimmer, Loader, Placeholder, Segment } from "semantic-ui-react";
+import _isEmpty from "lodash/isEmpty";
+import _sortBy from "lodash/sortBy";
+import axios from "axios";
+
+import { ReadOnlyCustomFields } from "@js/oarepo_requests/components";
+import { SideRequestInfo } from ".";
+
+export const Timeline = ({ request }) => {
+ const [events, setEvents] = useState([]);
+ const [error, setError] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ setIsLoading(true);
+ setError(null);
+ axios
+ .get(`${request.links.timeline}`, {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ }
+ })
+ .then(response => {
+ setEvents(response.data.hits.hits)
+ })
+ .catch(error => {
+ console.error("Error while fetching timeline events", error);
+ setError(error);
+ })
+ .finally(() => {
+ setIsLoading(false);
+ });
+ }, []);
+
+ return (
+ <>
+ {i18next.t("Timeline")}
+
+
+ {i18next.t("Loading timeline...")}
+
+ {error ?
+
+ {i18next.t("Error while fetching timeline events")}
+ {error?.message}
+ :
+ isLoading ?
+
+
+ {Array.from({ length: 5 }).map((_, index) => (
+
+
+
+
+ ))}
+
+ :
+ !_isEmpty(events) ?
+
+ {events.map(event => (
+
+
+
+
+ {/*
+
+ {event._source.created_by.label}
+ {event._source.created}
+
+
+ {event._source.message}
+
+ */}
+
+ ))}
+ :
+
+ {i18next.t("No events")}
+ {i18next.t("No events, i.e. messages or timeline, available for this request.")}
+
+ }
+
+ >
+ );
+}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
index 4b2481a2..5a75e3a9 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
@@ -3,4 +3,5 @@ export { SideRequestInfo } from './SideRequestInfo';
export { ActionButtons } from './ActionButtons';
export { ConfirmModal } from './ConfirmModal';
export { MainRequestDetails } from './MainRequestDetails';
-export { TopicPreview } from './TopicPreview';
\ No newline at end of file
+export { TopicPreview } from './TopicPreview';
+export { Timeline } from './Timeline';
From f8e4328ce9d6437e0dfeec014aa08d8d8291ddef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Tue, 4 Jun 2024 17:00:47 +0200
Subject: [PATCH 11/73] Add EventSubmitForm component to request detail page;
impl Timeline
---
.../components/EventSubmitForm.jsx | 124 ++++++++++++++++++
.../components/MainRequestDetails.jsx | 3 +-
.../request-detail/components/Timeline.jsx | 28 ++--
.../request-detail/components/index.js | 1 +
4 files changed, 141 insertions(+), 15 deletions(-)
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/EventSubmitForm.jsx
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/EventSubmitForm.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/EventSubmitForm.jsx
new file mode 100644
index 00000000..5ce2f2a8
--- /dev/null
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/EventSubmitForm.jsx
@@ -0,0 +1,124 @@
+import React, { useState, useEffect, useRef } from "react";
+import PropTypes from "prop-types";
+
+import { i18next } from "@translations/oarepo_requests_ui/i18next";
+import { Button, Grid, List, Divider, Comment, Header, Container, Icon, Menu, Message, Feed, Dimmer, Loader, Placeholder, Segment, FormField } from "semantic-ui-react";
+import _isEmpty from "lodash/isEmpty";
+import _sortBy from "lodash/sortBy";
+import axios from "axios";
+import { RichEditor } from "react-invenio-forms";
+import { RichInputField } from "@js/oarepo_ui";
+
+import { Formik, Field, Form, ErrorMessage } from "formik";
+import * as Yup from 'yup';
+import { sanitizeHtml } from "sanitize-html";
+
+import { ReadOnlyCustomFields } from "@js/oarepo_requests/components";
+import { SideRequestInfo } from ".";
+
+const sanitizeInput = (htmlString, validTags) => {
+ const decodedString = decode(htmlString);
+ const cleanInput = sanitizeHtml(decodedString, {
+ allowedTags: validTags || ["b", "i", "em", "strong", "a", "div", "li", "p"],
+ allowedAttributes: {
+ a: ["href"],
+ },
+ });
+ return cleanInput;
+};
+
+export const EventSubmitForm = ({ request }) => {
+ const [error, setError] = useState(null);
+
+ const callApi = async (url, method = "POST", data = null) => {
+ if (_isEmpty(url)) {
+ console.log("URL parameter is missing or invalid.");
+ }
+ return axios({
+ url: url,
+ method: method,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ },
+ data: data
+ })};
+
+ const onSubmit = async (values, { setSubmitting }) => {
+ setSubmitting(true);
+ setError(null);
+ try {
+ console.log("Sending request");
+ await callApi(request.links?.comments, "POST", values);
+ } catch (error) {
+ setError(error);
+ } finally {
+ setSubmitting(false);
+ }
+ }
+
+ const CommentPayloadSchema = Yup.object().shape({
+ payload: Yup.object().shape({
+ content: Yup.string()
+ .min(1, i18next.t("Comment must be at least 1 character long.")),
+ format: Yup.string().equals(["html"], i18next.t("Invalid format."))
+ })
+ });
+
+ return (
+
+ {({ values, isSubmitting, setFieldValue, setFieldTouched }) => (
+
+ )}
+
+ );
+}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
index fdb0731c..768795af 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/MainRequestDetails.jsx
@@ -7,7 +7,7 @@ import _isEmpty from "lodash/isEmpty";
import _sortBy from "lodash/sortBy";
import { ReadOnlyCustomFields } from "@js/oarepo_requests/components";
-import { SideRequestInfo, Timeline } from ".";
+import { SideRequestInfo, Timeline, EventSubmitForm } from ".";
export const MainRequestDetails = ({ request }) => {
const renderReadOnlyData = !_isEmpty(request?.payload);
@@ -43,6 +43,7 @@ export const MainRequestDetails = ({ request }) => {
}
+
{/* If events are enabled for this request type, you can see the timeline of events and create new events. */}
{/* {!_isEmpty(eventTypes) &&
<>
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/Timeline.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/Timeline.jsx
index 346c9619..15c01f08 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/Timeline.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/Timeline.jsx
@@ -62,27 +62,27 @@ export const Timeline = ({ request }) => {
:
!_isEmpty(events) ?
- {events.map(event => (
+ {events.map(event => {
+ const isRenderable = event?.payload?.event && event?.created;
+ return isRenderable ? (
-
+
- {/*
+
- {event._source.created_by.label}
- {event._source.created}
+ {event?.created_by?.user ?
+ <>{event.created_by.user} {event.payload.event} this request on{event.created}> :
+ Request {event.payload.event} on {event.created}
+ }
-
- {event._source.message}
-
- */}
+ {event?.payload?.content && {event.payload.content}}
+
- ))}
+ ) : null;
+ })}
:
-
- {i18next.t("No events")}
- {i18next.t("No events, i.e. messages or timeline, available for this request.")}
-
+ null
}
>
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
index 5a75e3a9..38c04fc6 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/index.js
@@ -5,3 +5,4 @@ export { ConfirmModal } from './ConfirmModal';
export { MainRequestDetails } from './MainRequestDetails';
export { TopicPreview } from './TopicPreview';
export { Timeline } from './Timeline';
+export { EventSubmitForm } from './EventSubmitForm';
\ No newline at end of file
From 29e81444f100dce43b0aefd2b1a71b65fcbc3b4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20=C4=8Corov=C4=8D=C3=A1k?=
Date: Fri, 7 Jun 2024 16:19:10 +0200
Subject: [PATCH 12/73] Add TopicPreview, Timeline fetching, fix submit forms
---
.../components/EventSubmitForm.jsx | 49 ++++++---------
.../request-detail/components/Timeline.jsx | 45 ++++++++------
.../components/TopicPreview.jsx | 2 +-
.../request-detail/utils/index.js | 59 +++++++++++++++++++
4 files changed, 103 insertions(+), 52 deletions(-)
create mode 100644 oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/utils/index.js
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/EventSubmitForm.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/EventSubmitForm.jsx
index 5ce2f2a8..6ac8add4 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/EventSubmitForm.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/request-detail/components/EventSubmitForm.jsx
@@ -6,26 +6,14 @@ import { Button, Grid, List, Divider, Comment, Header, Container, Icon, Menu, Me
import _isEmpty from "lodash/isEmpty";
import _sortBy from "lodash/sortBy";
import axios from "axios";
-import { RichEditor } from "react-invenio-forms";
-import { RichInputField } from "@js/oarepo_ui";
+import { RichEditor, FieldLabel, RichInputField } from "react-invenio-forms";
import { Formik, Field, Form, ErrorMessage } from "formik";
import * as Yup from 'yup';
-import { sanitizeHtml } from "sanitize-html";
import { ReadOnlyCustomFields } from "@js/oarepo_requests/components";
import { SideRequestInfo } from ".";
-
-const sanitizeInput = (htmlString, validTags) => {
- const decodedString = decode(htmlString);
- const cleanInput = sanitizeHtml(decodedString, {
- allowedTags: validTags || ["b", "i", "em", "strong", "a", "div", "li", "p"],
- allowedAttributes: {
- a: ["href"],
- },
- });
- return cleanInput;
-};
+import { sanitizeInput } from "../utils";
export const EventSubmitForm = ({ request }) => {
const [error, setError] = useState(null);
@@ -48,7 +36,6 @@ export const EventSubmitForm = ({ request }) => {
setSubmitting(true);
setError(null);
try {
- console.log("Sending request");
await callApi(request.links?.comments, "POST", values);
} catch (error) {
setError(error);
@@ -60,7 +47,8 @@ export const EventSubmitForm = ({ request }) => {
const CommentPayloadSchema = Yup.object().shape({
payload: Yup.object().shape({
content: Yup.string()
- .min(1, i18next.t("Comment must be at least 1 character long.")),
+ .min(1, i18next.t("Comment must be at least 1 character long."))
+ .required(i18next.t("Comment must be at least 1 character long.")),
format: Yup.string().equals(["html"], i18next.t("Invalid format."))
})
});
@@ -78,30 +66,27 @@ export const EventSubmitForm = ({ request }) => {
>
{({ values, isSubmitting, setFieldValue, setFieldTouched }) => (
}
-
+
+ }
>
);
}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/ModalContentSideInfo.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/ModalContentSideInfo.jsx
index df675a5a..2edac1c3 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/ModalContentSideInfo.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/ModalContentSideInfo.jsx
@@ -8,7 +8,7 @@ import { List } from "semantic-ui-react";
* @typedef {import("../types").RequestType} RequestType
*/
-/** @param {{ request: Request, requestType: RequestType, isSidebar: boolean }} props */
+/** @param {{ request: Request, isSidebar: boolean }} props */
export const ModalContentSideInfo = ({ request, isSidebar = false }) => {
return (
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/RequestList.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/RequestList.jsx
index 2d4f4777..1b3a3410 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/RequestList.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/RequestList.jsx
@@ -41,7 +41,7 @@ export const RequestList = ({ requests }) => {
}
actions={modalActions}
- ContentComp={RequestModalContent}
+ ContentComponent={RequestModalContent}
/>
)
})}
diff --git a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/RequestModal.jsx b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/RequestModal.jsx
index 9a3a3306..a7d0eae2 100644
--- a/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/RequestModal.jsx
+++ b/oarepo_requests/ui/theme/assets/semantic-ui/js/oarepo_requests_ui/record-requests/components/RequestModal.jsx
@@ -17,8 +17,8 @@ import { ConfirmModalContextProvider, useRequestContext, useRecordContext } from
* @typedef {import("semantic-ui-react").ConfirmProps} ConfirmProps
*/
-/** @param {{ request: Request?, requestType: RequestType?, trigger: ReactElement, actions: [{ name: string, component: ReactElement }], ContentComp: ReactElement }} props */
-export const RequestModal = ({ request, requestType, trigger, actions, ContentComp }) => {
+/** @param {{ request: Request?, requestType: RequestType?, trigger: ReactElement, actions: [{ name: string, component: ReactElement }], ContentComponent: ReactElement }} props */
+export const RequestModal = ({ request, requestType, trigger, actions, ContentComponent }) => {
const errorMessageRef = useRef(null);
const { fetchNewRequests } = useRequestContext();
const {
@@ -30,7 +30,6 @@ export const RequestModal = ({ request, requestType, trigger, actions, ContentCo
const requestOrRequestType = request ?? requestType;
requestType = request ? request_types?.find(requestType => requestType.type_id === request.type) ?? {} : requestOrRequestType;
- console.error(requestOrRequestType, request_types, requestType)
const formik = useFormik({
initialValues:
@@ -104,11 +103,11 @@ export const RequestModal = ({ request, requestType, trigger, actions, ContentCo
{error?.message}
}
-
+
{actions.map(({ name, component: ActionComponent }) =>
-
+
)}