hotfix (dataset): enhance dataset editing and validation

- Modified the TableKeywords component to remove the external_key reset when the type is updated, only resetting the value.
- Updated the DatasetController to pass authorization checks (`can.edit`, `can.delete`) to the edit view.
- Updated the arrayContainsTypes validation rule to improve the error messages for titles and descriptions, clarifying the requirements for main and translated entries.
- Updated the Dataset Edit view to:
  - Remove unused code and comments.
  - Add authorization checks to the save button.
  - Add a release button.
  - Add icons to the save and release buttons.
  - Add a computed property `hasUnsavedChanges` to determine if there are unsaved changes in the form.
This commit is contained in:
Kaimbacher 2025-04-18 11:39:19 +02:00
parent 2cb33a779c
commit c3ae4327b7
4 changed files with 83 additions and 55 deletions

View file

@ -468,15 +468,6 @@
</div>
<!-- <div class="mb-4">
<label for="description" class="block text-gray-700 font-bold mb-2">Description:</label>
<textarea id="description"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
v-model="form.type"></textarea>
</div> -->
<div class="mb-4">
<!-- <label for="project" class="block text-gray-700 font-bold mb-2">Project:</label>
<select
@ -498,25 +489,15 @@
{{ form.errors['files'].join(', ') }}
</div>
<!-- Add more input fields for the other properties of the dataset -->
<!-- <button
type="submit"
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
>
Save
</button> -->
<template #footer>
<BaseButtons>
<BaseButton @click.stop="submit" :disabled="form.processing" label="Save" color="info"
:class="{ 'opacity-25': form.processing }" small>
<BaseButton v-if="can.edit" @click.stop="submit" :disabled="form.processing" label="Save"
color="info" :icon="mdiDisc" :class="{ 'opacity-25': form.processing }" small>
</BaseButton>
<!-- <button :disabled="form.processing" :class="{ 'opacity-25': form.processing }"
class="text-base hover:scale-110 focus:outline-none flex justify-center px-4 py-2 rounded font-bold cursor-pointer hover:bg-teal-200 bg-teal-100 text-teal-700 border duration-200 ease-in-out border-teal-600 transition"
@click.stop="submit">
Save
</button> -->
<BaseButton v-if="can.edit" :route-name="stardust.route('dataset.release', [dataset.id])"
color="info" :icon="mdiLockOpen" :label="'Release'" small
:disabled="form.processing"
:class="{ 'opacity-25': form.processing }" />
</BaseButtons>
</template>
</CardBox>
@ -570,7 +551,9 @@ import {
mdiBookOpenPageVariant,
mdiEarthPlus,
mdiAlertBoxOutline,
mdiRestore
mdiRestore,
mdiLockOpen,
mdiDisc
} from '@mdi/js';
import { notify } from '@/notiwind';
import NotificationBar from '@/Components/NotificationBar.vue';
@ -624,8 +607,10 @@ const props = defineProps({
type: Object,
default: () => ({}),
},
can: {
type: Object,
default: () => ({}),
},
});
const flash: ComputedRef<any> = computed(() => {
@ -650,31 +635,70 @@ const fitBounds: LatLngBoundsExpression = [
];
const mapId = 'test';
// const downloadFile = async (id: string): Promise<string> => {
// const response = await axios.get<Blob>(`/api/download/${id}`, {
// responseType: 'blob',
// });
// const url = URL.createObjectURL(response.data);
// setTimeout(() => {
// URL.revokeObjectURL(url);
// }, 1000);
// return url;
// };
// for (const file of props.dataset.files) {
// // console.log(`${file.name} path is ${file.filePath} here.`);
// file.fileSrc = ref("");
// // downloadFile(file.id).then((value: string) => {
// // file.fileSrc = ref(value);
// // form = useForm<Dataset>(props.dataset as Dataset);
// // });
// }
props.dataset.filesToDelete = [];
props.dataset.subjectsToDelete = [];
props.dataset.referencesToDelete = [];
let form = useForm<Dataset>(props.dataset as Dataset);
// Add this computed property to the script section
const hasUnsavedChanges = computed(() => {
// Check if form is processing
if (form.processing) return true;
// Compare current form state with original dataset
// Check basic properties
if (form.language !== props.dataset.language) return true;
if (form.type !== props.dataset.type) return true;
if (form.project_id !== props.dataset.project_id) return true;
if (form.embargo_date !== props.dataset.embargo_date) return true;
// Check if licenses have changed
const originalLicenses = Array.isArray(props.dataset.licenses)
? props.dataset.licenses.map(l => typeof l === 'object' ? l.id.toString() : l)
: [];
const currentLicenses = Array.isArray(form.licenses)
? form.licenses.map(l => typeof l === 'object' ? l.id.toString() : l)
: [];
if (JSON.stringify(currentLicenses) !== JSON.stringify(originalLicenses)) return true;
// Check if titles have changed
if (JSON.stringify(form.titles) !== JSON.stringify(props.dataset.titles)) return true;
// Check if descriptions have changed
if (JSON.stringify(form.descriptions) !== JSON.stringify(props.dataset.descriptions)) return true;
// Check if authors have changed
if (JSON.stringify(form.authors) !== JSON.stringify(props.dataset.authors)) return true;
// Check if contributors have changed
if (JSON.stringify(form.contributors) !== JSON.stringify(props.dataset.contributors)) return true;
// Check if subjects have changed
// if (JSON.stringify(form.subjects) !== JSON.stringify(props.dataset.subjects)) return true;
let test = JSON.stringify(form.subjects);
let test2 = JSON.stringify(props.dataset.subjects);
if (test !== test2) {
return true;
}
// Check if references have changed
if (JSON.stringify(form.references) !== JSON.stringify(props.dataset.references)) return true;
// Check if coverage has changed
if (JSON.stringify(form.coverage) !== JSON.stringify(props.dataset.coverage)) return true;
// Check if files have changed
if (form.files?.length !== props.dataset.files?.length) return true;
if (form.filesToDelete?.length > 0) return true;
// Check if there are new files to upload
if (form.files?.some(file => !file.id)) return true;
// No changes detected
return false;
});
const submit = async (): Promise<void> => {
let route = stardust.route('dataset.update', [props.dataset.id]);