Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion vue/src/js/components/FormSummaryItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
:key="`stepper-preview-item-subtitle-${inputName}`"
>
<template
v-for="(context, key) in model[inputName]"
v-for="(context, key) in sortedModelData(inputName)"
:key="`stepper-preview-item-subtitle-${inputName}-${index}`"
>
<!-- Array context -->
Expand Down Expand Up @@ -81,6 +81,37 @@ export default {
required: true
}
},
methods: {
sortedModelData(inputName) {
const data = this.model[inputName]

if (!data) return {}

// If it's an array, sort it
if (Array.isArray(data)) {
return data.sort((a, b) => {
// If array elements are strings, sort alphabetically
if (typeof a === 'string' && typeof b === 'string') {
return a.localeCompare(b)
}
// If array elements are arrays (like ['Country', 'Package']), sort by first element
if (Array.isArray(a) && Array.isArray(b) && a[0] && b[0]) {
return a[0].localeCompare(b[0])
}
return 0
})
}

// If it's an object, convert to array of entries and sort by key
if (typeof data === 'object') {
return Object.entries(data).sort(([keyA], [keyB]) => {
return keyA.localeCompare(keyB)
})
}

return data
}
},
created() {

}
Expand Down
20 changes: 18 additions & 2 deletions vue/src/js/components/ListSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

<!-- Data rows -->
<div
v-for="(item, i) in items"
v-for="(item, i) in sortedItems"
:key="`item-${i}`"
class="ue-list-section__row ue-list-section__row--data"
:class="[getRowClass(item, i), {'has-bottom-border': hasRowBottomBorder}]"
Expand All @@ -57,7 +57,7 @@
</div>

<!-- Empty state message -->
<div v-if="items.length === 0 && emptyMessage" class="ue-list-section__row ue-list-section__row--empty">
<div v-if="sortedItems.length === 0 && emptyMessage" class="ue-list-section__row ue-list-section__row--empty">
<div class="ue-list-section__row--empty .ue-list-section__cell">{{ emptyMessage }}</div>
</div>
</div>
Expand Down Expand Up @@ -155,6 +155,22 @@ export default {
});
},

sortedItems() {
// Sort items alphabetically by the first field (usually the name/title)
return [...this.items].sort((a, b) => {
const fieldA = this.$lodash.get(a, this.itemFields[0], '')
const fieldB = this.$lodash.get(b, this.itemFields[0], '')

// Handle different data types
if (typeof fieldA === 'string' && typeof fieldB === 'string') {
return fieldA.localeCompare(fieldB)
}

// Fallback to string comparison
return String(fieldA).localeCompare(String(fieldB))
})
},

