-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16381 from davelopez/explore_doi_repository_integ…
…ration Add Invenio RDM repository integration
- Loading branch information
Showing
26 changed files
with
1,587 additions
and
92 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import { getLocalVue } from "@tests/jest/helpers"; | ||
import { mount, Wrapper } from "@vue/test-utils"; | ||
import flushPromises from "flush-promises"; | ||
|
||
import { mockFetcher } from "@/schema/__mocks__"; | ||
|
||
import { CreatedEntry } from "../FilesDialog/services"; | ||
|
||
import ExportRDMForm from "./ExportRDMForm.vue"; | ||
import FilesInput from "@/components/FilesDialog/FilesInput.vue"; | ||
|
||
jest.mock("@/schema"); | ||
|
||
const localVue = getLocalVue(true); | ||
|
||
const CREATE_RECORD_BTN = "#create-record-button"; | ||
const EXPORT_TO_NEW_RECORD_BTN = "#export-button-new-record"; | ||
const EXPORT_TO_EXISTING_RECORD_BTN = "#export-button-existing-record"; | ||
|
||
const FAKE_RDM_SOURCE_URI = "gxfiles://test-uri"; | ||
const FAKE_RDM_EXISTING_RECORD_URI = "gxfiles://test-uri/test-record"; | ||
const FAKE_RECORD_NAME = "test record name"; | ||
const FAKE_ENTRY: CreatedEntry = { | ||
uri: FAKE_RDM_SOURCE_URI, | ||
name: FAKE_RECORD_NAME, | ||
external_link: "http://example.com", | ||
}; | ||
|
||
async function initWrapper() { | ||
mockFetcher.path("/api/remote_files").method("post").mock({ data: FAKE_ENTRY }); | ||
|
||
const wrapper = mount(ExportRDMForm, { | ||
propsData: {}, | ||
localVue, | ||
}); | ||
await flushPromises(); | ||
return wrapper; | ||
} | ||
|
||
describe("ExportRDMForm", () => { | ||
let wrapper: Wrapper<Vue>; | ||
|
||
beforeEach(async () => { | ||
wrapper = await initWrapper(); | ||
}); | ||
|
||
describe("Export to new record", () => { | ||
beforeEach(async () => { | ||
await selectExportChoice("new"); | ||
}); | ||
|
||
it("enables the create new record button when the required fields are filled in", async () => { | ||
expect(wrapper.find(CREATE_RECORD_BTN).attributes("disabled")).toBeTruthy(); | ||
|
||
await setRecordNameInput(FAKE_RECORD_NAME); | ||
await setRDMSourceInput(FAKE_RDM_SOURCE_URI); | ||
|
||
expect(wrapper.find(CREATE_RECORD_BTN).attributes("disabled")).toBeFalsy(); | ||
}); | ||
|
||
it("displays the export to this record button when the create new record button is clicked", async () => { | ||
expect(wrapper.find(EXPORT_TO_NEW_RECORD_BTN).exists()).toBeFalsy(); | ||
|
||
await setRecordNameInput(FAKE_RECORD_NAME); | ||
await setRDMSourceInput(FAKE_RDM_SOURCE_URI); | ||
await clickCreateNewRecordButton(); | ||
|
||
expect(wrapper.find(EXPORT_TO_NEW_RECORD_BTN).exists()).toBeTruthy(); | ||
}); | ||
|
||
it("emits an export event when the export to new record button is clicked", async () => { | ||
await setFileNameInput("test file name"); | ||
await setRecordNameInput(FAKE_RECORD_NAME); | ||
await setRDMSourceInput(FAKE_RDM_SOURCE_URI); | ||
await clickCreateNewRecordButton(); | ||
|
||
await wrapper.find(EXPORT_TO_NEW_RECORD_BTN).trigger("click"); | ||
expect(wrapper.emitted("export")).toBeTruthy(); | ||
}); | ||
}); | ||
|
||
describe("Export to existing record", () => { | ||
beforeEach(async () => { | ||
await selectExportChoice("existing"); | ||
}); | ||
|
||
it("enables the export to existing record button when the required fields are filled in", async () => { | ||
expect(wrapper.find(EXPORT_TO_EXISTING_RECORD_BTN).attributes("disabled")).toBeTruthy(); | ||
|
||
await setFileNameInput("test file name"); | ||
await setRDMDirectoryInput(FAKE_RDM_EXISTING_RECORD_URI); | ||
|
||
expect(wrapper.find(EXPORT_TO_EXISTING_RECORD_BTN).attributes("disabled")).toBeFalsy(); | ||
}); | ||
|
||
it("emits an export event when the export to existing record button is clicked", async () => { | ||
await setFileNameInput("test file name"); | ||
await setRDMDirectoryInput(FAKE_RDM_EXISTING_RECORD_URI); | ||
await wrapper.find(EXPORT_TO_EXISTING_RECORD_BTN).trigger("click"); | ||
expect(wrapper.emitted("export")).toBeTruthy(); | ||
}); | ||
}); | ||
|
||
async function selectExportChoice(choice: string) { | ||
const exportChoice = wrapper.find(`#radio-${choice}`); | ||
await exportChoice.setChecked(true); | ||
} | ||
|
||
async function setRDMSourceInput(newValue: string) { | ||
const component = wrapper.findComponent(FilesInput); | ||
expect(component.attributes("placeholder")).toContain("source"); | ||
component.vm.$emit("input", newValue); | ||
await flushPromises(); | ||
} | ||
|
||
async function setRDMDirectoryInput(newValue: string) { | ||
const component = wrapper.findComponent(FilesInput); | ||
expect(component.attributes("placeholder")).toContain("directory"); | ||
component.vm.$emit("input", newValue); | ||
await flushPromises(); | ||
} | ||
|
||
async function setRecordNameInput(newValue: string) { | ||
const recordNameInput = wrapper.find("#record-name-input"); | ||
await recordNameInput.setValue(newValue); | ||
} | ||
|
||
async function setFileNameInput(newValue: string) { | ||
const recordNameInput = wrapper.find("#file-name-input"); | ||
await recordNameInput.setValue(newValue); | ||
} | ||
|
||
async function clickCreateNewRecordButton() { | ||
const createRecordButton = wrapper.find(CREATE_RECORD_BTN); | ||
expect(createRecordButton.attributes("disabled")).toBeFalsy(); | ||
await createRecordButton.trigger("click"); | ||
await flushPromises(); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
<script setup lang="ts"> | ||
import { BButton, BCard, BFormGroup, BFormInput, BFormRadio, BFormRadioGroup } from "bootstrap-vue"; | ||
import { computed, ref } from "vue"; | ||
import { CreatedEntry, createRemoteEntry, FilterFileSourcesOptions } from "@/components/FilesDialog/services"; | ||
import { useToast } from "@/composables/toast"; | ||
import localize from "@/utils/localization"; | ||
import { errorMessageAsString } from "@/utils/simple-error"; | ||
import ExternalLink from "@/components/ExternalLink.vue"; | ||
import FilesInput from "@/components/FilesDialog/FilesInput.vue"; | ||
const toast = useToast(); | ||
interface Props { | ||
what?: string; | ||
clearInputAfterExport?: boolean; | ||
defaultRecordName?: string; | ||
defaultFilename?: string; | ||
} | ||
const props = withDefaults(defineProps<Props>(), { | ||
what: "archive", | ||
clearInputAfterExport: false, | ||
defaultRecordName: "", | ||
defaultFilename: "", | ||
}); | ||
const emit = defineEmits<{ | ||
(e: "export", recordUri: string, fileName: string, newRecordName?: string): void; | ||
}>(); | ||
type ExportChoice = "existing" | "new"; | ||
const includeOnlyRDMCompatible: FilterFileSourcesOptions = { include: ["rdm"] }; | ||
const recordUri = ref<string>(""); | ||
const sourceUri = ref<string>(""); | ||
const fileName = ref<string>(props.defaultFilename); | ||
const exportChoice = ref<ExportChoice>("new"); | ||
const recordName = ref<string>(props.defaultRecordName); | ||
const newEntry = ref<CreatedEntry>(); | ||
const canCreateRecord = computed(() => Boolean(sourceUri.value) && Boolean(recordName.value)); | ||
const canExport = computed(() => Boolean(recordUri.value) && Boolean(fileName.value)); | ||
const repositoryRecordDescription = computed(() => localize(`Select a repository to export ${props.what} to.`)); | ||
const nameDescription = computed(() => localize("Give the exported file a name.")); | ||
const recordNameDescription = computed(() => localize("Give the new record a name or title.")); | ||
const namePlaceholder = computed(() => localize("File name")); | ||
const recordNamePlaceholder = computed(() => localize("Record name")); | ||
function doExport() { | ||
emit("export", recordUri.value, fileName.value); | ||
if (props.clearInputAfterExport) { | ||
clearInputs(); | ||
} | ||
} | ||
async function doCreateRecord() { | ||
try { | ||
newEntry.value = await createRemoteEntry(sourceUri.value, recordName.value); | ||
recordUri.value = newEntry.value.uri; | ||
} catch (e) { | ||
toast.error(errorMessageAsString(e)); | ||
} | ||
} | ||
function clearInputs() { | ||
recordUri.value = ""; | ||
sourceUri.value = ""; | ||
fileName.value = ""; | ||
newEntry.value = undefined; | ||
} | ||
</script> | ||
|
||
<template> | ||
<div class="export-to-rdm-repository"> | ||
<BFormGroup id="fieldset-name" label-for="name" :description="nameDescription" class="mt-3"> | ||
<BFormInput id="file-name-input" v-model="fileName" :placeholder="namePlaceholder" required /> | ||
</BFormGroup> | ||
|
||
<BFormRadioGroup v-model="exportChoice" class="export-radio-group"> | ||
<BFormRadio id="radio-new" v-localize name="exportChoice" value="new"> Export to new record </BFormRadio> | ||
<BFormRadio id="radio-existing" v-localize name="exportChoice" value="existing"> | ||
Export to existing draft record | ||
</BFormRadio> | ||
</BFormRadioGroup> | ||
|
||
<div v-if="exportChoice === 'new'"> | ||
<div v-if="newEntry"> | ||
<BCard> | ||
<p> | ||
<b>{{ newEntry.name }}</b> | ||
<span v-localize> draft record has been created in the repository.</span> | ||
</p> | ||
<p v-if="newEntry.external_link"> | ||
You can preview the record in the repository, further edit its metadata and decide when to | ||
publish it at | ||
<ExternalLink :href="newEntry.external_link"> | ||
<b>{{ newEntry.external_link }}</b> | ||
</ExternalLink> | ||
</p> | ||
<p v-localize>Please use the button below to upload the exported {{ props.what }} to the record.</p> | ||
<BButton | ||
id="export-button-new-record" | ||
v-localize | ||
class="export-button" | ||
variant="primary" | ||
:disabled="!canExport" | ||
@click.prevent="doExport"> | ||
Export to this record | ||
</BButton> | ||
</BCard> | ||
</div> | ||
<div v-else> | ||
<BFormGroup | ||
id="fieldset-record-new" | ||
label-for="source-selector" | ||
:description="repositoryRecordDescription" | ||
class="mt-3"> | ||
<FilesInput | ||
id="source-selector" | ||
v-model="sourceUri" | ||
mode="source" | ||
:require-writable="true" | ||
:filter-options="includeOnlyRDMCompatible" /> | ||
</BFormGroup> | ||
<BFormGroup | ||
id="fieldset-record-name" | ||
label-for="record-name" | ||
:description="recordNameDescription" | ||
class="mt-3"> | ||
<BFormInput | ||
id="record-name-input" | ||
v-model="recordName" | ||
:placeholder="recordNamePlaceholder" | ||
required /> | ||
</BFormGroup> | ||
<p v-localize> | ||
You need to create the new record in a repository before exporting the {{ props.what }} to it. | ||
</p> | ||
<BButton | ||
id="create-record-button" | ||
v-localize | ||
variant="primary" | ||
:disabled="!canCreateRecord" | ||
@click.prevent="doCreateRecord"> | ||
Create new record | ||
</BButton> | ||
</div> | ||
</div> | ||
<div v-else> | ||
<BFormGroup | ||
id="fieldset-record-existing" | ||
label-for="existing-record-selector" | ||
:description="repositoryRecordDescription" | ||
class="mt-3"> | ||
<FilesInput | ||
id="existing-record-selector" | ||
v-model="recordUri" | ||
mode="directory" | ||
:require-writable="true" | ||
:filter-options="includeOnlyRDMCompatible" /> | ||
</BFormGroup> | ||
<BButton | ||
id="export-button-existing-record" | ||
v-localize | ||
class="export-button" | ||
variant="primary" | ||
:disabled="!canExport" | ||
@click.prevent="doExport"> | ||
Export to existing record | ||
</BButton> | ||
</div> | ||
</div> | ||
</template> |
Oops, something went wrong.