From 3d8f2354cb2c41e58ddae71570556073d3e21ade Mon Sep 17 00:00:00 2001 From: Arno Kaimbacher Date: Wed, 29 Oct 2025 11:20:27 +0100 Subject: [PATCH] feat: Enhance Dataset Edit Page with Unsaved Changes Indicator and Improved Structure - Added a progress indicator for unsaved changes at the top of the dataset edit page. - Enhanced the title section with a dataset status badge and improved layout. - Introduced collapsible sections for better organization of form fields. - Improved notifications for success/error messages. - Refactored form fields into distinct sections: Basic Information, Licenses, Titles, Descriptions, Creators & Contributors, Additional Metadata, Geographic Coverage, and Files. - Enhanced loading spinner with a more visually appealing overlay. - Added new project validation logic in the backend with create and update validators. --- app/controllers/projects_controller.ts | 8 +- app/validators/project.ts | 28 + resources/js/Layouts/LayoutAuthenticated.vue | 23 +- resources/js/Pages/Admin/License/Index.vue | 159 +-- resources/js/Pages/Admin/Project/Create.vue | 55 +- resources/js/Pages/Admin/Project/Index.vue | 4 +- resources/js/Pages/Admin/Role/Index.vue | 164 ++-- resources/js/Pages/Dashboard.vue | 138 +-- resources/js/Pages/Submitter/Dataset/Edit.vue | 909 ++++++++++-------- 9 files changed, 863 insertions(+), 625 deletions(-) create mode 100644 app/validators/project.ts diff --git a/app/controllers/projects_controller.ts b/app/controllers/projects_controller.ts index 7b4d43e..21e20df 100644 --- a/app/controllers/projects_controller.ts +++ b/app/controllers/projects_controller.ts @@ -1,6 +1,7 @@ // app/controllers/projects_controller.ts import Project from '#models/project'; import type { HttpContext } from '@adonisjs/core/http'; +import { createProjectValidator, updateProjectValidator } from '#validators/project'; export default class ProjectsController { // GET /settings/projects @@ -23,7 +24,8 @@ export default class ProjectsController { // POST /settings/projects public async store({ request, response, session }: HttpContext) { - const data = request.only(['label', 'name', 'description']); + // Validate the request data + const data = await request.validateUsing(createProjectValidator); await Project.create(data); @@ -40,7 +42,9 @@ export default class ProjectsController { // PUT /settings/projects/:id public async update({ params, request, response, session }: HttpContext) { const project = await Project.findOrFail(params.id); - const data = request.only(['label', 'name', 'description']); + + // Validate the request data + const data = await request.validateUsing(updateProjectValidator); await project.merge(data).save(); diff --git a/app/validators/project.ts b/app/validators/project.ts new file mode 100644 index 0000000..bad6c7c --- /dev/null +++ b/app/validators/project.ts @@ -0,0 +1,28 @@ +// app/validators/project.ts +import vine from '@vinejs/vine'; + +export const createProjectValidator = vine.compile( + vine.object({ + label: vine.string().trim().minLength(1).maxLength(50), + name: vine + .string() + .trim() + .minLength(3) + .maxLength(255) + .regex(/^[a-z0-9-]+$/), + description: vine.string().trim().maxLength(255).minLength(5).optional(), + }), +); + +export const updateProjectValidator = vine.compile( + vine.object({ + // label is NOT included since it's readonly + name: vine + .string() + .trim() + .minLength(3) + .maxLength(255) + .regex(/^[a-z0-9-]+$/), + description: vine.string().trim().maxLength(255).minLength(5).optional(), + }), +); diff --git a/resources/js/Layouts/LayoutAuthenticated.vue b/resources/js/Layouts/LayoutAuthenticated.vue index 15a117c..c077c7b 100644 --- a/resources/js/Layouts/LayoutAuthenticated.vue +++ b/resources/js/Layouts/LayoutAuthenticated.vue @@ -14,11 +14,11 @@ const props = defineProps({ showAsideMenu: { type: Boolean, default: true // Set default value to true + }, + hasProgressBar: { + type: Boolean, + default: false // New prop to indicate if progress bar is shown } - // user: { - // type: Object, - // default: () => ({}), - // } }); @@ -29,9 +29,18 @@ const props = defineProps({ }">
- + 'xl:pl-60': props.showAsideMenu==true, + 'pt-14': !props.hasProgressBar, + 'pt-24': props.hasProgressBar // Increased padding when progress bar is present (pt-14 + height of progress bar) + }" + class="min-h-screen w-screen transition-position lg:w-auto bg-gray-50 dark:bg-slate-800 dark:text-slate-100"> +