fix: Update TablePersons components for improved event handling and layout consistency
Some checks failed
build.yaml / fix: Update TablePersons components for improved event handling and layout consistency (push) Failing after 0s

This commit is contained in:
Kaimbacher 2025-11-05 15:38:28 +01:00
commit 38c05f6714
4 changed files with 84 additions and 58 deletions

View file

@ -46,8 +46,8 @@ const dragEnabled = ref(props.canReorder);
// Name type options
const nameTypeOptions = {
'Personal': 'Personal',
'Organizational': 'Org'
Personal: 'Personal',
Organizational: 'Org',
};
// Computed properties
@ -111,9 +111,10 @@ const removeAuthor = (index: number) => {
const actualIndex = perPage.value * currentPage.value + index;
const person = items.value[actualIndex];
const displayName = person.name_type === 'Organizational'
? person.last_name || person.email
: `${person.first_name || ''} ${person.last_name || person.email}`.trim();
const displayName =
person.name_type === 'Organizational'
? person.last_name || person.email
: `${person.first_name || ''} ${person.last_name || person.email}`.trim();
if (confirm(`Are you sure you want to remove ${displayName}?`)) {
items.value.splice(actualIndex, 1);
@ -128,12 +129,12 @@ const removeAuthor = (index: number) => {
const updatePerson = (index: number, field: keyof Person, value: any) => {
const actualIndex = perPage.value * currentPage.value + index;
const person = items.value[actualIndex];
// Handle name_type change - clear first_name if switching to Organizational
if (field === 'name_type' && value === 'Organizational') {
person.first_name = '';
}
(person as any)[field] = value;
emit('person-updated', actualIndex, person);
};
@ -178,7 +179,10 @@ const perPageOptions = [
<template>
<div class="card">
<!-- Table Controls -->
<div v-if="hasMultiplePages" class="flex justify-between items-center px-4 py-2.5 border-b border-gray-200 dark:border-slate-700 bg-gray-50 dark:bg-slate-800/50">
<div
v-if="hasMultiplePages"
class="flex justify-between items-center px-4 py-2.5 border-b border-gray-200 dark:border-slate-700 bg-gray-50 dark:bg-slate-800/50"
>
<div class="flex items-center gap-2">
<span class="text-xs text-gray-600 dark:text-gray-400">
{{ currentPage * perPage + 1 }}-{{ Math.min((currentPage + 1) * perPage, items.length) }} of {{ items.length }}
@ -204,10 +208,18 @@ const perPageOptions = [
<th scope="col" class="text-left px-2 py-2 text-xs font-semibold text-gray-600 dark:text-gray-300 w-10">#</th>
<th class="text-left px-2 py-2 text-[10px] font-semibold text-gray-600 dark:text-gray-300 w-40">Type</th>
<th class="text-left px-2 py-2 text-xs font-semibold text-gray-600 dark:text-gray-300 min-w-[120px]">First Name</th>
<th class="text-left px-2 py-2 text-xs font-semibold text-gray-600 dark:text-gray-300 min-w-[160px]">Last Name / Org</th>
<th class="text-left px-2 py-2 text-xs font-semibold text-gray-600 dark:text-gray-300 min-w-[160px]">
Last Name / Org
</th>
<th class="text-left px-2 py-2 text-xs font-semibold text-gray-600 dark:text-gray-300 min-w-[140px]">ORCID</th>
<th class="text-left px-2 py-2 text-xs font-semibold text-gray-600 dark:text-gray-300 min-w-[160px]">Email</th>
<th v-if="showContributorTypes" scope="col" class="text-left px-2 py-2 text-xs font-semibold text-gray-600 dark:text-gray-300 w-32">Role</th>
<th
v-if="showContributorTypes"
scope="col"
class="text-left px-2 py-2 text-xs font-semibold text-gray-600 dark:text-gray-300 w-32"
>
Role
</th>
<th v-if="canDelete" class="w-16 px-2 py-2 text-xs font-semibold text-gray-600 dark:text-gray-300">Actions</th>
</tr>
</thead>
@ -223,7 +235,9 @@ const perPageOptions = [
handle=".drag-handle"
>
<template #item="{ index, element }">
<tr class="border-b border-gray-100 dark:border-slate-800 hover:bg-blue-50 dark:hover:bg-slate-800/70 transition-colors">
<tr
class="border-b border-gray-100 dark:border-slate-800 hover:bg-blue-50 dark:hover:bg-slate-800/70 transition-colors"
>
<td v-if="canReorder" class="px-2 py-2">
<div class="drag-handle cursor-move text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
<BaseIcon :path="mdiDragVariant" :size="18" />
@ -234,8 +248,8 @@ const perPageOptions = [
<!-- Name Type Selector -->
<td class="px-2 py-2">
<div class="flex items-center gap-1.5">
<BaseIcon
:path="element.name_type === 'Organizational' ? mdiDomain : mdiAccount"
<BaseIcon
:path="element.name_type === 'Organizational' ? mdiDomain : mdiAccount"
:size="16"
:class="element.name_type === 'Organizational' ? 'text-purple-500' : 'text-blue-500'"
:title="element.name_type"
@ -249,7 +263,10 @@ const perPageOptions = [
class="text-[8px] compact-select-mini flex-1"
/>
</div>
<div class="text-red-500 text-[8px] mt-0.5" v-if="errors && Array.isArray(errors[`${relation}.${index}.name_type`])">
<div
class="text-red-500 text-[8px] mt-0.5"
v-if="errors && Array.isArray(errors[`${relation}.${index}.name_type`])"
>
{{ errors[`${relation}.${index}.name_type`][0] }}
</div>
</td>
@ -266,7 +283,10 @@ const perPageOptions = [
class="text-xs compact-input"
/>
<span v-else class="text-gray-400 text-xs italic"></span>
<div class="text-red-500 text-xs mt-0.5" v-if="errors && Array.isArray(errors[`${relation}.${index}.first_name`])">
<div
class="text-red-500 text-xs mt-0.5"
v-if="errors && Array.isArray(errors[`${relation}.${index}.first_name`])"
>
{{ errors[`${relation}.${index}.first_name`][0] }}
</div>
</td>
@ -281,7 +301,10 @@ const perPageOptions = [
:placeholder="element.name_type === 'Organizational' ? 'Organization' : 'Last name'"
class="text-xs compact-input"
/>
<div class="text-red-500 text-xs mt-0.5" v-if="errors && Array.isArray(errors[`${relation}.${index}.last_name`])">
<div
class="text-red-500 text-xs mt-0.5"
v-if="errors && Array.isArray(errors[`${relation}.${index}.last_name`])"
>
{{ errors[`${relation}.${index}.last_name`][0] }}
</div>
</td>
@ -295,7 +318,10 @@ const perPageOptions = [
placeholder="0000-0000-0000-0000"
class="text-xs compact-input font-mono"
/>
<div class="text-red-500 text-xs mt-0.5" v-if="errors && Array.isArray(errors[`${relation}.${index}.identifier_orcid`])">
<div
class="text-red-500 text-xs mt-0.5"
v-if="errors && Array.isArray(errors[`${relation}.${index}.identifier_orcid`])"
>
{{ errors[`${relation}.${index}.identifier_orcid`][0] }}
</div>
</td>
@ -310,7 +336,10 @@ const perPageOptions = [
placeholder="email@example.com"
class="text-xs compact-input"
/>
<div class="text-red-500 text-xs mt-0.5" v-if="errors && Array.isArray(errors[`${relation}.${index}.email`])">
<div
class="text-red-500 text-xs mt-0.5"
v-if="errors && Array.isArray(errors[`${relation}.${index}.email`])"
>
{{ errors[`${relation}.${index}.email`][0] }}
</div>
</td>
@ -335,10 +364,10 @@ const perPageOptions = [
<!-- Actions -->
<td class="px-2 py-2 whitespace-nowrap">
<BaseButton
color="danger"
:icon="mdiTrashCan"
small
<BaseButton
color="danger"
:icon="mdiTrashCan"
small
@click.prevent="removeAuthor(index)"
class="compact-button"
/>
@ -354,29 +383,30 @@ const perPageOptions = [
:key="element.id || index"
class="border-b border-gray-100 dark:border-slate-800 hover:bg-blue-50 dark:hover:bg-slate-800/70 transition-colors"
>
<td v-if="canReorder" class="px-2 py-2 text-gray-400">
<BaseIcon :path="mdiDragVariant" :size="18" />
<td class="px-2 py-2 text-gray-400">
<BaseIcon v-if="canReorder && !hasMultiplePages" :path="mdiDragVariant" :size="18" />
</td>
<td class="px-2 py-2 text-xs text-gray-600 dark:text-gray-400">{{ currentPage * perPage + index + 1 }}</td>
<!-- Name Type Selector -->
<td class="px-2 py-2">
<BaseIcon
:path="element.name_type === 'Organizational' ? mdiDomain : mdiAccount"
:size="16"
:class="element.name_type === 'Organizational' ? 'text-purple-500' : 'text-blue-500'"
:title="element.name_type"
/>
<FormControl
required
:model-value="element.name_type"
@update:model-value="updatePerson(index, 'name_type', $event)"
type="select"
:options="nameTypeOptions"
:is-read-only="element.status || !canEdit"
class="text-xs compact-select"
:error="getFieldError(index, 'name_type')"
/>
<div class="flex items-center gap-1.5">
<BaseIcon
:path="element.name_type === 'Organizational' ? mdiDomain : mdiAccount"
:size="16"
:class="element.name_type === 'Organizational' ? 'text-purple-500' : 'text-blue-500'"
:title="element.name_type"
/>
<FormControl
required
v-model="element.name_type"
type="select"
:options="nameTypeOptions"
:is-read-only="element.status == true"
class="text-xs compact-select"
:error="getFieldError(index, 'name_type')"
/>
</div>
<div v-if="getFieldError(index, 'name_type')" class="text-red-500 text-xs mt-0.5">
{{ getFieldError(index, 'name_type') }}
</div>
@ -459,7 +489,7 @@ const perPageOptions = [
@update:model-value="updatePerson(index, 'pivot_contributor_type', $event)"
type="select"
:options="contributortypes"
:is-read-only="element.status || !canEdit"
:is-read-only="!canEdit"
placeholder="Role"
class="text-xs compact-select"
:error="getFieldError(index, 'pivot_contributor_type')"
@ -475,8 +505,7 @@ const perPageOptions = [
color="danger"
:icon="mdiTrashCan"
small
@click="removeAuthor(index)"
:disabled="element.status || !canEdit"
@click.prevent="removeAuthor(index)"
title="Remove person"
class="compact-button"
/>
@ -542,9 +571,7 @@ const perPageOptions = [
/>
</div>
<span class="text-sm text-gray-600 dark:text-gray-400">
Page {{ currentPageHuman }} of {{ numPages }}
</span>
<span class="text-sm text-gray-600 dark:text-gray-400"> Page {{ currentPageHuman }} of {{ numPages }} </span>
</div>
</div>
</template>
@ -568,4 +595,4 @@ const perPageOptions = [
padding: 0.5rem !important;
}
}
</style>
</style>