feat: update API controllers, validations, and Vue components
All checks were successful
CI / container-job (push) Successful in 49s
All checks were successful
CI / container-job (push) Successful in 49s
- Modified Api/Authors.Controller.ts to use only personal types and sort by dataset_count. - Completely rewritten AvatarController.ts. - Added new Api/CollectionsController.ts for querying collections and collection_roles. - Modified Api/DatasetController.ts to preload titles, identifier and order by server_date_published. - Modified FileController.ts to serve files from /storage/app/data/ instead of /storage/app/public. - Added new Api/UserController for requesting submitters (getSubmitters). - Improved OaiController.ts with performant DB queries for better ResumptionToken handling. - Modified Submitter/DatasetController.ts by adding a categorize method for library classification. - Rewritten ResumptionToken.ts. - Improved TokenWorkerService.ts to utilize browser fingerprint. - Edited dataset.ts by adding the doiIdentifier property. - Enhanced person.ts to improve the fullName property. - Completely rewritten AsideMenuItem.vue component. - Updated CarBoxClient.vue to use TypeScript. - Added new CardBoxDataset.vue for displaying recent datasets on the dashboard. - Completely rewritten TableSampleClients.vue for the dashboard. - Completely rewritten UserAvatar.vue. - Made small layout changes in Dashboard.vue. - Added new Category.vue for browsing scientific collections. - Adapted the pinia store in main.ts. - Added additional routes in start/routes.ts and start/api/routes.ts. - Improved referenceValidation.ts for better ISBN existence checking. - NPM dependency updates.
This commit is contained in:
parent
36cd7a757b
commit
b540547e4c
34 changed files with 1757 additions and 1018 deletions
|
@ -1,162 +1,143 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed, ComputedRef } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import { Link, usePage } from '@inertiajs/vue3';
|
||||
// import { Link } from '@inertiajs/inertia-vue3';
|
||||
|
||||
import { StyleService } from '@/Stores/style.service';
|
||||
import { mdiMinus, mdiPlus } from '@mdi/js';
|
||||
import { getButtonColor } from '@/colors';
|
||||
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||
// import AsideMenuList from '@/Components/AsideMenuList.vue';
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
import type { User } from '@/Dataset';
|
||||
import { MenuItem } from '@headlessui/vue';
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
parentItem: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
// isDropdownList: Boolean,
|
||||
});
|
||||
interface MenuItem {
|
||||
href?: string;
|
||||
route?: string;
|
||||
icon?: string;
|
||||
label: string;
|
||||
target?: string;
|
||||
color?: string;
|
||||
children?: MenuItem[];
|
||||
isOpen?: boolean;
|
||||
roles?: string[];
|
||||
}
|
||||
|
||||
const user: ComputedRef<User> = computed(() => {
|
||||
return usePage().props.authUser as User;
|
||||
const props = defineProps<{
|
||||
item: MenuItem;
|
||||
parentItem?: MenuItem;
|
||||
// isDropdownList?: boolean;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'menu-click', event: Event, item: MenuItem): void;
|
||||
}>();
|
||||
|
||||
// Retrieve authenticated user from page props
|
||||
const user = computed<User>(() => usePage().props.authUser as User);
|
||||
|
||||
// Check if the menu item has children
|
||||
const hasChildren = computed(() => {
|
||||
return Array.isArray(props.item?.children) && props.item.children.length > 0;
|
||||
});
|
||||
|
||||
const itemRoute = computed(() => (props.item && props.item.route ? stardust.route(props.item.route) : ''));
|
||||
// const isCurrentRoute = computed(() => (props.item && props.item.route ? stardust.isCurrent(props.item.route): false));
|
||||
// const itemHref = computed(() => (props.item && props.item.href ? props.item.href : ''));
|
||||
|
||||
const emit = defineEmits(['menu-click']);
|
||||
// Determine which element to render based on 'href' or 'route'
|
||||
const isComponent = computed(() => {
|
||||
if (props.item.href) {
|
||||
return 'a';
|
||||
}
|
||||
if (props.item.route) {
|
||||
return Link;
|
||||
}
|
||||
return 'div';
|
||||
});
|
||||
|
||||
// Check if any child route is active
|
||||
const isChildActive = computed(() => {
|
||||
if (props.item.children && props.item.children.length > 0) {
|
||||
return props.item.children.some(child => child.route && stardust.isCurrent(child.route));
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Automatically use prop item.isOpen if set from the parent,
|
||||
// or if one of its children is active then force open state.
|
||||
const isOpen = computed(() => {
|
||||
return props.item.isOpen || isChildActive.value;
|
||||
});
|
||||
|
||||
|
||||
const styleService = StyleService();
|
||||
|
||||
const hasColor = computed(() => props.item && props.item.color);
|
||||
|
||||
// const isDropdownOpen = ref(false);
|
||||
|
||||
// const isChildSelected = computed(() => {
|
||||
// if (props.item.children && props.item.children.length > 0) {
|
||||
// return children.value.some(childItem => stardust.isCurrent(childItem.route));
|
||||
// }
|
||||
// return false;
|
||||
|
||||
// const children = computed(() => {
|
||||
// return props.item.children || [];
|
||||
// });
|
||||
|
||||
|
||||
const hasChildren = computed(() => {
|
||||
// props.item.children?.length > 0
|
||||
if (props.item.children && props.item.children.length > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
const children = computed(() => {
|
||||
return props.item.children || [];
|
||||
});
|
||||
|
||||
const componentClass = computed(() => [
|
||||
hasChildren ? 'py-3 px-6 text-sm font-semibold' : 'py-3 px-6',
|
||||
hasColor.value ? getButtonColor(props.item.color, false, true) : styleService.asideMenuItemStyle,
|
||||
]);
|
||||
|
||||
|
||||
|
||||
// const toggleDropdown = () => {
|
||||
// // emit('menu-click', event, props.item);
|
||||
// // console.log(props.item);
|
||||
// if (hasChildren.value) {
|
||||
// isDropdownOpen.value = !isDropdownOpen.value;
|
||||
// }
|
||||
// // if (props.parentItem?.hasDropdown.value) {
|
||||
// // props.parentItem.isDropdownActive.value = true;
|
||||
// // }
|
||||
// };
|
||||
|
||||
const menuClick = (event) => {
|
||||
const menuClick = (event: Event) => {
|
||||
emit('menu-click', event, props.item);
|
||||
|
||||
if (hasChildren.value) {
|
||||
// if (isChildSelected.value == false) {
|
||||
// isDropdownOpen.value = !isDropdownOpen.value;
|
||||
props.item.isOpen = !props.item.isOpen;
|
||||
// }
|
||||
// Toggle open state if the menu has children
|
||||
props.item.isOpen = !props.item.isOpen;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// const handleChildSelected = () => {
|
||||
// isChildSelected.value = true;
|
||||
// };
|
||||
|
||||
|
||||
const activeInactiveStyle = computed(() => {
|
||||
const activeStyle = computed(() => {
|
||||
if (props.item.route && stardust.isCurrent(props.item.route)) {
|
||||
// console.log(props.item.route);
|
||||
return styleService.asideMenuItemActiveStyle;
|
||||
return 'text-sky-600 font-bold';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
const is = computed(() => {
|
||||
if (props.item.href) {
|
||||
return 'a';
|
||||
}
|
||||
if (props.item.route) {
|
||||
return Link;
|
||||
}
|
||||
|
||||
return 'div';
|
||||
});
|
||||
|
||||
const hasRoles = computed(() => {
|
||||
if (props.item.roles) {
|
||||
return user.value.roles.some(role => props.item.roles.includes(role.name));
|
||||
return user.value.roles.some(role => props.item.roles?.includes(role.name));
|
||||
// return test;
|
||||
}
|
||||
return true
|
||||
});
|
||||
|
||||
// props.routeName && stardust.isCurrent(props.routeName) ? props.activeColor : null
|
||||
</script>
|
||||
|
||||
<!-- :target="props.item.target ?? null" -->
|
||||
<template>
|
||||
<li v-if="hasRoles">
|
||||
<!-- <component :is="itemHref ? 'div' : Link" :href="itemHref ? itemHref : itemRoute" -->
|
||||
<component :is="is" :href="itemRoute ? stardust.route(props.item.route) : props.item.href"
|
||||
class="flex cursor-pointer dark:text-slate-300 dark:hover:text-white menu-item-wrapper" :class="componentClass"
|
||||
@click="menuClick" v-bind:target="props.item.target ?? null">
|
||||
<BaseIcon v-if="item.icon" :path="item.icon" class="flex-none menu-item-icon" :class="activeInactiveStyle"
|
||||
w="w-16" :size="18" />
|
||||
<component :is="isComponent" :href="props.item.href ? props.item.href : itemRoute"
|
||||
class="flex cursor-pointer dark:text-slate-300 dark:hover:text-white menu-item-wrapper"
|
||||
:class="componentClass" @click="menuClick" :target="props.item.target || null">
|
||||
<BaseIcon v-if="props.item.icon" :path="props.item.icon" class="flex-none menu-item-icon"
|
||||
:class="activeStyle" w="w-16" :size="18" />
|
||||
<div class="menu-item-label">
|
||||
<span class="grow text-ellipsis line-clamp-1" :class="activeInactiveStyle">
|
||||
{{ item.label }}
|
||||
<span class="grow text-ellipsis line-clamp-1" :class="[activeStyle]">
|
||||
{{ props.item.label }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- plus icon for expanding sub menu -->
|
||||
<BaseIcon v-if="hasChildren" :path="props.item.isOpen ? mdiMinus : mdiPlus" class="flex-none"
|
||||
:class="[activeInactiveStyle]" w="w-12" />
|
||||
<!-- Display plus or minus icon if there are child items -->
|
||||
<BaseIcon v-if="hasChildren" :path="isOpen ? mdiMinus : mdiPlus" class="flex-none"
|
||||
:class="[activeStyle]" w="w-12" />
|
||||
</component>
|
||||
<!-- Render dropdown -->
|
||||
<div class="menu-item-dropdown"
|
||||
:class="[styleService.asideMenuDropdownStyle, props.item.isOpen ? 'block dark:bg-slate-800/50' : 'hidden']"
|
||||
v-if="hasChildren">
|
||||
:class="[styleService.asideMenuDropdownStyle, isOpen ? 'block dark:bg-slate-800/50' : 'hidden']"
|
||||
v-if="props.item.children && props.item.children.length > 0">
|
||||
<ul>
|
||||
<!-- <li v-for="( child, index ) in children " :key="index">
|
||||
<AsideMenuItem :item="child" :key="index"> </AsideMenuItem>
|
||||
</li> -->
|
||||
<AsideMenuItem v-for="(childItem, index) in children" :key="index" :item="childItem" />
|
||||
|
||||
<AsideMenuItem v-for="(childItem, index) in (props.item.children as any[])" :key="index" :item="childItem"
|
||||
@menu-click="$emit('menu-click', $event, childItem)" />
|
||||
</ul>
|
||||
</div>
|
||||
<!-- <AsideMenuList v-if="hasChildren" :items="item.children"
|
||||
:class="[styleService.asideMenuDropdownStyle, isDropdownOpen ? 'block dark:bg-slate-800/50' : 'hidden']" /> -->
|
||||
|
||||
|
||||
</li>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
|
@ -167,17 +148,12 @@ const hasRoles = computed(() => {
|
|||
}
|
||||
|
||||
.menu-item-icon {
|
||||
font-size: 2.5rem;
|
||||
/* margin-right: 10px; */
|
||||
font-size: 2.5rem;
|
||||
/* margin-right: 10px; */
|
||||
}
|
||||
|
||||
/* .menu-item-label {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
} */
|
||||
|
||||
.menu-item-dropdown {
|
||||
/* margin-left: 10px; */
|
||||
padding-left: 0.75rem;
|
||||
/* margin-left: 10px; */
|
||||
padding-left: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue