From 80e6cecd153447feb00fc3d0dce34c6b9d11221f Mon Sep 17 00:00:00 2001 From: pamfilos Date: Tue, 24 Oct 2023 11:50:07 +0200 Subject: [PATCH 1/3] ui: forms - update serviceGetter for CAP records Signed-off-by: pamfilos --- .../src/antd/admin/utils/fieldTypes.js | 49 ++++- .../src/antd/forms/fields/ImportDataField.js | 179 ++++++++++++++++++ .../src/antd/forms/fields/ServiceGetter.js | 28 ++- ui/cap-react/src/antd/forms/fields/index.js | 2 + .../antd/forms/fields/services/CAPDeposit.js | 49 +++++ .../antd/forms/fields/services/svg/capLogo.js | 89 +++++++++ 6 files changed, 388 insertions(+), 8 deletions(-) create mode 100644 ui/cap-react/src/antd/forms/fields/ImportDataField.js create mode 100644 ui/cap-react/src/antd/forms/fields/services/CAPDeposit.js create mode 100644 ui/cap-react/src/antd/forms/fields/services/svg/capLogo.js diff --git a/ui/cap-react/src/antd/admin/utils/fieldTypes.js b/ui/cap-react/src/antd/admin/utils/fieldTypes.js index bf4e090c77..a416a30af0 100644 --- a/ui/cap-react/src/antd/admin/utils/fieldTypes.js +++ b/ui/cap-react/src/antd/admin/utils/fieldTypes.js @@ -247,6 +247,50 @@ const collections = { }; const simple = { + importData: { + title: "Import Data", + icon: , + description: "Provided a URL or query", + child: {}, + optionsSchema: { + type: "object", + title: "File upload widget", + properties: { + ...common.optionsSchema, + readOnly: extra.optionsSchema.readOnly, + isRequired: extra.optionsSchema.isRequired, + "x-cap-import-data": { + type: "object", + properties: { + queryUrl: { + type: "string" + }, + resultsPath: { + type: "string" + }, + } + } + }, + }, + optionsSchemaUiSchema: { + readOnly: extra.optionsSchemaUiSchema.readOnly, + isRequired: extra.optionsSchemaUiSchema.isRequired, + }, + optionsUiSchema: { + ...common.optionsUiSchema, + }, + optionsUiSchemaUiSchema: { + ...common.optionsUiSchemaUiSchema, + }, + default: { + schema: { + type: "object", + }, + uiSchema: { + "ui:field": "importData", + }, + }, + }, text: { title: "Text", icon: , @@ -916,6 +960,8 @@ const advanced = { { const: "orcid", title: "ORCiD" }, { const: "ror", title: "ROR" }, { const: "zenodo", title: "Zenodo" }, + { const: "capRecords", title: "CAP Records" }, + { const: "capDeposits", title: "CAP Deposits" }, ], }, uniqueItems: "true", @@ -934,7 +980,8 @@ const advanced = { properties: {}, }, uiSchema: { - "ui:servicesList": ["orcid", "ror", "zenodo"], + "ui:serfvicesList": ["orcid", "ror", "zenodo"], + "ui:servicesList": ["capDeposits"], "ui:field": "idFetcher", }, }, diff --git a/ui/cap-react/src/antd/forms/fields/ImportDataField.js b/ui/cap-react/src/antd/forms/fields/ImportDataField.js new file mode 100644 index 0000000000..44d3d92b27 --- /dev/null +++ b/ui/cap-react/src/antd/forms/fields/ImportDataField.js @@ -0,0 +1,179 @@ +import React, { useState } from "react"; +import PropTypes from "prop-types"; + +import axios from "axios"; + +// import CustomOption from "./ImportDataFieldSelectComponent"; +import { Avatar, Checkbox, Input, List, Select, Space, Typography } from "antd"; +import ServiceGetter from "./ServiceGetter"; + +const EMPTY_VALUE = "---- No Selection ---- "; + +const ImportDataField = ({ schema, uiSchema, formData, onChange }) => { + // const [data, setData] = useState([]); + const [selected, setSelected] = useState(); + + const query = uiSchema?.["ui:options"]?.query || undefined; + const importData = uiSchema["importData"] || {}; + + const [fetchedResults, setFetchedResults] = useState(null); + const [currentIndex, setCurrentIndex] = useState(null); + const [data, setData] = useState(null); + + const { + "x-cap-import-data": { + queryUrl = "/api/deposits", + // queryUrl = "", + queryParam = "q", + resultsPath = "hits.hits", + hitTitle = "metadata.general_title", + hitDescription = "created_by.email", + // resultsPath = null + } = {}, + } = schema; + // } = uiSchema; + + const getResultFromData = data => { + let results = data; + const resultPathArray = resultsPath.split("."); + resultPathArray.map(p => (results = results[p])); + return results; + }; + + const serializeResults = data => { + return data.map(entry => { + let title = entry; + let description = entry; + + hitTitle.split(".").map(i => (title = title[i])); + hitDescription.split(".").map(i => (description = description[i])); + return { + label: title, + value: description, + data: entry, + }; + }); + // let results = data; + // const resultPathArray = resultsPath.split("."); + // resultPathArray.map(p => (results = results[p])); + // return results; + }; + const fetchSuggestions = async (val = "") => { + try { + const { data } = await axios.get(queryUrl, { + params: { + [queryParam]: val, + }, + }); + console.log(data); + + let results = getResultFromData(data); + console.log("rrrrrrrrrrrrrrrr", results); + results = serializeResults(results); + console.log("rrrrrrrrrrrr3333rrrr", results); + setFetchedResults(results); + // updateAll(data, true); + } catch (err) { + // + } + }; + + return ( + + + { + // e.target.value == "" && + // fetchedResults && + // setFetchedResults(null); + // updateAll(fetchedResults || [], false); + // }} + onSearch={fetchSuggestions} + /> + {fetchedResults && ( + ( + { + console.log(item) + setData(item.data)} + + } extfra={[
Content
]}> + } + description={item.value} + /> +
+ )} + /> + )} + + + { + data && JSON.stringify(data) + } +
+ ); +}; + +ImportDataField.propTypes = { + onChange: PropTypes.func, + uiSchema: PropTypes.object, + formData: PropTypes.object, +}; + +export default ImportDataField; diff --git a/ui/cap-react/src/antd/forms/fields/ServiceGetter.js b/ui/cap-react/src/antd/forms/fields/ServiceGetter.js index 10700213f6..5c48be561f 100644 --- a/ui/cap-react/src/antd/forms/fields/ServiceGetter.js +++ b/ui/cap-react/src/antd/forms/fields/ServiceGetter.js @@ -9,6 +9,8 @@ import OrcidSvg from "./services/svg/OrcidSvg"; import ZenodoSvg from "./services/svg/ZenodoSvg"; import RorSvg from "./services/svg/RorSvg"; import Icon from "@ant-design/icons"; +import CAPDeposit from "./services/CAPDeposit"; +import CAPLogo from "./services/svg/capLogo"; const SERVICES = { orcid: { @@ -26,15 +28,25 @@ const SERVICES = { url: "/api/services/zenodo/record/", svg: ZenodoSvg, }, + capRecords: { + name: "CAP Records", + url: "/api/records/", + svg: ZenodoSvg, + }, + capDeposits: { + name: "CAP Deposits", + url: "/api/deposits/", + svg: CAPLogo, + }, }; -const ServiceGetter = ({ formData = {}, uiSchema, onChange }) => { +const ServiceGetter = ({ formData = {}, uiSchema ={}, onChange }) => { const [service, setService] = useState(); const [loading, setLoading] = useState(false); const [errorMessage, setErrorMessage] = useState(undefined); useEffect(() => { - if (uiSchema["ui:servicesList"].length === 1) { + if (uiSchema?.["ui:servicesList"]?.length === 1) { setService(uiSchema["ui:servicesList"]); } }, [uiSchema]); @@ -44,8 +56,9 @@ const ServiceGetter = ({ formData = {}, uiSchema, onChange }) => { ror: , zenodo: , orcid: , + capDeposits: , }; - return choices[name]; + return choices[name] || {JSON.stringify(formData.fetched)}; }; const getId = (service, id) => { @@ -81,7 +94,7 @@ const ServiceGetter = ({ formData = {}, uiSchema, onChange }) => { try { const results = await axios.get(currentServiceApi + resourceID); let { data } = results; - if (!data.status) { + if (!data.statuss) { const resource_data = { source: { service: service, @@ -103,10 +116,11 @@ const ServiceGetter = ({ formData = {}, uiSchema, onChange }) => { return (
{formData.fetched ? ( - + {getContentByName(formData.source.service)}
]}> - } - description={i.value} - /> - - - - - // { - // ...i, - // label: ( - // - // - // {i.value} -- {i.data.id} || {i.label} - // - // - // ), - // } - ))} - { - // e.target.value == "" && - // fetchedResults && - // setFetchedResults(null); - // updateAll(fetchedResults || [], false); - // }} - onSearch={fetchSuggestions} + allowClear + value={searchValue} + cle + onChange={updateSearchValue} + onSearch={_onSearch} /> - {fetchedResults && ( - ( - { - console.log(item) - setData(item.data)} - - } extfra={[
Content
]}> - } - description={item.value} - /> -
- )} - /> + {!isEmpty(fetchedResults) && ( + fetchSuggestions(true)} + hasMore={fetchedResults.length < fetchedResultsTotal} + style={{ backgroundColor: "#fff" }} + loader={ + + + + + + } + endMessage={It is all, nothing more 🤐} + > + ( + { + onChange({ + url: item?.data?.links?.self, + data: item.data + }) + setData(item.data); + setFetchedResults([]); + }} + extfra={[
Content
]} + > + } + description={item.value} + /> +
+ )} + /> +
)} - - - { - data && JSON.stringify(data) - } ); }; diff --git a/ui/cap-react/src/antd/forms/fields/ServiceGetter.js b/ui/cap-react/src/antd/forms/fields/ServiceGetter.js index 5c48be561f..f7002fde37 100644 --- a/ui/cap-react/src/antd/forms/fields/ServiceGetter.js +++ b/ui/cap-react/src/antd/forms/fields/ServiceGetter.js @@ -31,7 +31,7 @@ const SERVICES = { capRecords: { name: "CAP Records", url: "/api/records/", - svg: ZenodoSvg, + svg: CAPLogo, }, capDeposits: { name: "CAP Deposits", @@ -40,7 +40,7 @@ const SERVICES = { }, }; -const ServiceGetter = ({ formData = {}, uiSchema ={}, onChange }) => { +const ServiceGetter = ({ formData = {}, uiSchema = {}, onChange }) => { const [service, setService] = useState(); const [loading, setLoading] = useState(false); const [errorMessage, setErrorMessage] = useState(undefined); @@ -94,16 +94,14 @@ const ServiceGetter = ({ formData = {}, uiSchema ={}, onChange }) => { try { const results = await axios.get(currentServiceApi + resourceID); let { data } = results; - if (!data.statuss) { - const resource_data = { - source: { - service: service, - externalID: resourceID, - }, - fetched: data, - }; - onChange(resource_data); - } else setErrorMessage("Resource not found or inaccessible"); + const resource_data = { + source: { + service: service, + externalID: resourceID, + }, + fetched: data, + }; + onChange(resource_data); } catch (e) { setErrorMessage("Resource not found or inaccessible"); } @@ -113,9 +111,9 @@ const ServiceGetter = ({ formData = {}, uiSchema ={}, onChange }) => { } }; - return ( -
- {formData.fetched ? ( + if (formData.fetched) { + return ( +
{getContentByName(formData.source.service)} @@ -127,41 +125,44 @@ const ServiceGetter = ({ formData = {}, uiSchema ={}, onChange }) => { /> - ) : ( - - {uiSchema["ui:servicesList"]?.length > 1 && ( - - )} - {service && ( - - - - - - {errorMessage} +
+ ); + } + return ( +
+ + {uiSchema["ui:servicesList"]?.length > 1 && ( + + )} + {service && ( + + + + - )} - - )} + {errorMessage} + + )} +
); }; diff --git a/ui/cap-react/src/antd/forms/fields/services/CAPDeposit.js b/ui/cap-react/src/antd/forms/fields/services/CAPDeposit.js index 4bd4f79203..6c077e1959 100644 --- a/ui/cap-react/src/antd/forms/fields/services/CAPDeposit.js +++ b/ui/cap-react/src/antd/forms/fields/services/CAPDeposit.js @@ -1,5 +1,15 @@ import PropTypes from "prop-types"; -import { Avatar, Card, Col, Divider, Modal, Row, Space, Tag, Typography } from "antd"; +import { + Avatar, + Card, + Col, + Divider, + Modal, + Row, + Space, + Tag, + Typography, +} from "antd"; import { stringToHslColor } from "../../../utils"; import { EyeFilled, EyeInvisibleFilled, LinkOutlined } from "@ant-design/icons"; import { useState } from "react"; @@ -23,20 +33,25 @@ const CAPDeposit = ({ data }) => { /> - {data.schema.fullname}} - title={data?.metadata?.general_title || "No title"} - description={ - }> - - - - setShowModal(true)} /> - + + + {data?.schema?.fullname}} + title={data?.metadata?.general_title || "No title"} + description={"No description"} + /> + - } - /> + }> + + + + setShowModal(true)} /> + + );