From 93905c83a2b114659c4521cfff01db518058353c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Rosenstr=C3=B6m?= Date: Thu, 31 Oct 2024 13:36:59 +0100 Subject: [PATCH 1/2] Add functionality for deleting and creating records in bulk --- .../components/care/bulk-changes-header.vue | 32 ++- .../src/components/care/bulk-changes.vue | 115 +++++---- cataloging/src/components/care/preview.vue | 29 ++- .../src/components/shared/type-icon.vue | 6 +- .../src/resources/json/combinedTemplates.json | 223 +++++++++++++++++- cataloging/src/resources/json/i18n.json | 4 +- cataloging/src/utils/bulk.js | 6 + 7 files changed, 347 insertions(+), 68 deletions(-) diff --git a/cataloging/src/components/care/bulk-changes-header.vue b/cataloging/src/components/care/bulk-changes-header.vue index 856d71eb8..458ee5114 100644 --- a/cataloging/src/components/care/bulk-changes-header.vue +++ b/cataloging/src/components/care/bulk-changes-header.vue @@ -7,10 +7,11 @@ import {mapGetters} from "vuex"; import { STATUS_KEY, } from "@/utils/bulk.js"; +import TypeIcon from "../shared/type-icon.vue"; export default { name: 'bulk-changes-header.vue', - components: {IdPill, FormBuilder}, + components: {TypeIcon, IdPill, FormBuilder}, data() { return { editing: false, @@ -21,6 +22,7 @@ export default { documentId: '', isNew: false, isDraft: false, + specType: '' }, computed: { ...mapGetters([ @@ -36,6 +38,9 @@ export default { status() { return StringUtil.getLabelByLang(this.currentBulkChange[STATUS_KEY], this.user.settings.language, this.resources); }, + typeLabel() { + return StringUtil.getLabelByLang(this.specType, this.user.settings.language, this.resources); + }, }, methods: { translatePhrase, @@ -58,7 +63,6 @@ export default { @@ -101,6 +101,7 @@ export default { font-size: 3rem; padding-bottom: 10px; padding-right: 1rem; + font-weight: 600; &.cursor-pointer { cursor: pointer; } @@ -115,8 +116,15 @@ export default { margin-left: auto; text-align:right; } - &-noItems { - margin-left: 5px; + &-typeHeader { + display: flex; + width: 100%; + flex-wrap: wrap; + } + &-type{ + margin-left: 3px; + display: flex; + font-size: 12px; } } diff --git a/cataloging/src/components/care/bulk-changes.vue b/cataloging/src/components/care/bulk-changes.vue index 467eff553..f2b590a69 100644 --- a/cataloging/src/components/care/bulk-changes.vue +++ b/cataloging/src/components/care/bulk-changes.vue @@ -27,7 +27,9 @@ import { SHOULD_UPDATE_TIMESTAMP_KEY, STATUS_KEY, Status, - TARGET_FORM_KEY, VALUE_FROM_KEY, + TARGET_FORM_KEY, + VALUE_FROM_KEY, + Type } from "@/utils/bulk.js"; export default { @@ -50,7 +52,7 @@ export default { showOverview: true, inlinedIds: [], activeStep: '', - steps: [ + allSteps: [ 'form', 'targetForm', 'preview', @@ -105,9 +107,15 @@ export default { return this.isActive('targetForm') ? this.inspector.data.mainEntity : this.currentSpec[TARGET_FORM_KEY]; }, formTitle() { + if (this.specType === Type.Delete) { + return `${this.steps.indexOf('form') + 1}. ${translatePhrase('Remove records')}` + } return `${this.steps.indexOf('form') + 1}. ${translatePhrase('Selection')}` }, changesTitle() { + if (this.specType === Type.Create) { + return `${this.steps.indexOf('targetForm') + 1}. ${translatePhrase('Create records')}` + } return `${this.steps.indexOf('targetForm') + 1}. ${translatePhrase('Changes')}` }, previewTitle() { @@ -151,6 +159,15 @@ export default { shouldExportAffected() { return this.isLoud; }, + steps() { + if (!this.hasTargetForm) { + return this.allSteps.filter(step => step !== 'targetForm'); + } else if(!this.hasMatchForm) { + return this.allSteps.filter(step => step !== 'form') + } else { + return this.allSteps; + } + }, hasUnsavedChanges() { if (this.lastFetchedSpec && this.isDraft) { const matchFormEqual = isEqual(this.formObj, this.lastFetchedSpec[MATCH_FORM_KEY]); @@ -159,6 +176,15 @@ export default { } return false; }, + hasTargetForm() { + return this.specType !== Type.Delete; + }, + hasMatchForm() { + return this.specType !== Type.Create; + }, + specType() { + return this.currentSpec['@type']; + } }, methods: { translatePhrase, @@ -171,7 +197,6 @@ export default { const record = initData['@graph'][0]; const mainEntity = initData['@graph'][1]; - this.currentBulkChange = mainEntity; this.currentBulkChange.label = '-' + this.getDateString(); this.currentSpec = this.currentBulkChange[CHANGE_SPEC_KEY]; @@ -196,8 +221,7 @@ export default { // FIXME: remove emptyTemplate const initial = emptyTemplate.mainEntity[CHANGE_SPEC_KEY][MATCH_FORM_KEY]; this.setInspectorData(initial); - this.currentSpec[MATCH_FORM_KEY] = initial; - this.currentSpec[TARGET_FORM_KEY] = initial; //FIXME: to avoid undefined on init + this.currentSpec = emptyTemplate.mainEntity[CHANGE_SPEC_KEY]; //FIXME: to avoid undefined on init this.fetchRecord(this.documentId); }, fetchRecord(fnurgel) { @@ -365,27 +389,25 @@ export default { // const agents = (this.changeSets || []).map((c) => c.agent).filter((a) => a); // DataUtil.fetchMissingLinkedToQuoted(agents, this.$store); - if (typeof result.changeSets === 'undefined') { - this.resetPreviewData(); - return; - } // Form preview - const formChangeset = result.changeSets[1]; + if (typeof result.changeSets !== 'undefined') { + const formChangeset = result.changeSets[1]; - const [formDisplayData, formDisplayPaths] = HistoryUtil.buildDisplayData( - this.currentSpec[MATCH_FORM_KEY], - this.currentSpec[TARGET_FORM_KEY], - formChangeset.addedPaths, - formChangeset.removedPaths, - (s) => StringUtil.getLabelByLang(s, this.user.settings.language, this.resources), - ); - this.formPreviewData= formDisplayData; - this.formPreviewDiff.removed = formDisplayPaths.removed.map(path => `mainEntity.${path}`); - this.formPreviewDiff.added = formDisplayPaths.added.map(path => `mainEntity.${path}`); - this.formPreviewDiff.modified = formDisplayPaths.modified.map(path => `mainEntity.${path}`); + const [formDisplayData, formDisplayPaths] = HistoryUtil.buildDisplayData( + this.currentSpec[MATCH_FORM_KEY], + this.currentSpec[TARGET_FORM_KEY], + formChangeset.addedPaths, + formChangeset.removedPaths, + (s) => StringUtil.getLabelByLang(s, this.user.settings.language, this.resources), + ); + this.formPreviewData = formDisplayData; + this.formPreviewDiff.removed = formDisplayPaths.removed.map(path => `mainEntity.${path}`); + this.formPreviewDiff.added = formDisplayPaths.added.map(path => `mainEntity.${path}`); + this.formPreviewDiff.modified = formDisplayPaths.modified.map(path => `mainEntity.${path}`); + } this.totalItems = result.totalItems; - if (this.totalItems === 0 || typeof result.changeSets === 'undefined') { + if (this.totalItems === 0) { this.resetPreviewData(); return; } else { @@ -396,22 +418,29 @@ export default { this.previousPreviewLink = result.prev; this.itemOffset = result.itemOffset; - let before = result.items[0].changeSets[0].version; - let after = result.items[0].changeSets[1].version; - const changeset = result.items[0].changeSets[1]; + if (this.specType === Type.Update) { + let before = result.items[0].changeSets[0].version; + let after = result.items[0].changeSets[1].version; + const changeset = result.items[0].changeSets[1]; - const [displayData, displayPaths] = HistoryUtil.buildDisplayData( - before, - after, - changeset.addedPaths.map(el => el.slice(2)), //temporary hack to remove [@graph, 1, ... - changeset.removedPaths.map(el => el.slice(2)), - (s) => StringUtil.getLabelByLang(s, this.user.settings.language, this.resources), - ); + const [displayData, displayPaths] = HistoryUtil.buildDisplayData( + before, + after, + changeset.addedPaths.map(el => el.slice(2)), //temporary hack to remove [@graph, 1, ... + changeset.removedPaths.map(el => el.slice(2)), + (s) => StringUtil.getLabelByLang(s, this.user.settings.language, this.resources), + ); - this.fullPreviewData= displayData; - this.fullPreviewDiff.removed = displayPaths.removed.map(path => `mainEntity.${path}`); - this.fullPreviewDiff.added = displayPaths.added.map(path => `mainEntity.${path}`); - this.fullPreviewDiff.modified = displayPaths.modified.map(path => `mainEntity.${path}`); + this.fullPreviewData = displayData; + this.fullPreviewDiff.removed = displayPaths.removed.map(path => `mainEntity.${path}`); + this.fullPreviewDiff.added = displayPaths.added.map(path => `mainEntity.${path}`); + this.fullPreviewDiff.modified = displayPaths.modified.map(path => `mainEntity.${path}`); + } else if (this.specType === Type.Delete) { + this.fullPreviewDiff.removed = []; + this.fullPreviewDiff.added = []; + this.fullPreviewDiff.modifed = []; + this.fullPreviewData = result.items[0].changeSets[0].version; + } DataUtil.fetchMissingLinkedToQuoted(this.fullPreviewData, this.$store); this.loadingPreview.next = false; this.loadingPreview.previous = false; @@ -671,8 +700,9 @@ export default { :documentId="documentId" :is-new="isNew" :is-draft="isDraft" + :spec-type="specType" /> -
+
-
+
@@ -740,10 +771,10 @@ export default {
- - - - + SPECIFICATION +
{{ this.currentBulkChange }}
+ ENTITY FORM +
{{ this.dataObj }}
diff --git a/cataloging/src/components/care/preview.vue b/cataloging/src/components/care/preview.vue index b35636049..004b723eb 100644 --- a/cataloging/src/components/care/preview.vue +++ b/cataloging/src/components/care/preview.vue @@ -4,10 +4,9 @@ import { mapGetters } from 'vuex'; import {isEmpty} from 'lodash-es'; import ItemEntity from "@/components/inspector/item-entity.vue"; import EntitySummary from "@/components/shared/entity-summary.vue"; -import {asFnurgelLink, translatePhrase} from "@/utils/filters.js"; -import {offset} from "@floating-ui/dom"; +import {translatePhrase} from "@/utils/filters.js"; import * as StringUtil from "../../../../lxljs/string.js"; -import { Status } from "@/utils/bulk.js"; +import { Status, Type } from "@/utils/bulk.js"; export default { name: 'preview', @@ -51,6 +50,10 @@ export default { type: Boolean, default: false, }, + specType: { + type: String, + default: '', + } }, computed: { ...mapGetters([ @@ -68,7 +71,7 @@ export default { return !isEmpty(this.previewData) && !isEmpty(this.previewDiff); }, showPreview() { - return this.hasPreviewData && !this.hasUnsaved; + return this.hasPreviewData; }, noHitsLabel() { if (this.hasUnsaved) { @@ -79,8 +82,17 @@ export default { return translatePhrase('No matching records'); } }, + deleteSpecLabel() { + return translatePhrase('Delete record'); + }, completedLabel() { return StringUtil.getLabelByLang(Status.Completed, this.user.settings.language, this.resources) + }, + isDeleteSpec() { + return this.specType === Type.Delete; + }, + isUpdateSpec() { + return this.specType === Type.Update; } }, emits: ['onInactive', 'onActive'], @@ -126,7 +138,7 @@ export default { :should-link="false" :exclude-components="['details']"/>
- + diff --git a/cataloging/src/components/shared/type-icon.vue b/cataloging/src/components/shared/type-icon.vue index ceed56c34..7183a5ee7 100644 --- a/cataloging/src/components/shared/type-icon.vue +++ b/cataloging/src/components/shared/type-icon.vue @@ -1,6 +1,6 @@