totalRatio() {
// Calculate the total ratio to determine percentages
if (!this.colRatios || this.colRatios.length === 0) {
Expand Down
5 changes: 3 additions & 2 deletions vue/src/js/components/StepperForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -484,9 +484,10 @@

return result
},
handleFinalFormAction({index, event}) {
// For Addon conflict.
handleFinalFormAction({index, event,data}) {
// const data = this.previewFormData[index]
const data = this.lastFormPreview[index]
// const data = this.lastFormPreview[index]
const fieldName = data.fieldName
const fieldFormat = data._fieldFormat ?? 'id'
const lastStepModel = cloneDeep(this.lastStepModel)
Expand Down
71 changes: 61 additions & 10 deletions vue/src/js/components/inputs/FormTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@

<script>
import { toRefs, reactive, ref, computed, watch } from 'vue';
import { cloneDeep, each, filter, startCase, snakeCase, isString } from 'lodash-es';
import { cloneDeep, each, filter, startCase, snakeCase, isString, get } from 'lodash-es';
import { useI18n } from 'vue-i18n';
import { useInput,
makeInputProps,
Expand Down Expand Up @@ -106,6 +106,15 @@ export default {
type: Array,
default: () => ['*']
},
orderBy: {
type: String,
default: 'name'
},
orderByDirection: {
type: String,
default: 'asc',
validator: (value) => ['asc', 'desc'].includes(value)
},
noSchemaUpdatingProgressBar: {
type: Boolean,
default: false
Expand All @@ -119,7 +128,33 @@ export default {

const { matchStandardAttribute, castStandardAttribute, castEvalAttribute, castAttribute, castObjectAttribute } = useCastAttributes()

const elements = ref(props.items)
// Helper function to sort items based on configurable parameters
const sortItems = (items) => {
return [...items].sort((a, b) => {
const fieldA = a[props.orderBy] || ''
const fieldB = b[props.orderBy] || ''

// Handle different data types
let comparison = 0
if (typeof fieldA === 'string' && typeof fieldB === 'string') {
comparison = fieldA.localeCompare(fieldB)
} else if (typeof fieldA === 'number' && typeof fieldB === 'number') {
comparison = fieldA - fieldB
} else {
// Fallback to string comparison
comparison = String(fieldA).localeCompare(String(fieldB))
}

return props.orderByDirection === 'desc' ? -comparison : comparison
})
}

// Sort items based on configurable orderBy and orderByDirection parameters
const sortedItems = computed(() => {
return sortItems(props.items)
})

const elements = ref(sortedItems.value)
const loading = ref(true)

const formRefs = reactive(new Map())
Expand All @@ -134,7 +169,7 @@ export default {

const getFormRef = (id) => formRefs.get(id)

const models = ref(elements.value.reduce((acc, item) => {
const models = ref(sortedItems.value.reduce((acc, item) => {
if(!__isset(acc[item.id])){
acc[item.id] = {
...(getModel(props.schema, {})),
Expand Down Expand Up @@ -249,7 +284,7 @@ export default {
return getSchema(baseSchema, models.value?.[item.id] ?? {})
}

const schemas = ref(elements.value.reduce((acc, item, index) => {
const schemas = ref(sortedItems.value.reduce((acc, item, index) => {
if(!__isset(acc[item.id])){
acc[item.id] = generateSchema(item)
// Process initial triggers
Expand All @@ -259,20 +294,20 @@ export default {
return acc
}, {}))

const valids = ref(elements.value.reduce((acc, item, i) => {
const valids = ref(sortedItems.value.reduce((acc, item, i) => {
acc[i] = null
return acc
}, {}))

if(elements.value.length > 0){
if(sortedItems.value.length > 0){
loading.value = false
}

const states = reactive({
loading,
elements,
formRefs,
activeTab: 1,
activeTab: 0,
models,
schemas,
valids,
Expand All @@ -281,6 +316,9 @@ export default {
watch(() => props.items, (newVal) => {
loading.value = true

// Get sorted items for display using configurable parameters
const newSortedItems = sortItems(newVal)

let addedItems = newVal.filter(item => !elements.value.find(el => el.id == item.id))
let removedItems = elements.value.filter(item => !newVal.find(el => el.id == item.id))

Expand All @@ -299,7 +337,10 @@ export default {
schemas.value = updatedSchemas
}

valids.value[item.id] = null
const itemIndex = newSortedItems.findIndex(el => el.id === item.id)
if (itemIndex !== -1) {
valids.value[itemIndex] = null
}
// setFormRef(item.id, null)
})
}
Expand All @@ -308,12 +349,22 @@ export default {
removedItems.forEach(item => {
delete models.value[item.id]
delete schemas.value[item.id]
delete valids.value[item.id]
const itemIndex = elements.value.findIndex(el => el.id === item.id)
if (itemIndex !== -1) {
delete valids.value[itemIndex]
}
setFormRef(item.id, null)
})
}

elements.value = newVal
// Update elements with sorted items for display
elements.value = newSortedItems

// Reinitialize valids array with correct size
valids.value = newSortedItems.reduce((acc, item, i) => {
acc[i] = null
return acc
}, {})
})

watch(() => elements.value, (newVal) => {
Expand Down
42 changes: 37 additions & 5 deletions vue/src/js/components/stepper/StepperPreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@
</ue-title>

<v-row>
<!-- Preview cards -->
<template v-for="(context, index) in formattedPreview" :key="`summary-${index}`">
<!-- Country cards (sorted alphabetically) -->
<template v-for="(context, index) in sortedCountryCards" :key="`country-${index}`">
<v-col cols="12" :md="context.col || 6" class="d-flex">
<ue-configurable-card v-bind="context" elevation="2" title-color="primary" class="my-2 w-100 h-100" col-padding-x="4"/>
</v-col>
</template>

<!-- Final form data -->
<!-- Press Release Content card (if exists) -->
<v-col v-if="pressReleaseContentCard" cols="12" :md="pressReleaseContentCard.col || 12" class="d-flex">
<ue-configurable-card v-bind="pressReleaseContentCard" elevation="2" title-color="primary" class="my-2 w-100 h-100" col-padding-x="4"/>
</v-col>

<!-- Final form data (Add-ons) -->
<v-col cols="12" v-if="previewFormData.length > 0" v-fit-grid>
<v-sheet class="px-0">
<div class="d-flex flex-column ga-2 my-4">
Expand All @@ -36,7 +41,7 @@
</div>
<!-- Preview form items -->
<template
v-for="(data, index) in previewFormData"
v-for="(data, index) in sortedPreviewFormData"
:key="`final-form-data-${index}`"
>
<ue-configurable-card
Expand Down Expand Up @@ -111,6 +116,7 @@
:color="getFieldColor(data)"
@click="$emit('final-form-action', {
index: index,
data: data,
event: !fieldSelected(data)
})"
:readonly="isReadOnly(data)"
Expand Down Expand Up @@ -157,6 +163,32 @@ export default {
default: () => {}
}
},
computed: {
sortedCountryCards() {
// Filter and sort only country cards (exclude Press Release Content)
return [...this.formattedPreview]
.filter(card => card.title && !card.title.toLowerCase().includes('press release'))
.sort((a, b) => {
const titleA = a.title || ''
const titleB = b.title || ''
return titleA.localeCompare(titleB)
})
},
pressReleaseContentCard() {
// Find the Press Release Content card
return this.formattedPreview.find(card =>
card.title && card.title.toLowerCase().includes('press release')
)
},
sortedPreviewFormData() {
// Sort add-ons alphabetically by name
return [...this.previewFormData].sort((a, b) => {
const nameA = a.name || ''
const nameB = b.name || ''
return nameA.localeCompare(nameB)
})
}
},
methods: {
fieldSelected(data) {
const fieldName = data.fieldName
Expand All @@ -167,7 +199,7 @@ export default {

let selected = false
if(isString(fieldFormat)){
result = includes(values, data[fieldFormat])
selected = includes(values, data[fieldFormat])
}else if(isObject(fieldFormat)){
let item = values.find(item => item[fieldFormatUniqueKey] === data[fieldFormatSourceKey])
selected = item !== undefined && item !== null
Expand Down
Loading