diff --git a/app/Controllers/Http/Submitter/DatasetController.ts b/app/Controllers/Http/Submitter/DatasetController.ts index 70d19ce..64272b2 100644 --- a/app/Controllers/Http/Submitter/DatasetController.ts +++ b/app/Controllers/Http/Submitter/DatasetController.ts @@ -23,6 +23,7 @@ import { ReferenceIdentifierTypes, RelationTypes, DatasetTypes, + SubjectTypes, } from 'Contracts/enums'; import type { ModelQueryBuilderContract } from '@ioc:Adonis/Lucid/Orm'; import DatasetReference from 'App/Models/DatasetReference'; @@ -131,6 +132,8 @@ export default class DatasetController { projects: projects, referenceIdentifierTypes: Object.entries(ReferenceIdentifierTypes).map(([key, value]) => ({ value: key, label: value })), relationTypes: Object.entries(RelationTypes).map(([key, value]) => ({ value: key, label: value })), + contributorTypes: ContributorTypes, + subjectTypes: SubjectTypes }); } @@ -190,7 +193,12 @@ export default class DatasetController { }), ), authors: schema.array([rules.minLength(1)]).members(schema.object().members({ email: schema.string({ trim: true }) })), - + contributors: schema.array.optional().members( + schema.object().members({ + email: schema.string({ trim: true }), + pivot_contributor_type: schema.enum(Object.keys(ContributorTypes)), + }), + ), // project_id: schema.number(), }); @@ -240,6 +248,12 @@ export default class DatasetController { }), ), authors: schema.array([rules.minLength(1)]).members(schema.object().members({ email: schema.string({ trim: true }) })), + contributors: schema.array.optional().members( + schema.object().members({ + email: schema.string({ trim: true }), + pivot_contributor_type: schema.enum(Object.keys(ContributorTypes)), + }), + ), // third step project_id: schema.number.optional(), embargo_date: schema.date.optional({ format: 'yyyy-MM-dd' }, [rules.after(10, 'days')]), @@ -481,31 +495,41 @@ export default class DatasetController { private async savePersons(dataset: Dataset, persons: any[], role: string, trx: TransactionClientContract) { for (const [key, person] of persons.entries()) { - const pivotData = { role: role, sort_order: key + 1 }; + const pivotData = { + role: role, + sort_order: key + 1, + allow_email_contact: false, + ...this.extractPivotAttributes(person), // Merge pivot attributes here + }; if (person.id !== undefined) { await dataset .useTransaction(trx) .related('persons') .attach({ - [person.id]: { - role: pivotData.role, - sort_order: pivotData.sort_order, - allow_email_contact: false, - }, + [person.id]: pivotData, }); } else { const dataPerson = new Person(); dataPerson.fill(person); - await dataset.useTransaction(trx).related('persons').save(dataPerson, false, { - role: pivotData.role, - sort_order: pivotData.sort_order, - allow_email_contact: false, - }); + await dataset.useTransaction(trx).related('persons').save(dataPerson, false, pivotData); } } } + // Helper function to extract pivot attributes from a person object + private extractPivotAttributes(person: any) { + const pivotAttributes = {}; + for (const key in person) { + if (key.startsWith('pivot_')) { + // pivotAttributes[key] = person[key]; + const cleanKey = key.replace('pivot_', ''); // Remove 'pivot_' prefix + pivotAttributes[cleanKey] = person[key]; + } + } + return pivotAttributes; + } + public messages: CustomMessages = { 'minLength': '{{ field }} must be at least {{ options.minLength }} characters long', 'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long', @@ -532,6 +556,7 @@ export default class DatasetController { 'The language of the translated description must be different from the language of the dataset', 'authors.minLength': 'at least {{ options.minLength }} author must be defined', + 'contributors.*.pivot_contributor_type.required': 'contributor type is required, if defined', 'after': `{{ field }} must be older than ${dayjs().add(10, 'day')}`, diff --git a/app/Validators/CreateDatasetValidator.ts b/app/Validators/CreateDatasetValidator.ts index 0552e14..bdaaa9b 100644 --- a/app/Validators/CreateDatasetValidator.ts +++ b/app/Validators/CreateDatasetValidator.ts @@ -1,7 +1,7 @@ import { schema, CustomMessages, rules } from '@ioc:Adonis/Core/Validator'; import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'; import dayjs from 'dayjs'; -import { TitleTypes, DescriptionTypes, RelationTypes, ReferenceIdentifierTypes } from 'Contracts/enums'; +import { TitleTypes, DescriptionTypes, RelationTypes, ReferenceIdentifierTypes, ContributorTypes } from 'Contracts/enums'; export default class CreateDatasetValidator { constructor(protected ctx: HttpContextContract) {} @@ -58,6 +58,12 @@ export default class CreateDatasetValidator { }), ), authors: schema.array([rules.minLength(1)]).members(schema.object().members({ email: schema.string({ trim: true }) })), + contributors: schema.array.optional().members( + schema.object().members({ + email: schema.string({ trim: true }), + pivot_contributor_type: schema.enum(Object.keys(ContributorTypes)), + }), + ), // third step project_id: schema.number.optional(), embargo_date: schema.date.optional({ format: 'yyyy-MM-dd' }, [rules.after(10, 'days')]), @@ -149,6 +155,7 @@ export default class CreateDatasetValidator { 'The language of the translated description must be different from the language of the dataset', 'authors.minLength': 'at least {{ options.minLength }} author must be defined', + 'contributors.*.pivot_contributor_type.required': 'contributor type is required, if defined', 'after': `{{ field }} must be older than ${dayjs().add(10, 'day')}`, diff --git a/contracts/enums.ts b/contracts/enums.ts index 732600d..ee905c8 100644 --- a/contracts/enums.ts +++ b/contracts/enums.ts @@ -54,31 +54,32 @@ export enum PersonRoles { } export enum ContributorTypes { - contact_person = 'ContactPerson', - data_collector = 'DataCollector', - data_curator = 'DataCurator', - data_manager = 'DataManager', + ContactPerson = 'ContactPerson', + DataCollector = 'DataCollector', + DataCurator = 'DataCurator', + DataManager = 'DataManager', Distributor = 'Distributor', - editor = 'Editor', - hosting_institution = 'HostingInstitution', - producer = 'Producer', - poroject_leader = 'ProjectLeader', - project_manager = 'ProjectManager', - project_member = 'ProjectMember', - registration_agency = 'RegistrationAgency', - registration_authority = 'RegistrationAuthority', - related_person = 'RelatedPerson', - researcher = 'Researcher', - research_group = 'ResearchGroup', - rights_holder = 'RightsHolder', - sponsor = 'Sponsor', - supervisor = 'Supervisor', - work_package_leader = 'WorkPackageLeader', - other = 'Other', + Editor = 'Editor', + HostingInstitution = 'HostingInstitution', + Producer = 'Producer', + ProjectLeader = 'ProjectLeader', + ProjectManager = 'ProjectManager', + ProjectMember = 'ProjectMember', + RegistrationAgency = 'RegistrationAgency', + RegistrationAuthority = 'RegistrationAuthority', + RelatedPerson = 'RelatedPerson', + Researcher = 'Researcher', + ResearchGroup = 'ResearchGroup', + RightsHolder = 'RightsHolder', + Sponsor = 'Sponsor', + Supervisor = 'Supervisor', + WorkPackageLeader = 'WorkPackageLeader', + Other = 'Other', } export enum SubjectTypes { uncontrolled = 'uncontrolled', + geoera = 'GeoEra', } export enum ReferenceIdentifierTypes { diff --git a/database/migrations/dataset_11_subjects.ts b/database/migrations/dataset_11_subjects.ts index eb2cb37..0495fb0 100644 --- a/database/migrations/dataset_11_subjects.ts +++ b/database/migrations/dataset_11_subjects.ts @@ -9,7 +9,7 @@ export default class DatasetSubjects extends BaseSchema { table.bigIncrements('id').defaultTo("nextval('dataset_subjects_id_seq')"); table.string('language', 3); // table.string('type', 255).notNullable().defaultTo('uncontrolled'); - table.enum('type', Object.values(SubjectTypes)).defaultTo('uncontrolled'); + table.enum('type', Object.keys(SubjectTypes)).defaultTo('uncontrolled'); table.string('value', 255).notNullable(); table.string('external_key', 255); table.timestamp('created_at', { useTz: false }).nullable(); diff --git a/resources/css/_table.css b/resources/css/_table.css index 8af7b34..44357d1 100644 --- a/resources/css/_table.css +++ b/resources/css/_table.css @@ -40,9 +40,9 @@ table { @apply lg:bg-gray-50 lg:dark:bg-slate-800; } - /* tbody tr:nth-child(even) { - @apply lg:bg-gray-50 lg:dark:bg-slate-800 lg:bg-opacity-25; - } */ + tbody tr:nth-child(even) { + @apply lg:bg-gray-50 lg:dark:bg-slate-600 lg:bg-opacity-25; + } td:before { content: attr(data-label); diff --git a/resources/js/Components/SearchCategoryAutocomplete.vue b/resources/js/Components/SearchCategoryAutocomplete.vue index 6f5342f..e5cb179 100644 --- a/resources/js/Components/SearchCategoryAutocomplete.vue +++ b/resources/js/Components/SearchCategoryAutocomplete.vue @@ -235,7 +235,7 @@ const inputElClass = computed(() => { // dark:placeholder-gray-400 dark:text-white dark:focus:border-blue-500" const base = [ 'block p-2.5 w-full z-20 text-sm text-gray-900 bg-gray-50 rounded-r-lg', - 'dark:placeholder-gray-400', + 'dark:placeholder-gray-400 dark:text-white dark:focus:border-blue-500', 'h-12', props.borderless ? 'border-0' : 'border', props.transparent ? 'bg-transparent' : 'bg-white dark:bg-slate-800', diff --git a/resources/js/Components/TableKeywords.vue b/resources/js/Components/TableKeywords.vue index 9f71b9c..2310004 100644 --- a/resources/js/Components/TableKeywords.vue +++ b/resources/js/Components/TableKeywords.vue @@ -20,6 +20,10 @@ const props = defineProps({ type: Array, default: () => [], }, + subjectTypes: { + type: Object, + default: () => ({}), + }, errors: { type: Object, default: () => ({}), @@ -102,73 +106,59 @@ const removeItem = (key) => { - Type - Value - Language + Type + Value + Language - + - + - - + +
{{ errors[`subjects.${index}.type`].join(', ') }}
- - + +
{{ errors[`subjects.${index}.value`].join(', ') }}
- +
{{ errors[`subjects.${index}.value`].join(', ') }}
- - + +
{{ errors[`subjects.${index}.language`].join(', ') }}
- + - + @@ -179,15 +169,8 @@ const removeItem = (key) => {
- + Page {{ currentPageHuman }} of {{ numPages }} @@ -197,3 +180,14 @@ const removeItem = (key) => { {{ errors.subjects.join(', ') }}
+ + diff --git a/resources/js/Components/TablePersons.vue b/resources/js/Components/TablePersons.vue index ffbfdff..d7d0913 100644 --- a/resources/js/Components/TablePersons.vue +++ b/resources/js/Components/TablePersons.vue @@ -7,13 +7,14 @@ import { mdiDragVariant } from '@mdi/js'; import BaseIcon from '@/Components/BaseIcon.vue'; // import CardBoxModal from '@/Components/CardBoxModal.vue'; // import TableCheckboxCell from '@/Components/TableCheckboxCell.vue'; -import BaseLevel from '@/Components/BaseLevel.vue'; +// import BaseLevel from '@/Components/BaseLevel.vue'; import BaseButtons from '@/Components/BaseButtons.vue'; import BaseButton from '@/Components/BaseButton.vue'; import UserAvatar from '@/Components/UserAvatar.vue'; // import Person from 'App/Models/Person'; import { Person } from '@/Stores/main'; import Draggable from 'vuedraggable'; +import FormControl from '@/Components/FormControl.vue'; const props = defineProps({ checkable: Boolean, @@ -21,6 +22,14 @@ const props = defineProps({ type: Array, default: () => [], }, + contributortypes: { + type: Object, + default: () => ({}), + }, + errors: { + type: Object, + default: () => ({}), + }, }); const styleService = StyleService(); @@ -120,11 +129,15 @@ const removeAuthor = (key) => { - + Sort Name Email + + Type + + @@ -136,7 +149,9 @@ const removeAuthor = (key) => {