hotfix(dataset): enhance dataset creation and editing forms
- Added functionality to add new authors and contributors directly within the dataset creation and editing forms. - Implemented `addNewAuthor` and `addNewContributor` methods to dynamically add new person objects to the authors and contributors arrays in the form data. - Added header icons with click events to the `CardBox` component for authors and contributors sections to trigger the addition of new entries. - Updated the dataset index views for reviewers and editors to improve the display of dataset titles, including adding a CSS class to truncate long titles. - Ensured authors and contributors are ordered by `pivot_sort_order` when preloading in the Dataset and Editor controllers. - Fixed an issue where pressing enter in the `SearchAutocomplete` component would submit the form. - Updated validation messages to be available in the `updateEditorDatasetValidator`.
This commit is contained in:
parent
f04c1f6327
commit
106f8d5f27
10 changed files with 379 additions and 382 deletions
|
@ -504,8 +504,8 @@ export default class DatasetsController {
|
|||
.preload('descriptions', (query) => query.orderBy('id', 'asc'))
|
||||
.preload('coverage')
|
||||
.preload('licenses')
|
||||
.preload('authors')
|
||||
.preload('contributors')
|
||||
.preload('authors', (query) => query.orderBy('pivot_sort_order', 'asc'))
|
||||
.preload('contributors', (query) => query.orderBy('pivot_sort_order', 'asc'))
|
||||
// .preload('subjects')
|
||||
.preload('subjects', (builder) => {
|
||||
builder.orderBy('id', 'asc').withCount('datasets');
|
||||
|
|
|
@ -924,8 +924,8 @@ export default class DatasetController {
|
|||
.preload('descriptions', (query) => query.orderBy('id', 'asc'))
|
||||
.preload('coverage')
|
||||
.preload('licenses')
|
||||
.preload('authors')
|
||||
.preload('contributors')
|
||||
.preload('authors', (query) => query.orderBy('pivot_sort_order', 'asc'))
|
||||
.preload('contributors', (query) => query.orderBy('pivot_sort_order', 'asc'))
|
||||
// .preload('subjects')
|
||||
.preload('subjects', (builder) => {
|
||||
builder.orderBy('id', 'asc').withCount('datasets');
|
||||
|
|
|
@ -500,4 +500,5 @@ let messagesProvider = new SimpleMessagesProvider({
|
|||
|
||||
createDatasetValidator.messagesProvider = messagesProvider;
|
||||
updateDatasetValidator.messagesProvider = messagesProvider;
|
||||
updateEditorDatasetValidator.messagesProvider = messagesProvider;
|
||||
// export default createDatasetValidator;
|
||||
|
|
614
package-lock.json
generated
614
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -28,7 +28,7 @@
|
|||
autocomplete="off"
|
||||
@keydown.down="onArrowDown"
|
||||
@keydown.up="onArrowUp"
|
||||
@keydown.enter="onEnter"
|
||||
@keydown.enter.prevent="onEnter"
|
||||
/>
|
||||
<svg
|
||||
class="w-4 h-4 absolute left-2.5 top-3.5"
|
||||
|
|
|
@ -232,7 +232,8 @@
|
|||
</CardBox>
|
||||
|
||||
<!-- (7) authors -->
|
||||
<CardBox class="mb-6 shadow" has-table title="Creators" :icon="mdiBookOpenPageVariant">
|
||||
<CardBox class="mb-6 shadow" has-table title="Creators" :icon="mdiBookOpenPageVariant"
|
||||
:header-icon="mdiPlusCircle" v-on:header-icon-click="addNewAuthor()">
|
||||
<SearchAutocomplete source="/api/persons" :response-property="'first_name'"
|
||||
placeholder="search in person table...." v-on:person="onAddAuthor"></SearchAutocomplete>
|
||||
|
||||
|
@ -245,7 +246,8 @@
|
|||
|
||||
|
||||
<!-- (8) contributors -->
|
||||
<CardBox class="mb-6 shadow" has-table title="Contributors" :icon="mdiBookOpenPageVariant">
|
||||
<CardBox class="mb-6 shadow" has-table title="Contributors" :icon="mdiBookOpenPageVariant"
|
||||
:header-icon="mdiPlusCircle" v-on:header-icon-click="addNewContributor()">
|
||||
<SearchAutocomplete source="/api/persons" :response-property="'first_name'"
|
||||
placeholder="search in person table...." v-on:person="onAddContributor">
|
||||
</SearchAutocomplete>
|
||||
|
@ -734,6 +736,11 @@ const removeDescription = (key: any) => {
|
|||
form.descriptions.splice(key, 1);
|
||||
};
|
||||
|
||||
const addNewAuthor = () => {
|
||||
let newAuthor = { status: false, first_name: '', last_name: '', email: '', academic_title: '', identifier_orcid: '', name_type: 'Personal' };
|
||||
form.authors.push(newAuthor);
|
||||
};
|
||||
|
||||
const onAddAuthor = (person: Person) => {
|
||||
if (form.authors.filter((e) => e.id === person.id).length > 0) {
|
||||
notify({ type: 'warning', title: 'Warning', text: 'person is already defined as author' }, 4000);
|
||||
|
@ -745,6 +752,11 @@ const onAddAuthor = (person: Person) => {
|
|||
}
|
||||
};
|
||||
|
||||
const addNewContributor = () => {
|
||||
let newContributor = { status: false, first_name: '', last_name: '', email: '', academic_title: '', identifier_orcid: '', name_type: 'Personal', pivot: { contributor_type: '' } };
|
||||
form.contributors.push(newContributor);
|
||||
};
|
||||
|
||||
const onAddContributor = (person: Person) => {
|
||||
if (form.contributors.filter((e) => e.id === person.id).length > 0) {
|
||||
notify({ type: 'warning', title: 'Warning', text: 'person is already defined as contributor' }, 4000);
|
||||
|
|
|
@ -196,7 +196,7 @@ const formatServerState = (state: string) => {
|
|||
<BaseButton
|
||||
v-if="can.approve && (dataset.server_state == 'editor_accepted' || dataset.server_state == 'rejected_reviewer')"
|
||||
:route-name="stardust.route('editor.dataset.reject', [dataset.id])"
|
||||
color="info" :icon="mdiUndo" label="'Reject'" small class="col-span-1">
|
||||
color="info" :icon="mdiUndo" label="Reject" small class="col-span-1">
|
||||
</BaseButton>
|
||||
|
||||
<BaseButton
|
||||
|
|
|
@ -122,12 +122,9 @@ const formatServerState = (state: string) => {
|
|||
|
||||
<tbody>
|
||||
<tr v-for="dataset in props.datasets.data" :key="dataset.id" :class="[getRowClass(dataset)]">
|
||||
<td data-label="Login" class="py-4 whitespace-nowrap text-gray-700 dark:text-white">
|
||||
<!-- <Link v-bind:href="stardust.route('user.show', [user.id])"
|
||||
class="no-underline hover:underline text-cyan-600 dark:text-cyan-400">
|
||||
{{ user.login }}
|
||||
</Link> -->
|
||||
<div class="text-sm font-medium">{{ dataset.main_title }}</div>
|
||||
<td data-label="Login"
|
||||
class="py-4 whitespace-nowrap text-gray-700 dark:text-white">
|
||||
<div class="text-sm table-title">{{ dataset.main_title }}</div>
|
||||
</td>
|
||||
<td class="py-4 whitespace-nowrap text-gray-700 dark:text-white">
|
||||
<div class="text-sm">{{ dataset.id }}</div>
|
||||
|
@ -185,3 +182,16 @@ const formatServerState = (state: string) => {
|
|||
</LayoutAuthenticated>
|
||||
</template>
|
||||
|
||||
<style scoped lang="css">
|
||||
.table-title {
|
||||
max-width: 200px;
|
||||
/* set a maximum width */
|
||||
overflow: hidden;
|
||||
/* hide overflow */
|
||||
text-overflow: ellipsis;
|
||||
/* show ellipsis for overflowed text */
|
||||
white-space: nowrap;
|
||||
/* prevent wrapping */
|
||||
}
|
||||
|
||||
</style>
|
|
@ -444,6 +444,12 @@ const onAddAuthor = (person: Person) => {
|
|||
notify({ type: 'info', text: 'person has been successfully added as author' });
|
||||
}
|
||||
};
|
||||
|
||||
const addNewContributor = () => {
|
||||
let newContributor = { status: false, first_name: '', last_name: '', email: '', academic_title: '', identifier_orcid: '', name_type: 'Personal', pivot: { contributor_type: '' } };
|
||||
form.contributors.push(newContributor);
|
||||
};
|
||||
|
||||
const onAddContributor = (person: Person) => {
|
||||
if (form.contributors.filter((e) => e.id === person.id).length > 0) {
|
||||
notify({ type: 'warning', title: 'Warning', text: 'person is already defined as contributor' }, 4000);
|
||||
|
@ -588,8 +594,10 @@ Removes a selected keyword
|
|||
<input class="form-checkbox" name="rights" id="rights" type="checkbox" v-model="dataset.rights" />
|
||||
terms and conditions
|
||||
</label> -->
|
||||
<FormField label="Rights" help="You must agree that you have read the Terms and Conditions. Please click on the 'i' icon to find a read the policy" wrap-body
|
||||
:class="{ 'text-red-400': form.errors.rights }" class="mt-8 w-full mx-2 flex-1 flex-col">
|
||||
<FormField label="Rights"
|
||||
help="You must agree that you have read the Terms and Conditions. Please click on the 'i' icon to find a read the policy"
|
||||
wrap-body :class="{ 'text-red-400': form.errors.rights }"
|
||||
class="mt-8 w-full mx-2 flex-1 flex-col">
|
||||
<label for="rights" class="checkbox mr-6 mb-3 last:mr-0">
|
||||
<input type="checkbox" id="rights" required v-model="form.rights" />
|
||||
<span class="check" />
|
||||
|
@ -797,8 +805,8 @@ Removes a selected keyword
|
|||
|
||||
<TablePersons :errors="form.errors" :persons="form.authors" :relation="'authors'"
|
||||
v-if="form.authors.length > 0" />
|
||||
<div class="text-red-400 text-sm" v-if="errors.authors && Array.isArray(errors.authors)">
|
||||
{{ errors.authors.join(', ') }}
|
||||
<div class="text-red-400 text-sm" v-if="form.errors.authors && Array.isArray(form.errors.authors)">
|
||||
{{ form.errors.authors.join(', ') }}
|
||||
</div>
|
||||
<div class="w-full md:w-1/2">
|
||||
<label class="block" for="additionalCreators">Add additional creator(s) if creator is
|
||||
|
@ -821,6 +829,12 @@ Removes a selected keyword
|
|||
v-if="form.errors.contributors && Array.isArray(form.errors.contributors)">
|
||||
{{ form.errors.contributors.join(', ') }}
|
||||
</div>
|
||||
<div class="w-full md:w-1/2">
|
||||
<label class="block" for="additionalCreators">Add additional contributor(s) if
|
||||
contributor is not in database</label>
|
||||
<button class="bg-blue-500 text-white py-2 px-4 rounded-sm"
|
||||
@click.prevent="addNewContributor()">+</button>
|
||||
</div>
|
||||
</CardBox>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -241,11 +241,13 @@
|
|||
</CardBox>
|
||||
|
||||
<!-- (7) authors -->
|
||||
<CardBox class="mb-6 shadow" has-table title="Creators" :icon="mdiBookOpenPageVariant">
|
||||
<CardBox class="mb-6 shadow" has-table title="Creators" :icon="mdiBookOpenPageVariant"
|
||||
:header-icon="mdiPlusCircle" v-on:header-icon-click="addNewAuthor()">
|
||||
<SearchAutocomplete source="/api/persons" :response-property="'first_name'"
|
||||
placeholder="search in person table...." v-on:person="onAddAuthor"></SearchAutocomplete>
|
||||
|
||||
<TablePersons :persons="form.authors" v-if="form.authors.length > 0" :relation="'authors'" />
|
||||
<TablePersons :persons="form.authors" v-if="form.authors.length > 0" :errors="form.errors"
|
||||
:relation="'authors'" />
|
||||
<div class="text-red-400 text-sm"
|
||||
v-if="form.errors.authors && Array.isArray(form.errors.authors)">
|
||||
{{ form.errors.authors.join(', ') }}
|
||||
|
@ -254,7 +256,8 @@
|
|||
|
||||
|
||||
<!-- (8) contributors -->
|
||||
<CardBox class="mb-6 shadow" has-table title="Contributors" :icon="mdiBookOpenPageVariant">
|
||||
<CardBox class="mb-6 shadow" has-table title="Contributors" :icon="mdiBookOpenPageVariant"
|
||||
:header-icon="mdiPlusCircle" v-on:header-icon-click="addNewContributor()">
|
||||
<SearchAutocomplete source="/api/persons" :response-property="'first_name'"
|
||||
placeholder="search in person table...." v-on:person="onAddContributor">
|
||||
</SearchAutocomplete>
|
||||
|
@ -422,7 +425,8 @@
|
|||
class="bg-red-100 group w-full h-full rounded-md cursor-pointer relative shadow-sm overflow-hidden">
|
||||
<section
|
||||
class="flex flex-col rounded-md text-xs break-words w-full h-full z-20 absolute top-0 py-2 px-3">
|
||||
<h1 class="flex-1 text-gray-700 group-hover:text-blue-800 font-medium text-sm mb-1 truncate overflow-hidden whitespace-nowrap">
|
||||
<h1
|
||||
class="flex-1 text-gray-700 group-hover:text-blue-800 font-medium text-sm mb-1 truncate overflow-hidden whitespace-nowrap">
|
||||
{{ element.value }}
|
||||
</h1>
|
||||
<div class="flex flex-col mt-auto">
|
||||
|
@ -431,7 +435,7 @@
|
|||
</p>
|
||||
<p class="p-1 size text-xs text-gray-700">
|
||||
<span class="font-semibold">Relation:</span> {{ element.relation }}
|
||||
</p>
|
||||
</p>
|
||||
<div class="flex justify-end mt-1">
|
||||
<button
|
||||
class="restore ml-auto focus:outline-none hover:bg-gray-300 p-1 rounded-md text-gray-800"
|
||||
|
@ -533,8 +537,6 @@
|
|||
// import EditComponent from "./../EditComponent";
|
||||
// export default EditComponent;
|
||||
|
||||
// import { Component, Vue, Prop, Setup, toNative } from 'vue-facing-decorator';
|
||||
// import AuthLayout from '@/Layouts/Auth.vue';
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import { useForm, Head, usePage } from '@inertiajs/vue3';
|
||||
import { computed, ComputedRef } from 'vue';
|
||||
|
@ -634,12 +636,6 @@ const flash: ComputedRef<any> = computed(() => {
|
|||
const errors: ComputedRef<any> = computed(() => {
|
||||
return usePage().props.errors;
|
||||
});
|
||||
// const errors: ComputedRef<any> = computed(() => {
|
||||
// return usePage().props.errors;
|
||||
// });
|
||||
|
||||
// const projects = reactive([]);
|
||||
// const licenses = reactive([]);
|
||||
|
||||
const mapOptions: MapOptions = {
|
||||
center: [48.208174, 16.373819],
|
||||
|
@ -679,44 +675,8 @@ props.dataset.subjectsToDelete = [];
|
|||
props.dataset.referencesToDelete = [];
|
||||
let form = useForm<Dataset>(props.dataset as Dataset);
|
||||
|
||||
// const mainService = MainService();
|
||||
// mainService.fetchfiles(props.dataset);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// const files = computed(() => props.dataset.file);
|
||||
|
||||
|
||||
|
||||
// let form = useForm<Dataset>(props.dataset as Dataset);
|
||||
|
||||
// const form = useForm({
|
||||
// _method: 'put',
|
||||
// login: props.user.login,
|
||||
// email: props.user.email,
|
||||
// password: '',
|
||||
// password_confirmation: '',
|
||||
// roles: props.userHasRoles, // fill actual user roles from db
|
||||
// });
|
||||
|
||||
// async created() {
|
||||
// // Fetch the list of projects and licenses from the server
|
||||
// const response = await fetch('/api/datasets/edit/' + this.dataset.id);
|
||||
// const data = await response.json();
|
||||
// this.projects = data.projects;
|
||||
// this.licenses = data.licenses;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
const submit = async (): Promise<void> => {
|
||||
let route = stardust.route('dataset.update', [props.dataset.id]);
|
||||
// await Inertia.post('/app/register', this.form);
|
||||
// await router.post('/app/register', this.form);
|
||||
|
||||
|
||||
let licenses = form.licenses.map((obj) => {
|
||||
if (hasIdAttribute(obj)) {
|
||||
|
@ -726,12 +686,6 @@ const submit = async (): Promise<void> => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// const files = form.files.map((obj) => {
|
||||
// return new File([obj.blob], obj.label, { type: obj.type, lastModified: obj.lastModified });
|
||||
// });
|
||||
|
||||
const [fileUploads, fileInputs] = form.files?.reduce(
|
||||
([fileUploads, fileInputs], obj) => {
|
||||
if (!obj.id) {
|
||||
|
@ -815,6 +769,11 @@ const removeDescription = (key: any) => {
|
|||
form.descriptions.splice(key, 1);
|
||||
};
|
||||
|
||||
const addNewAuthor = () => {
|
||||
let newAuthor = { status: false, first_name: '', last_name: '', email: '', academic_title: '', identifier_orcid: '', name_type: 'Personal' };
|
||||
form.authors.push(newAuthor);
|
||||
};
|
||||
|
||||
const onAddAuthor = (person: Person) => {
|
||||
if (form.authors.filter((e) => e.id === person.id).length > 0) {
|
||||
notify({ type: 'warning', title: 'Warning', text: 'person is already defined as author' }, 4000);
|
||||
|
@ -826,6 +785,11 @@ const onAddAuthor = (person: Person) => {
|
|||
}
|
||||
};
|
||||
|
||||
const addNewContributor = () => {
|
||||
let newContributor = { status: false, first_name: '', last_name: '', email: '', academic_title: '', identifier_orcid: '', name_type: 'Personal', pivot: { contributor_type: '' } };
|
||||
form.contributors.push(newContributor);
|
||||
};
|
||||
|
||||
const onAddContributor = (person: Person) => {
|
||||
if (form.contributors.filter((e) => e.id === person.id).length > 0) {
|
||||
notify({ type: 'warning', title: 'Warning', text: 'person is already defined as contributor' }, 4000);
|
||||
|
|
Loading…
Add table
Reference in a new issue