Skip to content

Commit

Permalink
Support local IDs for overlay of MARC records.
Browse files Browse the repository at this point in the history
refs #3555
  • Loading branch information
justinlittman committed Aug 8, 2022
1 parent e38de3d commit 2b1c610
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 32 deletions.
7 changes: 4 additions & 3 deletions __tests__/actionCreators/transfer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ describe("transfer", () => {
sinopiaApi.postTransfer = jest.fn().mockResolvedValue()
const store = mockStore(createState())
await store.dispatch(
transfer(resourceUri, "stanford", "ils", "testerrorkey")
transfer(resourceUri, "stanford", "ils", "abc123", "testerrorkey")
)

expect(store.getActions()).toHaveLength(0)
expect(sinopiaApi.postTransfer).toHaveBeenCalledWith(
resourceUri,
"stanford",
"ils"
"ils",
"abc123"
)
})
})
Expand All @@ -32,7 +33,7 @@ describe("transfer", () => {
sinopiaApi.postTransfer = jest.fn().mockRejectedValue("Ooops!")
const store = mockStore(createState())
await store.dispatch(
transfer(resourceUri, "stanford", "ils", "testerrorkey")
transfer(resourceUri, "stanford", "ils", "abc123", "testerrorkey")
)

expect(store.getActions()).toHaveAction("ADD_ERROR", {
Expand Down
33 changes: 32 additions & 1 deletion __tests__/feature/editing/transfer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jest.spyOn(Config, "transferConfig", "get").mockReturnValue({
},
})

describe("transfer saved bf:Instance when user belongs to a transfer group", () => {
describe("transfer saved bf:Instance when user belongs to a transfer group and no local ID", () => {
it("allows transfer", async () => {
const state = createState()
const store = createStore(state)
Expand All @@ -42,6 +42,37 @@ describe("transfer saved bf:Instance when user belongs to a transfer group", ()

const transferBtn = screen.getByText("Export to Catalog")
fireEvent.click(transferBtn)
fireEvent.click(await screen.findByText("Create a new record in catalog."))
await screen.findByText("Requesting")
}, 15000)
})

describe("transfer saved bf:Instance when user belongs to a transfer group and provided local ID", () => {
it("allows transfer", async () => {
const state = createState()
const store = createStore(state)
renderApp(store)

fireEvent.click(screen.getByText("Linked Data Editor", { selector: "a" }))

fireEvent.change(screen.getByLabelText("Search"), {
target: { value: bfUri },
})
fireEvent.click(screen.getByTestId("Submit search"))

await screen.findByText(bfUri)
fireEvent.click(screen.getByRole("button", { name: `Edit ${bfUri}` }))

await screen.findByText("The Practitioner's Guide to Graph Data", {
selector: resourceHeaderSelector,
})

const transferBtn = screen.getByText("Export to Catalog")
fireEvent.click(transferBtn)
fireEvent.change(await screen.findByLabelText("Enter local system id"), {
target: { value: "abc123" },
})
fireEvent.click(await screen.findByText("Go"))
await screen.findByText("Requesting")
}, 15000)
})
Expand Down
23 changes: 21 additions & 2 deletions __tests__/sinopiaApi.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,13 @@ describe("putUserHistory", () => {
})

describe("postTransfer", () => {
describe("success", () => {
describe("success without localId", () => {
it("returns", async () => {
global.fetch = jest.fn().mockResolvedValue({
ok: true,
})

await postTransfer(resourceUri, "stanford", "ils")
await postTransfer(resourceUri, "stanford", "ils", null)

expect(global.fetch).toHaveBeenCalledWith(
"https://api.development.sinopia.io/transfer/7b4c275d-b0c7-40a4-80b3-e95a0d9d987c/stanford/ils",
Expand All @@ -450,6 +450,25 @@ describe("postTransfer", () => {
)
})
})
describe("success with localId", () => {
it("returns", async () => {
global.fetch = jest.fn().mockResolvedValue({
ok: true,
})

await postTransfer(resourceUri, "stanford", "ils", "abc123")

expect(global.fetch).toHaveBeenCalledWith(
"https://api.development.sinopia.io/transfer/7b4c275d-b0c7-40a4-80b3-e95a0d9d987c/stanford/ils/abc123",
{
method: "POST",
headers: {
Authorization: "Bearer Secret-Token",
},
}
)
})
})
})

describe("fetchResourceRelationships", () => {
Expand Down
5 changes: 2 additions & 3 deletions src/actionCreators/transfer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ import { postTransfer } from "../sinopiaApi"
import { addError } from "actions/errors"

export const transfer =
(resourceUri, group, target, errorKey) => (dispatch) => {
postTransfer(resourceUri, group, target).catch((err) => {
(resourceUri, group, target, localId, errorKey) => (dispatch) =>
postTransfer(resourceUri, group, target, localId).catch((err) => {
dispatch(
addError(errorKey, `Error requesting transfer: ${err.message || err}`)
)
})
}

export const noop = () => {}
113 changes: 99 additions & 14 deletions src/components/editor/actions/TransferButton.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React, { useState, useEffect, useRef } from "react"
import PropTypes from "prop-types"
import _ from "lodash"

const TransferButton = ({ label, handleClick }) => {
const [btnText, setBtnText] = useState(label)
const TransferButton = ({ label, localId, group, target, handleTransfer }) => {
const [requesting, setRequesting] = useState(false)
const [providedLocalId, setProvidedLocalId] = useState("")
const timerRef = useRef(null)

useEffect(
Expand All @@ -12,27 +14,110 @@ const TransferButton = ({ label, handleClick }) => {
[]
)

const handleBtnClick = (event) => {
setBtnText(<em>Requesting</em>)
timerRef.current = setTimeout(() => setBtnText(label), 3000)
handleClick(event)
const handleExistingLocalIdClick = (event) => {
handleTransfer(localId)
notify()
event.preventDefault()
}

const handleProvidedLocalIdClick = (event) => {
handleTransfer(providedLocalId)
notify()
event.preventDefault()
}

const handleNoLocalIdClick = (event) => {
handleTransfer(null)
notify()
event.preventDefault()
}

const notify = () => {
setRequesting(true)
timerRef.current = setTimeout(() => setRequesting(false), 3000)
}

const handleChangeProvidedLocalId = (event) => {
setProvidedLocalId(event.target.value)
event.preventDefault()
}

if (requesting) {
return (
<button type="button" className="btn btn-secondary btn-no-outline">
<em>Requesting</em>
</button>
)
}

const btnId = `transferBtn-${group}-${target}`
const btnClasses = ["btn", "dropdown-toggle", "btn-no-outline"]
const dropDownItemBtnClasses = ["btn", "btn-secondary", "dropdown-item"]

return (
<button
type="button"
className="btn btn-secondary btn-no-outline"
onClick={handleBtnClick}
>
{btnText}
</button>
<div className="btn-group dropdown">
<button
type="button"
id={btnId}
className={btnClasses.join(" ")}
aria-label="Transfer to catalog"
title="Transfer to catalog"
data-bs-toggle="dropdown"
aria-expanded="false"
>
{label}
</button>
<div className="dropdown-menu dropdown-menu-end" aria-labelledby={btnId}>
{localId ? (
<React.Fragment>
<button
className={dropDownItemBtnClasses.join(" ")}
onClick={handleExistingLocalIdClick}
>
Export with local system ID: {localId}
</button>
</React.Fragment>
) : (
<React.Fragment>
<div className="dropdown-item">
Overlay record with local system ID:
<div className="input-group mb-3">
<input
type="text"
className="form-control"
aria-label="Enter local system id"
onChange={handleChangeProvidedLocalId}
value={providedLocalId}
/>
<button
className="btn btn-primary"
type="button"
disabled={_.isEmpty(providedLocalId)}
onClick={handleProvidedLocalIdClick}
>
Go
</button>
</div>
</div>
<button
className={dropDownItemBtnClasses.join(" ")}
onClick={handleNoLocalIdClick}
>
Create a new record in catalog.
</button>
</React.Fragment>
)}
</div>
</div>
)
}

TransferButton.propTypes = {
label: PropTypes.string.isRequired,
handleClick: PropTypes.func.isRequired,
group: PropTypes.string.isRequired,
target: PropTypes.string.isRequired,
localId: PropTypes.string,
handleTransfer: PropTypes.func.isRequired,
}

export default TransferButton
9 changes: 5 additions & 4 deletions src/components/editor/actions/TransferButtons.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,17 @@ const TransferButtons = ({ resourceKey }) => {
// Must be targets
if (_.isEmpty(transferTargets)) return null

const handleClick = (event, group, target) => {
dispatch(transfer(resource.uri, group, target, errorKey))
event.preventDefault()
const handleTransfer = (group, target, localId) => {
dispatch(transfer(resource.uri, group, target, localId, errorKey))
}

const buttons = transferTargets.map(([target, group, label]) => (
<TransferButton
key={`${group}-${target}`}
group={group}
target={target}
label={`Export to ${label}`}
handleClick={(event) => handleClick(event, group, target)}
handleTransfer={(localId) => handleTransfer(group, target, localId)}
/>
))

Expand Down
10 changes: 5 additions & 5 deletions src/sinopiaApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,11 @@ export const putUserHistory = (
)
}

export const postTransfer = (resourceUri, group, target) => {
const url = `${resourceUri.replace(
"resource",
"transfer"
)}/${group}/${target}`
export const postTransfer = (resourceUri, group, target, localId) => {
let url = `${resourceUri.replace("resource", "transfer")}/${group}/${target}`
if (localId) {
url += `/${localId}`
}
return getJwt()
.then((jwt) =>
fetch(url, {
Expand Down

0 comments on commit 2b1c610

Please sign in to comment.