Compare commits
5 commits
9cbf6352a3
...
84f10d7365
Author | SHA1 | Date | |
---|---|---|---|
84f10d7365 | |||
7da41b56fe | |||
52672a944d | |||
bc064e438e | |||
e8c7438c52 |
|
@ -6,22 +6,15 @@ This file is part of LiberaForms.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="is_loading===true">
|
<div v-if="is_loading===true" class="ds-loading">
|
||||||
<div class="ds-loading">
|
{{ $t('Loading...') }}
|
||||||
{{ $t('Loading...') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<DisplayPanel v-else />
|
||||||
|
|
||||||
<DisplayPanel />
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { inject, computed, provide } from "vue";
|
import { inject, computed } from "vue";
|
||||||
import { dataDisplayStore } from '@/store.js'
|
import { dataDisplayStore } from '@/store.js'
|
||||||
import DisplayPanel from '@/components/panel/DisplayPanel.vue'
|
import DisplayPanel from '@/components/panel/DisplayPanel.vue'
|
||||||
|
|
||||||
|
|
|
@ -7,25 +7,35 @@ This file is part of LiberaForms.
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<ItemsGrid v-if="display_items" />
|
<div v-if="!is_loading">
|
||||||
|
<h2 v-if="!has_items" class="ds-no-data">
|
||||||
|
{{ $t('No data') }}
|
||||||
|
</h2>
|
||||||
|
<template v-else-if="display_items">
|
||||||
|
<ItemsGrid class="mt-4" />
|
||||||
|
|
||||||
<FieldModal v-if="!is_loading"
|
<FieldModal v-if="display_items"
|
||||||
:show_modal="show_field_modal"
|
:show_modal="show_field_modal"
|
||||||
:data="field_modal_data"
|
:data="field_modal_data"
|
||||||
@closeFieldModal="closeFieldModal" />
|
@closeFieldModal="closeFieldModal" />
|
||||||
|
|
||||||
|
<DeleteItemModal v-if="delete_item_initiated" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { computed, provide, ref, toRefs, reactive } from "vue";
|
import { computed, provide, ref, reactive } from "vue";
|
||||||
import { dataDisplayStore } from '@/store.js'
|
import { dataDisplayStore } from '@/store.js'
|
||||||
import ItemsGrid from '@/components/itemsRenderer/ItemsGrid.vue'
|
import ItemsGrid from '@/components/itemsRenderer/ItemsGrid.vue'
|
||||||
import FieldModal from '@/components/itemsRenderer/FieldModal.vue'
|
import FieldModal from '@/components/itemsRenderer/FieldModal.vue'
|
||||||
|
import DeleteItemModal from '@/components/itemsRenderer/DeleteItemModal.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ItemsRenderer',
|
name: 'ItemsRenderer',
|
||||||
components: {
|
components: {
|
||||||
ItemsGrid, FieldModal
|
ItemsGrid, FieldModal, DeleteItemModal
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
|
@ -39,6 +49,7 @@ export default {
|
||||||
item_id: null
|
item_id: null
|
||||||
|
|
||||||
})
|
})
|
||||||
|
const has_items = computed(() => {return store.itemsToDisplay.length})
|
||||||
|
|
||||||
function showFieldEditor(data) {
|
function showFieldEditor(data) {
|
||||||
//console.log("showFieldEditor:", data.item_id, data.field_name, data.field_value)
|
//console.log("showFieldEditor:", data.item_id, data.field_name, data.field_value)
|
||||||
|
@ -58,7 +69,7 @@ export default {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
display_items: computed(() => {
|
display_items: computed(() => {
|
||||||
if (store.downloading_items) {
|
if (store.downloading_items || !has_items) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (store.pdf_builder_mode) {
|
if (store.pdf_builder_mode) {
|
||||||
|
@ -69,13 +80,31 @@ export default {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}),
|
}),
|
||||||
|
has_items,
|
||||||
field_modal_data, show_field_modal, closeFieldModal,
|
field_modal_data, show_field_modal, closeFieldModal,
|
||||||
is_loading: computed(() => store.downloading_items),
|
is_loading: computed(() => store.downloading_items),
|
||||||
|
delete_item_initiated: computed(() => { return store.delete_item_initiated }),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style>
|
||||||
|
.ds-empty-field {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ds-loading {
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--lf-gray-800);
|
||||||
|
margin-top: 1.5em;
|
||||||
|
}
|
||||||
|
.ds-no-data {
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--lf-gray-600);
|
||||||
|
margin-top: 1em;
|
||||||
|
font-size: 1.75em;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
<!--
|
|
||||||
This file is part of LiberaForms.
|
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2024 LiberaForms.org
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
-->
|
|
||||||
|
|
||||||
<template>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { computed } from "vue";
|
|
||||||
import { dataDisplayStore } from '@/store.js'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'DeleteItem',
|
|
||||||
components: {
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = dataDisplayStore()
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
108
src/components/itemsRenderer/DeleteItemModal.vue
Normal file
108
src/components/itemsRenderer/DeleteItemModal.vue
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
<!--
|
||||||
|
This file is part of LiberaForms.
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: 2024 LiberaForms.org
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div tabindex="-1" aria-labelledby="delete-modal-label" aria-hidden="true"
|
||||||
|
class="modal fade d-block show"
|
||||||
|
@keydown.esc="closeModal()"
|
||||||
|
role="dialog">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="delete-modal-label">
|
||||||
|
{{ $t("Delete answer")}}
|
||||||
|
</h5>
|
||||||
|
<button type="button" aria-label="Close"
|
||||||
|
v-on:click="closeModal()">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
{{ $t("This cannot be undone!") }}
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-danger"
|
||||||
|
v-on:click="deleteItem()">
|
||||||
|
{{ $t("Delete") }}
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-secondary"
|
||||||
|
v-on:click="closeModal()">
|
||||||
|
{{ $t("Cancel") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-backdrop fade show"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios';
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { dataDisplayStore } from '@/store.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DeleteItemModal',
|
||||||
|
components: {
|
||||||
|
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const store = dataDisplayStore()
|
||||||
|
|
||||||
|
const item_id = store.delete_item_initiated
|
||||||
|
|
||||||
|
function deleteItem() {
|
||||||
|
|
||||||
|
function removeFromStore() {
|
||||||
|
let item_pos = store.items.findIndex(item => item.id === item_id)
|
||||||
|
store.items.splice(item_pos, 1)
|
||||||
|
store.meta.total = store.meta.total - 1
|
||||||
|
if (store.filtered_items) {
|
||||||
|
let item_pos = store.filtered_items.findIndex(item => item.id === item_id)
|
||||||
|
store.filtered_items.splice(item_pos, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let endpoint = store.item_endpoint + item_id + '/delete'
|
||||||
|
axios.delete(endpoint)
|
||||||
|
.then(response => {
|
||||||
|
if (response.data.deleted == true) {
|
||||||
|
removeFromStore()
|
||||||
|
if (response.data.remove_alert != false) {
|
||||||
|
let alert = document.getElementById(response.data.remove_alert.disk_alert)
|
||||||
|
if (alert !== null) {
|
||||||
|
alert.remove()
|
||||||
|
let alert_menu = document.getElementById(response.data.remove_alert.alerts)
|
||||||
|
let alerts = alert_menu.querySelectorAll("li");
|
||||||
|
if (alerts.length == 0) {
|
||||||
|
alert_menu.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log(e)
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.closeModal()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
store.delete_item_initiated = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
deleteItem, closeModal,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -24,7 +24,7 @@ This file is part of LiberaForms.
|
||||||
data-dismiss="modal"
|
data-dismiss="modal"
|
||||||
aria-label="Close"
|
aria-label="Close"
|
||||||
v-on:click="closeModal()">
|
v-on:click="closeModal()">
|
||||||
<XIcon aria-hidden="true" />
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
@ -131,12 +131,12 @@ This file is part of LiberaForms.
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import { dataDisplayStore } from '@/store.js'
|
import { dataDisplayStore } from '@/store.js'
|
||||||
import { XIcon } from '@zhuowenli/vue-feather-icons'
|
//import { XIcon } from '@zhuowenli/vue-feather-icons'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FieldModal',
|
name: 'FieldModal',
|
||||||
components: {
|
components: {
|
||||||
XIcon
|
//XIcon
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
data: Object,
|
data: Object,
|
||||||
|
|
|
@ -31,7 +31,6 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
field_name: String,
|
field_name: String,
|
||||||
field_value: undefined,
|
field_value: undefined,
|
||||||
edit_mode: Boolean,
|
|
||||||
item_id: Number,
|
item_id: Number,
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
|
|
@ -12,8 +12,7 @@ This file is part of LiberaForms.
|
||||||
class="p-0 stickyColumn first_sticky_col">
|
class="p-0 stickyColumn first_sticky_col">
|
||||||
|
|
||||||
<RowControls :item_id="item.id"
|
<RowControls :item_id="item.id"
|
||||||
:marked="item.marked"
|
:marked="item.marked" />
|
||||||
:edit_mode="edit_mode" />
|
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td v-else
|
<td v-else
|
||||||
|
@ -21,9 +20,7 @@ This file is part of LiberaForms.
|
||||||
<div :style="column_width">
|
<div :style="column_width">
|
||||||
<FieldRender :field_name="field.name"
|
<FieldRender :field_name="field.name"
|
||||||
:field_value="field.name == 'created' ? item.created : item.data[field.name]"
|
:field_value="field.name == 'created' ? item.created : item.data[field.name]"
|
||||||
:item_id="item.id"
|
:item_id="item.id" />
|
||||||
:edit_mode="field.name == 'created' ? false : edit_mode">
|
|
||||||
</FieldRender>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</template>
|
</template>
|
||||||
|
@ -44,7 +41,6 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
item: Object,
|
item: Object,
|
||||||
field_index: Object,
|
field_index: Object,
|
||||||
edit_mode: Boolean,
|
|
||||||
is_data_sticky: Boolean,
|
is_data_sticky: Boolean,
|
||||||
delete_initiated: Boolean,
|
delete_initiated: Boolean,
|
||||||
column_width: Object,
|
column_width: Object,
|
||||||
|
|
|
@ -7,7 +7,7 @@ This file is part of LiberaForms.
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="is_loading === false"
|
<div v-if="is_loading === false"
|
||||||
class="d-flex align-items-center justify-content-end my-4">
|
class="d-flex align-items-center justify-content-end mb-2">
|
||||||
<small class="page_count_display me-2">
|
<small class="page_count_display me-2">
|
||||||
{{ getPaginationText() }}
|
{{ getPaginationText() }}
|
||||||
</small>
|
</small>
|
||||||
|
|
|
@ -7,8 +7,6 @@ This file is part of LiberaForms.
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<ItemPagination />
|
|
||||||
|
|
||||||
{{ column_width }}
|
{{ column_width }}
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
|
@ -38,7 +36,6 @@ This file is part of LiberaForms.
|
||||||
<GridRow v-for="item in items" :key="item.id"
|
<GridRow v-for="item in items" :key="item.id"
|
||||||
:item="item"
|
:item="item"
|
||||||
:field_index="field_index"
|
:field_index="field_index"
|
||||||
:edit_mode="edit_mode"
|
|
||||||
:is_data_sticky="is_data_sticky"
|
:is_data_sticky="is_data_sticky"
|
||||||
:highlighted_row="highlighted_row"
|
:highlighted_row="highlighted_row"
|
||||||
@click="highlighted_row = item.id"
|
@click="highlighted_row = item.id"
|
||||||
|
@ -47,12 +44,13 @@ This file is part of LiberaForms.
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<ItemPagination />
|
||||||
<NumericTotals />
|
<NumericTotals />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref, inject } from "vue";
|
||||||
import { dataDisplayStore } from '@/store.js'
|
import { dataDisplayStore } from '@/store.js'
|
||||||
import { orderItems } from '@/modules/items.js'
|
import { orderItems } from '@/modules/items.js'
|
||||||
import { ArrowDownIcon, CheckCircleIcon } from '@zhuowenli/vue-feather-icons'
|
import { ArrowDownIcon, CheckCircleIcon } from '@zhuowenli/vue-feather-icons'
|
||||||
|
@ -72,11 +70,10 @@ export default {
|
||||||
const data_type = store.data_type
|
const data_type = store.data_type
|
||||||
|
|
||||||
const field_index = computed(() => {
|
const field_index = computed(() => {
|
||||||
return store.user_prefs.field_index
|
return store.field_index
|
||||||
})
|
})
|
||||||
const highlighted_row = ref(0)
|
const highlighted_row = ref(0)
|
||||||
|
|
||||||
let edit_mode = false
|
|
||||||
var is_data_sticky = false
|
var is_data_sticky = false
|
||||||
|
|
||||||
let grid_width = 400 //$refs.table.clientWidth
|
let grid_width = 400 //$refs.table.clientWidth
|
||||||
|
@ -125,7 +122,7 @@ export default {
|
||||||
return "stickyColumn first_sticky_col sticky_data_col"
|
return "stickyColumn first_sticky_col sticky_data_col"
|
||||||
}
|
}
|
||||||
if (col_index == 1) {
|
if (col_index == 1) {
|
||||||
if (edit_mode) {
|
if (store.show_other_options) {
|
||||||
return "stickyColumn sticky_data_col sticky_data_col_with_controls_expanded";
|
return "stickyColumn sticky_data_col sticky_data_col_with_controls_expanded";
|
||||||
}
|
}
|
||||||
if (store.has_row_controls) {
|
if (store.has_row_controls) {
|
||||||
|
@ -146,8 +143,6 @@ export default {
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
store,
|
|
||||||
edit_mode,
|
|
||||||
items: computed(() => store.paginatedItems),
|
items: computed(() => store.paginatedItems),
|
||||||
field_index,
|
field_index,
|
||||||
setOrder,
|
setOrder,
|
||||||
|
|
|
@ -12,11 +12,11 @@ This file is part of LiberaForms.
|
||||||
:aria-label="$t('Mark for reference')">
|
:aria-label="$t('Mark for reference')">
|
||||||
<CheckCircleIcon size="1.3x" />
|
<CheckCircleIcon size="1.3x" />
|
||||||
</button>
|
</button>
|
||||||
<button v-if="edit_mode==true"
|
<button v-if="with_other_options"
|
||||||
class="ds-delete-button"
|
class="ds-delete-button"
|
||||||
:class="{'ds-card-button':is_card==true}"
|
:class="{'ds-card-button':is_card==true}"
|
||||||
:aria-label="$t('Delete answer')"
|
:aria-label="$t('Delete answer')"
|
||||||
v-on:click="deleteItem">
|
v-on:click="initiateDelete()">
|
||||||
<TrashIcon size="1.3x" />
|
<TrashIcon size="1.3x" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,18 +36,18 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
item_id: Number,
|
item_id: Number,
|
||||||
marked: Boolean,
|
marked: Boolean,
|
||||||
edit_mode: Boolean,
|
|
||||||
is_card: Boolean,
|
is_card: Boolean,
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const store = dataDisplayStore()
|
const store = dataDisplayStore()
|
||||||
|
const with_other_options = computed(() => { return store.show_other_options })
|
||||||
|
|
||||||
const controlClass = computed(() => {
|
const controlClass = computed(() => {
|
||||||
if (props.is_card==true) {
|
if (props.is_card==true) {
|
||||||
return props.edit_mode ? 'card-controls editMode' : 'card-controls nonEditMode'
|
return with_other_options ? 'card-controls editMode' : 'card-controls nonEditMode'
|
||||||
} else {
|
} else {
|
||||||
return props.edit_mode ? 'grid-controls editMode' : 'grid-controls nonEditMode'
|
return with_other_options ? 'grid-controls editMode' : 'grid-controls nonEditMode'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -66,9 +66,16 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initiateDelete() {
|
||||||
|
store.delete_item_initiated = props.item_id
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
controlClass,
|
controlClass,
|
||||||
toggleBookmarked,
|
toggleBookmarked,
|
||||||
|
with_other_options,
|
||||||
|
initiateDelete
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ This file is part of LiberaForms.
|
||||||
v-on:click="displayItemsAs('cards')">
|
v-on:click="displayItemsAs('cards')">
|
||||||
{{ $t("Cards") }}
|
{{ $t("Cards") }}
|
||||||
</button>
|
</button>
|
||||||
<button v-if="include_graphs"
|
<button v-if="data_type='answer'"
|
||||||
class="btn btn-sm"
|
class="btn btn-sm"
|
||||||
:class="button_classes.graphs"
|
:class="button_classes.graphs"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
|
@ -56,7 +56,8 @@ export default {
|
||||||
'grid': store.display_items_as == 'grid' ? 'btn-primary' : 'btn-outline-secondary',
|
'grid': store.display_items_as == 'grid' ? 'btn-primary' : 'btn-outline-secondary',
|
||||||
'graphs': store.display_items_as == 'graphs' ? 'btn-primary' : 'btn-outline-secondary'
|
'graphs': store.display_items_as == 'graphs' ? 'btn-primary' : 'btn-outline-secondary'
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
|
data_type: store.data_type,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,34 +6,69 @@ This file is part of LiberaForms.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
|
||||||
|
|
||||||
<PanelControls />
|
|
||||||
<div class="ds-panel-desktop-container-1">
|
<div class="ds-panel-desktop-container-1">
|
||||||
|
<ExportOptions />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-2 ds-panel-desktop-container-1">
|
||||||
<!--<Filters :mq="$mq" :field_index="field_index" />-->
|
<!--<Filters :mq="$mq" :field_index="field_index" />-->
|
||||||
<ItemFilters />
|
<ItemFilters />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<div v-if="data_type=='answer'"
|
||||||
|
class="mt-3 ds-panel-desktop-container-1"
|
||||||
|
:class="controlGroupClasses()">
|
||||||
|
|
||||||
|
<div class="ds-controls-height">
|
||||||
|
<DisplayModes />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ds-controls-height">
|
||||||
|
<OtherOptions />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { computed } from "vue";
|
import { computed, ref, provide } from "vue";
|
||||||
import { dataDisplayStore } from '@/store.js'
|
import { dataDisplayStore } from '@/store.js'
|
||||||
import ItemFilters from '@/components/panel/ItemFilters.vue'
|
import ItemFilters from '@/components/panel/ItemFilters.vue'
|
||||||
import PanelControls from '@/components/panel/PanelControls.vue'
|
import ExportOptions from '@/components/panel/ExportOptions.vue'
|
||||||
|
import DisplayModes from '@/components/panel/DisplayModes.vue'
|
||||||
|
import OtherOptions from '@/components/panel/OtherOptions.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DisplayPanel',
|
name: 'DisplayPanel',
|
||||||
components: {
|
components: {
|
||||||
ItemFilters, PanelControls
|
ItemFilters, ExportOptions, DisplayModes, OtherOptions
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
const store = dataDisplayStore()
|
const store = dataDisplayStore()
|
||||||
|
|
||||||
|
provide('has_items', computed(() => {return store.itemsToDisplay.length}))
|
||||||
|
|
||||||
|
let mq = "lg"
|
||||||
|
function controlGroupClasses() {
|
||||||
|
if (mq == "sm") {
|
||||||
|
return "mb-3"
|
||||||
|
}
|
||||||
|
if (store.data_type=='answer') {
|
||||||
|
return 'd-flex align-items-center justify-content-between'
|
||||||
|
}
|
||||||
|
if (store.data_type=='user') {
|
||||||
|
return 'd-flex align-items-center justify-content-end'
|
||||||
|
}
|
||||||
|
return "mt-1";
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
controlGroupClasses,
|
||||||
|
data_type: store.data_type,
|
||||||
|
has_items: computed(() => store.itemsToDisplay.length),
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -41,5 +76,14 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.ds-controls-height {
|
||||||
|
min-height: 31px !important;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
<style>
|
||||||
|
.ds-controls-title svg {
|
||||||
|
color: var(--lf-link-color);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default {
|
||||||
|
|
||||||
function generateCSV() {
|
function generateCSV() {
|
||||||
var columns = []
|
var columns = []
|
||||||
let field_index = store.user_prefs.field_index
|
let field_index = store.field_index
|
||||||
|
|
||||||
field_index.forEach((field, i) => {
|
field_index.forEach((field, i) => {
|
||||||
columns.push(field.label)
|
columns.push(field.label)
|
||||||
|
@ -86,7 +86,7 @@ export default {
|
||||||
function generateJSON() {
|
function generateJSON() {
|
||||||
var result = []
|
var result = []
|
||||||
let items = store.itemsToDisplay
|
let items = store.itemsToDisplay
|
||||||
let field_index = store.user_prefs.field_index
|
let field_index = store.field_index
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
var obj = new Object();
|
var obj = new Object();
|
||||||
for(let i = 0; i < field_index.length; i++) {
|
for(let i = 0; i < field_index.length; i++) {
|
||||||
|
|
|
@ -211,7 +211,7 @@ export default {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filter_text,
|
filter_text,
|
||||||
default_field_index: computed(() => store.default_field_index),
|
default_field_index: store.default_field_index,
|
||||||
|
|
||||||
order_by: computed(() => store.user_prefs.order_by),
|
order_by: computed(() => store.user_prefs.order_by),
|
||||||
first_field,
|
first_field,
|
||||||
|
|
78
src/components/panel/OtherOptions.vue
Normal file
78
src/components/panel/OtherOptions.vue
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<!--
|
||||||
|
This file is part of LiberaForms.
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: 2024 LiberaForms.org
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<button v-if="available_options"
|
||||||
|
class="btn btn-sm"
|
||||||
|
:class="show_options && has_items ? 'btn-primary' : 'btn-outline-primary'"
|
||||||
|
:disabled="!has_items"
|
||||||
|
v-on:click="toggleOptions()">
|
||||||
|
{{ $t("Options") }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<a v-if="show_options && can_edit && has_items"
|
||||||
|
class="btn btn-sm btn-outline-danger modes"
|
||||||
|
role="button"
|
||||||
|
:href="endpoint+'/delete-all-items'">
|
||||||
|
{{ $t("Delete all") }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<button v-if="has_deleted_fields && has_items"
|
||||||
|
class="btn btn-sm"
|
||||||
|
:class="show_deleted==true ? 'btn-primary' : 'btn-outline-secondary'"
|
||||||
|
v-on:click="displayDeletedFields()">
|
||||||
|
{{ $t("Include deleted fields") }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { computed, inject } from "vue";
|
||||||
|
import { dataDisplayStore } from '@/store.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'OtherOptions',
|
||||||
|
components: {
|
||||||
|
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const store = dataDisplayStore()
|
||||||
|
const has_items = inject('has_items')
|
||||||
|
|
||||||
|
function toggleOptions() {
|
||||||
|
store.show_other_options = !store.show_other_options
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayDeletedFields() {
|
||||||
|
store.include_deleted_fields = !store.include_deleted_fields
|
||||||
|
store.filtered_items = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
has_items,
|
||||||
|
can_edit: store.can_edit,
|
||||||
|
data_type: store.data_type,
|
||||||
|
endpoint: store.endpoint,
|
||||||
|
has_deleted_fields: store.deleted_fields.length,
|
||||||
|
available_options: store.can_edit || store.deleted_fields,
|
||||||
|
show_options: computed(() => store.show_other_options),
|
||||||
|
toggleOptions, displayDeletedFields,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ds-controls-height {
|
||||||
|
min-height: 31px !important;
|
||||||
|
}
|
||||||
|
.ds-controls-title svg {
|
||||||
|
color: var(--lf-link-color);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,86 +0,0 @@
|
||||||
<!--
|
|
||||||
This file is part of LiberaForms.
|
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2024 LiberaForms.org
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
||||||
-->
|
|
||||||
|
|
||||||
<template>
|
|
||||||
|
|
||||||
<div class="ds-modes-export-container-1"
|
|
||||||
:class="controlGroupClasses()">
|
|
||||||
|
|
||||||
<div v-if="data_type=='answer'" class="ds-controls-height">
|
|
||||||
|
|
||||||
<DisplayModes :disabled="pdf_builder_mode"
|
|
||||||
:include_graphs="data_type=='answer'" />
|
|
||||||
|
|
||||||
<!--<EditOptions v-if="can_edit" :edit_mode="edit_mode" :can_edit="can_edit" />-->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="pdf_builder_mode"
|
|
||||||
class="ds-controls-title ds-controls-height fs-5 fw-light">
|
|
||||||
<ArrowLeftIcon stroke-width="1" size="1.2x"
|
|
||||||
v-if="mq=='sm'"
|
|
||||||
@click="togglePdfBuilderMode()"/>
|
|
||||||
{{ $t("Export PDF") }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ExportOptions />
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { computed } from "vue";
|
|
||||||
import { dataDisplayStore } from '@/store.js'
|
|
||||||
import { ArrowLeftIcon } from '@zhuowenli/vue-feather-icons'
|
|
||||||
import DisplayModes from '@/components/panel/DisplayModes.vue'
|
|
||||||
import EditOptions from '@/components/panel/EditOptions.vue'
|
|
||||||
import ExportOptions from '@/components/panel/ExportOptions.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'PanelControls',
|
|
||||||
components: {
|
|
||||||
DisplayModes, EditOptions, ExportOptions,
|
|
||||||
ArrowLeftIcon,
|
|
||||||
},
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
const store = dataDisplayStore()
|
|
||||||
|
|
||||||
let mq = "lg"
|
|
||||||
|
|
||||||
function controlGroupClasses() {
|
|
||||||
if (mq == "sm") {
|
|
||||||
return "mb-3"
|
|
||||||
}
|
|
||||||
if (store.data_type=='answer') {
|
|
||||||
return 'd-flex align-items-center justify-content-between mb-4'
|
|
||||||
}
|
|
||||||
if (store.data_type=='user') {
|
|
||||||
return 'd-flex align-items-center justify-content-end mb-3'
|
|
||||||
}
|
|
||||||
return "mt-1";
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
controlGroupClasses,
|
|
||||||
can_edit: store.can_edit,
|
|
||||||
data_type: store.data_type,
|
|
||||||
pdf_builder_mode: computed(() => { return store.pdf_builder_mode }),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.ds-controls-height {
|
|
||||||
min-height: 31px !important;
|
|
||||||
}
|
|
||||||
.ds-controls-title svg {
|
|
||||||
color: var(--lf-link-color);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
</style>
|
|
10
src/store.js
10
src/store.js
|
@ -37,7 +37,9 @@ export const dataDisplayStore = defineStore("dataDisplayStore", {
|
||||||
page_length: 10,
|
page_length: 10,
|
||||||
can_edit: false,
|
can_edit: false,
|
||||||
show_modes: false,
|
show_modes: false,
|
||||||
|
show_other_options: false,
|
||||||
has_row_controls: false,
|
has_row_controls: false,
|
||||||
|
delete_item_initiated: null, // is the id of the item
|
||||||
include_deleted_fields: false,
|
include_deleted_fields: false,
|
||||||
display_items_as: "grid",
|
display_items_as: "grid",
|
||||||
pdf_builder_mode: false,
|
pdf_builder_mode: false,
|
||||||
|
@ -104,7 +106,7 @@ export const dataDisplayStore = defineStore("dataDisplayStore", {
|
||||||
return field_value
|
return field_value
|
||||||
},
|
},
|
||||||
getFieldLabel: (state) => (field_name) => {
|
getFieldLabel: (state) => (field_name) => {
|
||||||
var field = state.user_prefs.field_index.find(x => x.name === field_name)
|
var field = state.field_index.find(x => x.name === field_name)
|
||||||
if (field !== undefined) {
|
if (field !== undefined) {
|
||||||
return field.label
|
return field.label
|
||||||
}
|
}
|
||||||
|
@ -125,6 +127,12 @@ export const dataDisplayStore = defineStore("dataDisplayStore", {
|
||||||
});
|
});
|
||||||
return label
|
return label
|
||||||
},
|
},
|
||||||
|
field_index: (state) => {
|
||||||
|
if (state.include_deleted_fields && state.deleted_fields.length) {
|
||||||
|
return state.user_prefs.field_index.concat(state.deleted_fields)
|
||||||
|
}
|
||||||
|
return state.user_prefs.field_index
|
||||||
|
},
|
||||||
getFieldStructure: (state) => (field_name) => {
|
getFieldStructure: (state) => (field_name) => {
|
||||||
return _.findWhere(state.meta.form_structure, {name: field_name})
|
return _.findWhere(state.meta.form_structure, {name: field_name})
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
"Cards": "Cards",
|
"Cards": "Cards",
|
||||||
"Options": "Options",
|
"Options": "Options",
|
||||||
"Delete all": "Delete all",
|
"Delete all": "Delete all",
|
||||||
"Deleted fields": "Deleted fields",
|
"Include deleted fields": "Include deleted fields",
|
||||||
"True": "True",
|
"True": "True",
|
||||||
"False": "False",
|
"False": "False",
|
||||||
"Previous": "Previous",
|
"Previous": "Previous",
|
||||||
|
|
Loading…
Reference in a new issue