diff --git a/components/browser/EdgeBrowser.js b/components/browser/EdgeBrowser.js
index 88c748c2d..1fc740086 100644
--- a/components/browser/EdgeBrowser.js
+++ b/components/browser/EdgeBrowser.js
@@ -306,37 +306,42 @@ export default class EdgeBrowser extends React.Component {
// index is index of the column where the custom load of an entity is changed
// also update if there's column with same parent
updateChildColumn(index, customLoad) {
- if (index + 1 >= this.state.columns.length) return
- const parentIdOfColumn = this.state.columns[index].parentId
- const resultColumns = []
- resultColumns.push(this.state.columns[0])
- for (let i = 1; i < this.state.columns.length; i += 1) {
- const parentColumn = this.state.columns[i - 1]
- const column = this.state.columns[i]
- if (parentColumn.parentId === parentIdOfColumn) {
- resultColumns.push({ ...column, parentCustomLoad: customLoad })
- } else {
- resultColumns.push(column)
+ this.setState((prevState) => {
+ if (index + 1 >= prevState.columns.length) return null
+ const parentIdOfColumn = prevState.columns[index].parentId
+ const resultColumns = []
+ resultColumns.push(prevState.columns[0])
+ for (let i = 1; i < prevState.columns.length; i += 1) {
+ const parentColumn = prevState.columns[i - 1]
+ const column = prevState.columns[i]
+ if (parentColumn.parentId === parentIdOfColumn) {
+ const updatedColumn = {
+ ...column,
+ parentCustomLoad: customLoad,
+ }
+ resultColumns.push(updatedColumn)
+ } else {
+ resultColumns.push(column)
+ }
}
- }
- this.setState({ columns: resultColumns })
+ return { columns: resultColumns }
+ })
}
// set the shouldUpdate property of column at index
// and all other columns with same parent
// to trigger entites reload of those columns
reloadColumnEntities(index) {
- const parentIdOfColumn = this.state.columns[index].parentId
- const resultColumns = []
- for (let i = 0; i < this.state.columns.length; i += 1) {
- const column = this.state.columns[i]
- if (column?.parentId === parentIdOfColumn) {
- resultColumns.push({ ...column, shouldReloadEntities: !column.shouldReloadEntities })
- } else {
- resultColumns.push(column)
- }
- }
- this.setState({ columns: resultColumns })
+ this.setState((prevState) => {
+ const parentIdOfColumn = prevState.columns[index].parentId
+ const resultColumns = prevState.columns.map((column) => {
+ if (column?.parentId === parentIdOfColumn) {
+ return { ...column, shouldReloadEntities: !column.shouldReloadEntities }
+ }
+ return column
+ })
+ return { columns: resultColumns }
+ })
}
async lookupSignatures() {
diff --git a/components/browser/EditEdgeTextbox.js b/components/browser/EditEdgeTextbox.js
new file mode 100644
index 000000000..d2310d530
--- /dev/null
+++ b/components/browser/EditEdgeTextbox.js
@@ -0,0 +1,114 @@
+/* eslint-disable jsx-a11y/anchor-is-valid */
+/* eslint-disable react/destructuring-assignment */
+/* globals $: false */
+
+import { useCallback, useEffect, useState } from 'react'
+import { debounce } from 'lodash'
+import { getTooltipTitle } from '../../lib/edge-utils'
+import LoadingSpinner from '../LoadingSpinner'
+import Icon from '../Icon'
+
+const EditEdgeTextbox = ({
+ existingEdge,
+ canAddEdge,
+ label,
+ selected,
+ addEdge,
+ removeEdge,
+ type,
+ editEdgeTemplate,
+}) => {
+ const showTrashButton = existingEdge?.writers?.length !== 0
+ const [isLoading, setIsLoading] = useState(false)
+ const [immediateValue, setImmediateValue] = useState(null)
+
+ const handleHover = (target) => {
+ if (!existingEdge) return
+ const title = getTooltipTitle(existingEdge)
+ $(target).tooltip({
+ title,
+ trigger: 'hover',
+ container: 'body',
+ })
+ }
+
+ const delayedAddEdge = useCallback(
+ debounce(async (e) => {
+ setIsLoading(true)
+ const result = await addEdge({
+ e,
+ existingEdge,
+ editEdgeTemplate,
+ updatedEdgeFields: { [type]: Number(e.target.value) },
+ })
+ setIsLoading(false)
+ if (!result) setImmediateValue(selected)
+ }, 500),
+ [existingEdge]
+ )
+
+ const handleRemoveEdge = async (e) => {
+ e.stopPropagation()
+ setIsLoading(true)
+ await removeEdge()
+ setIsLoading(false)
+ }
+
+ useEffect(() => {
+ setIsLoading(false)
+ if (selected !== null && selected !== undefined) {
+ setImmediateValue(selected)
+ } else {
+ setImmediateValue(null)
+ }
+ }, [existingEdge, canAddEdge])
+
+ if (!existingEdge && !canAddEdge) return null
+ return (
+
{
+ e.stopPropagation()
+ }}
+ >
+
+
+ e.stopPropagation()}
+ onChange={(e) => {
+ e.stopPropagation()
+ setImmediateValue(e.target.value)
+ delayedAddEdge(e)
+ }}
+ />
+
+
+ {isLoading && }
+ {existingEdge && showTrashButton && (
+
+ )}
+
+
+ )
+}
+
+export default EditEdgeTextbox
diff --git a/components/browser/ProfileEntity.js b/components/browser/ProfileEntity.js
index 3bf12efe4..4ea51e4ba 100644
--- a/components/browser/ProfileEntity.js
+++ b/components/browser/ProfileEntity.js
@@ -22,6 +22,7 @@ import EditEdgeToggle from './EditEdgeToggle'
import EditEdgeTwoDropdowns from './EditEdgeTwoDropdowns'
import ScoresList from './ScoresList'
import useQuery from '../../hooks/useQuery'
+import EditEdgeTextbox from './EditEdgeTextbox'
export default function ProfileEntity(props) {
const {
@@ -143,7 +144,7 @@ export default function ProfileEntity(props) {
if (isTraverseInvitation) {
props.removeEdgeFromEntity(id, result)
} else if (isCustomLoadInvitation) {
- props.updateChildColumn(props.columnIndex, null)
+ props.updateChildColumn(props.columnIndex, defaultWeight)
}
props.reloadColumnEntities()
} catch (error) {
@@ -204,7 +205,7 @@ export default function ProfileEntity(props) {
)
if (version === 1 && (!signatures || signatures.length === 0)) {
promptError("You don't have permission to edit this edge")
- return
+ return false
}
const {
@@ -241,8 +242,10 @@ export default function ProfileEntity(props) {
promptMessage(
`Invitation has been sent to ${body.tail} and it's waiting for the response.`
)
+ return true
} catch (error) {
promptError(error.message)
+ return false
}
}
@@ -317,10 +320,27 @@ export default function ProfileEntity(props) {
if (!edge && content?.isInvitedProfile && isEmergencyReviewerStage && !isInviteInvitation)
return null
+ const editEdgeTextbox = (type) => (
+ <>
+ p?.invitation === invitation.id).length === 0 ||
+ invitation.multiReply
+ }
+ label={invitation.name}
+ selected={edge?.[type]}
+ addEdge={addEdge}
+ removeEdge={() => removeEdge(edge)}
+ type={type} // label or weight
+ editEdgeTemplate={editEdgeTemplates?.find((p) => p?.invitation === invitation.id)}
+ />
+ >
+ )
+
const editEdgeDropdown = (type, controlType) => (
p?.invitation === invitation.id).length === 0 ||
invitation.multiReply
@@ -386,12 +406,14 @@ export default function ProfileEntity(props) {
const shouldRenderWeightRadio = weightRadio && !invitation.label
const shouldRenderLabelDropdown = labelDropdown && !invitation.weight
const shouldRenderWeightDropdown = weightDropdown && !invitation.label
+ const shouldRenderWeightTextbox = invitation.weight?.['value-textbox']
if (shouldRenderTwoRadio) return editEdgeTwoDropdowns('value-radio')
if (shouldRenderTwoDropdown) return editEdgeTwoDropdowns('value-dropdown')
if (shouldRenderLabelRadio) return editEdgeDropdown('label', 'value-radio') // for now treat radio the same as dropdown
if (shouldRenderWeightRadio) return editEdgeDropdown('weight', 'value-radio') // for now treat radio the same as dropdown
if (shouldRenderLabelDropdown) return editEdgeDropdown('label', 'value-dropdown')
+ if (shouldRenderWeightTextbox) return editEdgeTextbox('weight')
if (shouldRenderWeightDropdown) return editEdgeDropdown('weight', 'value-dropdown')
return editEdgeToggle()
}
diff --git a/lib/edge-utils.js b/lib/edge-utils.js
index 8c4680a06..b570cfd83 100644
--- a/lib/edge-utils.js
+++ b/lib/edge-utils.js
@@ -358,6 +358,9 @@ export function translateFieldSpec(invitation, fieldName, version) {
if (field.param?.enum) {
spec['value-dropdown'] = field.param.enum
}
+ if (field.param?.input === 'text') {
+ spec['value-textbox'] = true
+ }
return spec
}
const field = invitation.reply.content[fieldName]
diff --git a/styles/pages/edge-browser.scss b/styles/pages/edge-browser.scss
index 581a77c04..8ae30440b 100644
--- a/styles/pages/edge-browser.scss
+++ b/styles/pages/edge-browser.scss
@@ -191,6 +191,33 @@ main.edge-browser {
cursor: no-drop;
}
}
+ .edit-edge-textbox {
+ width: 15%;
+ padding-left: 0.5rem;
+
+ .edit-edge-input {
+ font-size: 0.75rem;
+ padding: 3px 5px;
+ height: fit-content;
+
+ &:disabled {
+ cursor: no-drop;
+ }
+ }
+ }
+ .edit-edge-spinner {
+ display: inline-flex;
+ vertical-align: middle;
+
+ .spinner-small {
+ height: 100%;
+ display: inline-block;
+ width: 40px;
+ & > div {
+ background-color: constants.$orRed;
+ }
+ }
+ }
.span-disabled {
pointer-events: none;
}