diff --git a/src/components/Feature/Edit/FeatureExtraForm.vue b/src/components/Feature/Edit/FeatureExtraForm.vue index b95c77128f464cfa6af24943347fcdc8cd994931..e6ce1e41ac2de211ff9c6e4153f9ae4f2c2fda6c 100644 --- a/src/components/Feature/Edit/FeatureExtraForm.vue +++ b/src/components/Feature/Edit/FeatureExtraForm.vue @@ -9,10 +9,11 @@ v-if="field && field.field_type === 'boolean'" :class="['ui checkbox', { 'disabled': field.disabled }]" > + <!-- JSON.parse is used in case of receiving a string 'true' or 'false'--> <input :id="field.name" type="checkbox" - :checked="field.value" + :checked="JSON.parse(field.value)" :name="field.name" @change="updateStore_extra_form" > @@ -175,7 +176,7 @@ export default { type: Object, default: null, }, - isConditionalField: { + useValueOnly: { type: Boolean, default: false, } @@ -205,8 +206,8 @@ export default { }, set(newValue) { //* set the value selected in the dropdown - if (this.isConditionalField) { - this.$emit('update:condition-value', newValue); + if (this.useValueOnly) { + this.$emit('update:value', newValue); } else { const newExtraForm = this.field; newExtraForm['value'] = newValue; @@ -292,7 +293,7 @@ export default { ]), initMultipleCheckboxXform() { - this.selectedMultipleCheckbox = this.field.value || []; + this.selectedMultipleCheckbox = typeof this.field.value === 'string' ? this.field.value.split(',') : this.field.value || []; }, initPrerecordedXform() { @@ -324,7 +325,6 @@ export default { // Check if the field object is defined. if (this.field) { let newValue; - // If the function is triggered by an event from a template input. if (val && val.target) { // For boolean fields (like checkboxes), use the 'checked' property. @@ -341,11 +341,10 @@ export default { // If the function is called directly with a value (not from an event). newValue = val; } - // Set the new value for the field. - if (this.isConditionalField) { + if (this.useValueOnly) { // If the component is used to update directly a returned value, emit an event with the new value. - this.$emit('update:condition-value', newValue); + this.$emit('update:value', newValue); } else { // Otherwise, update the Vuex store with the new value for the extra form field. this.UPDATE_EXTRA_FORM({ ...this.field, value: newValue }); diff --git a/src/components/FeatureType/CustomFormConditionalField.vue b/src/components/FeatureType/CustomFormConditionalField.vue index d7005d0f2fa07cf5b91a1b1e63e2426736d08080..588da94de27f789579dd7efbef8622533138b960 100644 --- a/src/components/FeatureType/CustomFormConditionalField.vue +++ b/src/components/FeatureType/CustomFormConditionalField.vue @@ -36,8 +36,8 @@ class="full-width" name="conditioning-value" :field="{...conditioningCustForm, value: config.conditionValue}" - :is-conditional-field="true" - @update:condition-value="updateConditionValue($event)" + :use-value-only="true" + @update:value="updateConditionValue($event)" /> </div> </div> @@ -64,8 +64,8 @@ class="full-width" name="forced-value" :field="{...customForm, value: config.forcedValue}" - :is-conditional-field="true" - @update:condition-value="updateForcedValue($event)" + :use-value-only="true" + @update:value="updateForcedValue($event)" /> </div> </div> diff --git a/src/components/Project/Edition/ProjectAttributeForm.vue b/src/components/Project/Edition/ProjectAttributeForm.vue new file mode 100644 index 0000000000000000000000000000000000000000..39de284a274e89613ce392c8f1862c1f1ecd05ef --- /dev/null +++ b/src/components/Project/Edition/ProjectAttributeForm.vue @@ -0,0 +1,85 @@ +<template> + <div class="field"> + <label for="attribute-value"> + {{ attribute.label }} + </label> + <div> + <FeatureExtraForm + :id="`attribute-value-for-${attribute.name}`" + ref="extraForm" + name="attribute-value" + :field="{ ...attribute, value }" + :use-value-only="true" + @update:value="updateValue($event.toString(), attribute.id)" + /> + </div> + </div> +</template> + +<script> +import FeatureExtraForm from '@/components/Feature/Edit/FeatureExtraForm'; + +export default { + + name: 'ProjectAttributeForm', + + components: { + FeatureExtraForm, + }, + + props: { + attribute: { + type: Object, + default: () => { + return {}; + } + }, + formProjectAttributes: { + type: Array, + default: () => { + return []; + } + } + }, + + computed: { + /** + * Retrieves the value of a project attribute from project data. + * + * @returns {String|null} The current value of the attribute for the project if set; + */ + value() { + // Find the attribute within the project's current attributes array. + const projectAttribute = this.formProjectAttributes.find(el => el.attribute_id === this.attribute.id); + // If the attribute is set in this project, return its value, otherwise return the attribute's default value. + return projectAttribute ? projectAttribute.value : this.attribute.default_value; + }, + }, + + methods: { + /** + * Updates the value of a project attribute or adds a new attribute if it does not exist. + * + * This function looks for an attribute by its ID. If the attribute exists, its value is updated. + * If the attribute does not exist, a new attribute object is added to the `project_attributes` array. + * + * @param {String} value - The new value to be assigned to the project attribute. + * @param {Number} attributeId - The ID of the attribute to be updated or added. + */ + updateValue(value, attributeId) { + let projectAttributes = [...this.formProjectAttributes]; + // Find the index of the attribute in the project_attributes array. + const attributeIndex = projectAttributes.findIndex(el => el.attribute_id === attributeId); + if (attributeIndex !== -1) { + // Directly update the attribute's value if it exists. + projectAttributes[attributeIndex].value = value; + } else { + // Add a new attribute object if it does not exist. + projectAttributes.push({ attribute_id: attributeId, value }); + } + this.$emit('update:project_attributes', projectAttributes); + } + } +}; + +</script> diff --git a/src/main.js b/src/main.js index 307162748226746f4f95b55c4d0f9c7cfef31550..91690b654516275c35c5354cce5c752ff170c735 100644 --- a/src/main.js +++ b/src/main.js @@ -112,6 +112,7 @@ const fetchDataAndInitializeApp = async () => { store.dispatch('map/GET_AVAILABLE_LAYERS'), store.dispatch('GET_USER_LEVEL_PERMISSIONS'), store.dispatch('GET_LEVELS_PERMISSIONS'), + store.dispatch('GET_PROJECT_ATTRIBUTES'), ]); new Vue({ diff --git a/src/store/index.js b/src/store/index.js index 3b9292bfcf44d2063b9b8179972ce1ce63e149a0..fba773d7ef43f175e5f5bbdb788fb1f74d654c56 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -36,6 +36,7 @@ export default new Vuex.Store({ logged: false, messageCount: 0, messages: [], + projectAttributes: [], reloadIntervalId: null, staticPages: null, user: false, @@ -54,9 +55,6 @@ export default new Vuex.Store({ SET_CONFIG(state, payload) { state.configuration = payload; }, - SET_COOKIE(state, cookie) { // ! not called anywhere. Delete it ? - state.cookie = cookie; - }, SET_STATIC_PAGES(state, staticPages) { state.staticPages = staticPages; }, @@ -69,13 +67,15 @@ export default new Vuex.Store({ SET_USER_TOKEN(state, payload) { state.userToken = payload; }, - SET_USER_PERMISSIONS(state, userPermissions) { state.user_permissions = userPermissions; }, SET_LEVELS_PERMISSIONS(state, levelsPermissions) { state.levelsPermissions = levelsPermissions; }, + SET_PROJECT_ATTRIBUTES(state, userPermissions) { + state.projectAttributes = userPermissions; + }, DISPLAY_MESSAGE(state, message) { message['counter'] = state.messageCount; state.messageCount += 1; @@ -308,6 +308,18 @@ export default new Vuex.Store({ throw error; }); }, + GET_PROJECT_ATTRIBUTES({ commit }) { + return axios + .get(`${this.state.configuration.VUE_APP_DJANGO_API_BASE}project-attributes/`) + .then((response) => { + if (response && response.status === 200) { + commit('SET_PROJECT_ATTRIBUTES', response.data); + } + }) + .catch((error) => { + throw error; + }); + }, CANCEL_CURRENT_SEARCH_REQUEST({ state }) { if (state.cancellableSearchRequest.length > 0) { const currentRequestCancelToken = diff --git a/src/views/Project/ProjectEdit.vue b/src/views/Project/ProjectEdit.vue index aed9494b10f663cc4efa7494420d6cb49aed4965..c626b1d0087f8eef4acf024896ab8f2cb46f8795 100644 --- a/src/views/Project/ProjectEdit.vue +++ b/src/views/Project/ProjectEdit.vue @@ -299,6 +299,24 @@ </div> </div> + + <div class="ui horizontal divider"> + ATTRIBUTS + </div> + + <div + v-if="project" + class="fields grouped" + > + <ProjectAttributeForm + v-for="(attribute, index) in projectAttributes" + :key="index" + :attribute="attribute" + :form-project-attributes="form.project_attributes" + @update:project_attributes="form.project_attributes = $event" + /> + </div> + <div class="ui divider" /> <button @@ -318,7 +336,8 @@ <script> import axios from '@/axios-client.js'; -import Dropdown from '@/components/Dropdown.vue'; +import Dropdown from '@/components/Dropdown'; +import ProjectAttributeForm from '@/components/Project/Edition/ProjectAttributeForm'; import mapService from '@/services/map-service'; import TextareaMarkdown from 'textarea-markdown'; @@ -330,6 +349,7 @@ export default { components: { Dropdown, + ProjectAttributeForm }, data() { @@ -389,7 +409,9 @@ export default { generate_share_link: false, fast_edition_mode: false, feature_browsing_default_filter: '', - feature_browsing_default_sort: '-created_on' + feature_browsing_default_sort: '-created_on', + project_attributes: [], + }, thumbnailFileSrc: '', scalesTable: [ @@ -423,6 +445,7 @@ export default { computed: { ...mapState([ 'levelsPermissions', + 'projectAttributes' ]), ...mapState('projects', ['project']), DJANGO_BASE_URL: function () { @@ -661,17 +684,9 @@ export default { return; } const projectData = { - title: this.form.title, - description: this.form.description, + ...this.form, access_level_arch_feature: this.form.access_level_arch_feature.value, access_level_pub_feature: this.form.access_level_pub_feature.value, - archive_feature: this.form.archive_feature, - delete_feature: this.form.delete_feature, - map_max_zoom_level: this.form.map_max_zoom_level, - is_project_type: this.form.is_project_type, - generate_share_link: this.form.generate_share_link, - fast_edition_mode: this.form.fast_edition_mode, - moderation: this.form.moderation, feature_browsing_default_sort: this.form.feature_browsing_default_sort.value, feature_browsing_default_filter: this.form.feature_browsing_default_filter.value, }; @@ -802,7 +817,7 @@ export default { zoomMap() { mapService.zoom(this.form.map_max_zoom_level); - } + }, }, }; </script>