diff --git a/packages/tdb-dashboard/src/App.css b/packages/tdb-dashboard/src/App.css index a9bffc32..4b3893ac 100644 --- a/packages/tdb-dashboard/src/App.css +++ b/packages/tdb-dashboard/src/App.css @@ -1201,3 +1201,32 @@ pre.CodeMirror-line > span > span.cm-string { /* line-height: 1.5 !important; */ min-height: 49px!important; } + +/** custom alert error message */ +.alert_danger_text { + color: #842029 !important; +} + +.alert_danger { + background-color: #f8d7da !important; + border: 1px solid #f5c2c7 !important; +} + +.alert_danger_border { + border: 1px solid #842029 !important; +} + +.alert_btn_close { + color: #842029 !important; + box-sizing: content-box; + width: 1em; + height: 1em; + padding: 0.25em 0.25em; + border: 0; + border-radius: 0.375rem; + opacity: 0.4; +} + +.alert_expand_icons { + margin-top: -20px; +} \ No newline at end of file diff --git a/packages/tdb-dashboard/src/components/Alerts.js b/packages/tdb-dashboard/src/components/Alerts.js index 26ed2a41..a28cd6ec 100644 --- a/packages/tdb-dashboard/src/components/Alerts.js +++ b/packages/tdb-dashboard/src/components/Alerts.js @@ -6,6 +6,24 @@ import {AiOutlineCheckCircle, AiOutlineWarning} from "react-icons/ai" import {BiErrorCircle} from "react-icons/bi" import {BsInfoCircle} from "react-icons/bs" import {queryTimeDisplay} from "./utils" +import { FaTimes, FaExclamationTriangle } from "react-icons/fa" + + +/** +* +* @param {*} type document Type +* @returns a close button icon +*/ +const AlertCloseButton = ({ className, onClick }) => { + // on close button display document list table + return + } export const Alerts = ({message, type, onCancel, time}) => { const [hiddenAlerts, setHiddenAlerts] = React.useState([]) @@ -38,17 +56,18 @@ export const Alerts = ({message, type, onCancel, time}) => { if(type == TERMINUS_DANGER) return onClose("danger")}>
-
- - Error: {message} -
-
diff --git a/packages/tdb-dashboard/src/components/ErrorDisplay.js b/packages/tdb-dashboard/src/components/ErrorDisplay.js new file mode 100644 index 00000000..e560feb9 --- /dev/null +++ b/packages/tdb-dashboard/src/components/ErrorDisplay.js @@ -0,0 +1,73 @@ +import React, {useContext} from "react" +import Accordion from 'react-bootstrap/Accordion'; +import { useAccordionButton } from 'react-bootstrap/AccordionButton'; +import Card from 'react-bootstrap/Card'; +import AccordionContext from 'react-bootstrap/AccordionContext'; +import * as CONST from "./constants" +import { MdKeyboardArrowDown, MdKeyboardArrowRight } from "react-icons/md" + +// function to show custom buttons on Show/Hide in Accordians +function ToggleErrorDisplay({ children, eventKey, expandComponent, hideComponent, css }) { + const { activeEventKey } = useContext(AccordionContext); + + const onExpand = useAccordionButton(eventKey, () => {}); + + const isCurrentEventKey = activeEventKey === eventKey; + + return ( + + ); +} + +// function displays accordians per property error +/** + * + * @param {*} propertyName property name + * @param {*} errorType error description per property + * @param {*} message message per property + * @returns + */ +export const DisplayErrorPerProperty = ({ propertyName, errorType, message }) => { + return + +
+
+ } + hideComponent={}/> + {errorType} +
{propertyName}
+
+
+
+ +
{message}
+
+
+} + + +// function display error messages +export const ErrorDisplay = ({ errorData, message, css }) => { + return + + + {message} + + + + + {/*
{JSON.stringify(errorData, null, 2)}
*/} + {errorData} +
+
+
+
+} \ No newline at end of file diff --git a/packages/tdb-dashboard/src/components/JsonFrameViewer.js b/packages/tdb-dashboard/src/components/JsonFrameViewer.js index 429d34c3..703c2b29 100644 --- a/packages/tdb-dashboard/src/components/JsonFrameViewer.js +++ b/packages/tdb-dashboard/src/components/JsonFrameViewer.js @@ -66,6 +66,7 @@ export const JsonFrameViewer = ({jsonData, mode, setExtracted}) => { if(setExtracted) setExtracted(data) } + // onBlur return { + let message = "It looks like there are conflicts, fix these conflicts and then update or exit the Change Request" - return
- {message} + return
+ +
{message}
+
+
{JSON.stringify(errorData, null, 2)}
} diff --git a/packages/tdb-dashboard/src/hooks/DocumentControlContext.js b/packages/tdb-dashboard/src/hooks/DocumentControlContext.js index 287799f7..28830601 100644 --- a/packages/tdb-dashboard/src/hooks/DocumentControlContext.js +++ b/packages/tdb-dashboard/src/hooks/DocumentControlContext.js @@ -3,6 +3,8 @@ export const DocumentControlContext = React.createContext() export const DocumentControlObj = () => useContext(DocumentControlContext) import {WOQLClientObj} from '../init-woql-client' import * as CONST from "../components/constants" +import { ErrorDisplay } from "../components/ErrorDisplay" +import { DisplayErrorPerProperty } from "../components/ErrorDisplay" export const DocumentControlProvider = ({children}) => { @@ -37,6 +39,51 @@ export const DocumentControlProvider = ({children}) => { + // function to format and display errors in document Interface + function formatErrorMessages (error) { + + if(!error.hasOwnProperty("api:message")) return error + + let message = error["api:message"] + let errorElements = [] + if(error["api:error"]) { + if(Array.isArray(error["api:error"]["api:witnesses"])) { + error["api:error"]["api:witnesses"].map(err => { + + if(err.hasOwnProperty("constraint_name")) { + // CONSTRAINT ERRORS + let propertyName = err["constraint_name"] + let errorType = `${err["@type"]} on ` + let message = err.message + + errorElements.push( + + ) + } + else { + if(err.hasOwnProperty("@type")) { + errorElements.push( +
{JSON.stringify(err, null, 2)}
+ ) + } + else { + // OTHER TYPE ERRORS + for(let items in err) { + let propertyName = items + let errorType = err[propertyName].hasOwnProperty("@type") ? `${err[propertyName]["@type"]} on ` : `Error occured on` + let message = JSON.stringify(err[propertyName], null, 2) + errorElements.push( + + ) + } + } + } + }) + } + } + return + } + return ( { jsonContent, setJsonContent, showFrames, - setShowFrames + setShowFrames, + formatErrorMessages }} > {children} diff --git a/packages/tdb-dashboard/src/hooks/DocumentHook.js b/packages/tdb-dashboard/src/hooks/DocumentHook.js index 19d5bc0c..2acde4c3 100644 --- a/packages/tdb-dashboard/src/hooks/DocumentHook.js +++ b/packages/tdb-dashboard/src/hooks/DocumentHook.js @@ -4,6 +4,7 @@ import { useNavigate, useParams } from "react-router-dom"; import { ChangeRequest } from "./ChangeRequest"; import { WOQLClientObj } from "../init-woql-client"; + // to be review this export function CheckStatusObj() { const {currentChangeRequest} = WOQLClientObj() @@ -22,6 +23,14 @@ export function CheckStatusObj() { } +// function to set error +function setErrorMessage(setErrorMsg, err) { + if(setErrorMsg) { + if(err.hasOwnProperty("data")) setErrorMsg(err.data) + else setErrorMsg(err.message) + } +} + /** * Create a new document * @param {*} client TerminusDB Client @@ -47,7 +56,7 @@ export function CreateDocumentHook(client,document, setLoading, setErrorMsg) { } catch(err){ setLoading(false) - if(setErrorMsg) setErrorMsg(err.message) + setErrorMessage(setErrorMsg, err) } } @@ -114,7 +123,8 @@ export function GetDocumentHook(client, documentId, setData, setLoading, setErro } catch(err){ if(setLoading) setLoading(false) - if(setErrorMsg) setErrorMsg(err.message) + setErrorMessage(setErrorMsg, err) + //if(setErrorMsg) setErrorMsg(err.message) } } @@ -152,7 +162,8 @@ export function EditDocumentHook(client, extractedUpdate, setLoading, setErrorMs navigate(-1) } catch(err){ - setErrorMsg(err.message) + //setErrorMsg(err.message) + setErrorMessage(setErrorMsg, err) setLoading(false) } } diff --git a/packages/tdb-dashboard/src/hooks/hookUtils.js b/packages/tdb-dashboard/src/hooks/hookUtils.js index aeb11f9d..73794bdd 100644 --- a/packages/tdb-dashboard/src/hooks/hookUtils.js +++ b/packages/tdb-dashboard/src/hooks/hookUtils.js @@ -43,9 +43,9 @@ export function formatErrorMessage (err){ }else if(err.data){ if( err.data["api:message"] === "Incorrect authentication information"){ message = "Incorrect authentication information, wrong username or password" - }else if (err.data["api:status"]==="api:conflict"){ + }else if (err.data["api:status"]==="api:conflict") { message = getCRConflictError(err.data["api:witnesses"]) - }else if (err.data["api:message"]=== "Schema check failure"){ + }else if (err.data["api:message"]=== "Schema check failure") { message = `${err.data["api:message"]} ${JSON.stringify(err.data["system:witnesses"], null, 2)}` }else{ message = err.data["api:message"] diff --git a/packages/tdb-dashboard/src/pages/ChangeDiff.js b/packages/tdb-dashboard/src/pages/ChangeDiff.js index 006825bb..ff1fa9ed 100644 --- a/packages/tdb-dashboard/src/pages/ChangeDiff.js +++ b/packages/tdb-dashboard/src/pages/ChangeDiff.js @@ -43,7 +43,7 @@ const CRAction = ({}) => { return // if needRebase - return + return {errorMessage && } diff --git a/packages/tdb-dashboard/src/pages/DocumentEdit.js b/packages/tdb-dashboard/src/pages/DocumentEdit.js index 53a45002..35af78b0 100644 --- a/packages/tdb-dashboard/src/pages/DocumentEdit.js +++ b/packages/tdb-dashboard/src/pages/DocumentEdit.js @@ -14,6 +14,7 @@ import {DocumentControlObj} from "../hooks/DocumentControlContext" import {CreateChangeRequestModal} from "../components/CreateChangeRequestModal" import {UTILS} from "@terminusdb/terminusdb-client" import {decodeUrl} from "../components/utils" +import { Alerts } from "../components/Alerts" const checkIfPrefix =(id)=>{ if(id.indexOf(":")>-1){ @@ -116,6 +117,10 @@ export const DocumentEdit = () => { setChangeRequestBranch, branch } = WOQLClientObj() + const { + formatErrorMessages + } = DocumentControlObj() + const {type, id} = useParams() let documentID=decodeUrl(id) // constants to display document body in Form or JSON View @@ -140,9 +145,10 @@ export const DocumentEdit = () => { return
- {errorMsg && + {/*errorMsg && {errorMsg} - } + */} + {errorMsg && } {showModal && { @@ -52,6 +53,7 @@ const onSelect = async (inp, type) => { return results } + const DisplayDocumentBody = ({setLoading, setErrorMsg}) => { const { woqlClient, @@ -102,17 +104,44 @@ const DisplayDocumentBody = ({setLoading, setErrorMsg}) => { /> } + +/*const FAKE_ERROR = { + "@type":"api:InsertDocumentErrorResponse", + "api:error": { + "@type":"api:SchemaCheckFailure", + "api:witnesses": [ + { + "@type":"ConstraintFailure", + "constraint_name":"MidLifeInsurance", + "message":"Failed to satisfy: 12 > 30\n In the Constraint:\n\n( 'Policy/3':'Policy'\n ∧ 'Policy/3' =[insurance_product]> 'MidLifeInsurance/Mid-Life%20Insurance%20Product'\n ∧ 'MidLifeInsurance/Mid-Life%20Insurance%20Product':'MidLifeInsurance'\n ) ⇒\n 'Policy/3' =[customer]> 'Customer/Jill+Curry+2'\n ∧ 'Customer/Jill+Curry+2' =[age]> 12\n ∧ « 12 > 30\n » ∧ 12 < 60\n \n" + }, + { + "@type":"ConstraintFailure", + "constraint_name":"Policy", + "message":"Failed to satisfy: 12 > 30\n In the Constraint:\n\n( 'Policy/3':'Policy'\n ∧ 'Policy/3' =[insurance_product]> 'MidLifeInsurance/Mid-Life%20Insurance%20Product'\n ∧ 'MidLifeInsurance/Mid-Life%20Insurance%20Product':'MidLifeInsurance'\n ) ⇒\n 'Policy/3' =[customer]> 'Customer/Jill+Curry+2'\n ∧ 'Customer/Jill+Curry+2' =[age]> 12\n ∧ « 12 > 30\n » ∧ 12 < 60\n \n" + } + ] + }, + "api:message":"Schema check failure", + "api:status":"api:failure" +}*/ + export const DocumentNew = () => { const { setChangeRequestBranch, branch,woqlClient } = WOQLClientObj() + const { + formatErrorMessages + } = DocumentControlObj() + const [showModal, setShowModal] = useState(false) const {type} = useParams() const [loading, setLoading]=useState(false) const [errorMsg, setErrorMsg]=useState(false) + //const [errorMsg, setErrorMsg]=useState(FAKE_ERROR) useEffect(() => { if(branch === "main"){ @@ -127,16 +156,17 @@ export const DocumentNew = () => { // setCurrentMode(currentMode) } - return
- {errorMsg && + return
+ {errorMsg && } + {/*errorMsg && {errorMsg} - } + */} {showModal && } {branch !== "main" && - +
diff --git a/packages/tdb-documents-ui/src/documentTypeFrames/helpers.js b/packages/tdb-documents-ui/src/documentTypeFrames/helpers.js index b0ca7015..a747e80e 100644 --- a/packages/tdb-documents-ui/src/documentTypeFrames/helpers.js +++ b/packages/tdb-documents-ui/src/documentTypeFrames/helpers.js @@ -160,7 +160,7 @@ export function displaySearchComponent(props, onSelect, linked, mode) { // display only anyof properties here // schema appears twice in UI so we display empty div when props.schema has anyOf - if(props.schema.hasOwnProperty("anyOf")) return
+ if(props.hasOwnProperty("schema") && props.schema.hasOwnProperty("anyOf")) return
const Selected = ({selected, mode}) => {