Changes in appbase query after migrating to 3.1.0-alpha.1
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Accessibilité débutants
- 25/100
- Type d'issue
- Bug
- Clarté
- À clarifier
- Activité
- À l'abandon
- Stack technique
- javascript
Piste de recherche
Commencez par le point d’entrée montré de reactive-list, en particulier @queryChange, defaultQuery et la configuration react, et comparez les requêtes générées entre les deux versions de la bibliothèque. Reproduisez l’échec de la mise à jour en masse avec le composant Vue et les captures d’écran fournis ; le travail est considéré comme terminé lorsque la modification de la forme de la query et une manière prise en charge de conserver ou d’adapter la requête ont été établies.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Affected Projects
Vue.JS
Library Version: x.y.z
"@appbaseio/reactivesearch-vue": "3.1.0-alpha.1"
Describe the bug
Lately, our application transitioned from Vue 2 to Vue 3, prompting an upgrade in the Appbase version from ^1.16.0-alpha.31 to 3.1.0-alpha.1. For performing bulk updates, we send queries to our backend, which subsequently calls the Appbase API to modify user data. However, due to the upgraded Appbase version, we've noticed alterations in the queries generated by Appbase. Consequently, these changes are causing failures in our backend operations.
The query displayed on the left side pertains to the older version, whereas the one on the right side corresponds to the new version, as shown in the image below.
Is there a way to utilize or retrieve the old query within the new app version itself? Alternatively, what could be another straightforward solution to implement, considering our release is currently stalled due to this issue?
Screenshots
Desktop (please complete the following information):
- Browser [e.g. chrome]
@queryChange is sending us the query
<template>
<div class="tw-flex tw-flex-col tw-px-4">
<StudioPageIntro title="Registrants">
Register attendees for your event and control access for each user. Registrants will automatically be sent email
notifications once added, so confirm your email schedule before uploading registrants.
</StudioPageIntro>
<div v-if="show" class="tw-flex tw-w-full tw-flex-1 tw-flex-col tw-overflow-scroll">
<!--
This is a very frustrating component because of reactive-base. If you make any chnages,
you can start having problems with the components rendered by appbase, such as filters
not updating or the pagination changing back to page 1 randomly.
It seems reactive-base observes all its direct children and on any change that will
re-render the virtual dom of its direct descendants it will refresh. It will also
stop refreshing when it is supposed to refresh if its not a direct descendant.
A rule of thumb, if you want it to make the data update, make it a direct child. If you
want it to not make the reactive-base store refresh, put it as a descendant of a descendant
and then provide all the data it needs through the store instead of through props.
-->
<StudioSpinner v-if="loadingColumns" overlay />
<reactive-base v-else :app="eventId" :credentials="appbaseCredentials" :url="appBaseUrl">
<StudioSpinner v-show="loadingRegistration" overlay />
<div>
<div class="tw-flex tw-flex-row tw-py-3 tw-align-top">
<div class="tw-mt-1 tw-flex tw-flex-1 tw-flex-row tw-items-center tw-justify-start">
<StudioButton
variant="outline"
trackingId="registrants-refresh-button"
class="tw-ml-0.5 tw-mr-2"
@click="refreshList"
>
<template #icon>
<TablerRefresh />
</template>
</StudioButton>
<div v-if="summary" class="tw-mr-2">
{{ summary }}
</div>
</div>
<div class="tw-flex tw-flex-row tw-items-start tw-justify-end tw-pl-2 tw-pr-1">
<SearchBox
placeholder="Search Registrants..."
className="appbase-search"
queryFormat="and"
filterLabel="Search"
componentId="SearchUsers"
:dataField="['full_name']"
/>
<StudioAddRegistrant @onRegistrantAdd="searchRegistrants" />
</div>
</div>
<selected-filters :showClearAll="true">
<template #default="{ selectedValues, setValue, clearValues }">
<div class="tw-flex tw-flex-row tw-flex-wrap">
<Chip
v-for="componentId in Object.keys(getFilteredValues(selectedValues))"
:key="componentId"
class="tw-mr-2"
:borderRadius="16"
:label="`${filteredText(componentId)}: ${selectedFilterValue(componentId, selectedValues)}`"
allowClose
@closeChip="() => setValue(componentId, null)"
/>
<StudioButton
v-if="Object.keys(getFilteredValues(selectedValues)).length"
variant="text"
trackingId="registrants-clear-all-filters-button"
@click="clearValues"
>
Clear All Filters
</StudioButton>
</div>
</template>
</selected-filters>
<div class="content tw-relative tw-mb-8 tw-w-full">
<div class="tw-absolute tw-right-[168px] tw-top-[12px]">
<StudioRegistrantsColumnSelectionPopup v-if="$store.state.registration.lastSearchedQueryResultSize > 0" />
</div>
<reactive-list
componentId="SearchResults"
prevLabel="Previous"
:sortOptions="sortOptions"
nextLabel="Next"
:react="{ and: oredFilters }"
:pagination="true"
:defaultQuery="defaultQuery"
:size="25"
:showEndPage="true"
:showResultStats="false"
:innerClass="{
sortOptions: 'appbase-sort-options',
pagination: 'appbase-paginator'
}"
:renderNoResults="() => null"
@data="onResult"
@queryChange="onQueryChange"
>
<template #render="{ data }">
<div>
<div class="tw-flex tw-flex-1 tw-flex-row tw-justify-between tw-py-3">
<StudioRegistrantsActions
:react="{ and: oredFilters }"
:defaultQuery="defaultQuery"
@banfinished="handleBanFinished"
/>
</div>
<v-data-table
:headers="visibleColumns"
:items="data"
showSelect
:itemsPerPage="25"
fixedHeader
class="tw-overflow-hidden tw-border tw-border-slate-200"
>
<!--
Do not bind props to this component. Route them through the store.
If you bind props to this element other than items then everytime
this component changes the reactive-list component above switches
back to page 1. If you route the changes through the store it cannot
tell.
-->
<template #headers="{ columns }">
<!-- Do not use v-if here. It will break filters. -->
<StudioRegistrantsTableHeader v-show="data.length > 0" :headers="columns" />
</template>
<template #bottom></template>
<template #body></template>
<template #tbody="{ items }">
<div v-if="items.length === 0" class="tw-py-12 tw-text-center">
<h5
class="tw-text-md tw-font-medium tw-leading-tight tw-text-slate-400 dark:tw-text-slate-500 lg:tw-text-lg lg:tw-leading-tight"
>
No registrants yet!
</h5>
</div>
<StudioRegistrantsTableRow
:rows="items"
@singleItemSelectionHandler="singleItemSelectionHandler"
/>
</template>
</v-data-table>
</div>
</template>
</reactive-list>
</div>
</div>
</reactive-base>
</div>
</div>
</template>
<script>
import { mapState, mapActions, mapGetters, mapMutations } from 'vuex';
import StudioRegistrantsTableRow from './StudioRegistrantsTableRow.vue';
import StudioRegistrantsTableHeader from './StudioRegistrantsTableHeader.vue';
import StudioRegistrantsActions from './StudioRegistrantsActions.vue';
import StudioRegistrantsColumnSelectionPopup from './StudioRegistrantsColumnSelectionPopup.vue';
import StudioAddRegistrant from './StudioAddRegistrant.vue';
import { snakeCaseToCapitalized } from '@/store/modules/registration';
import logger from '@goldcast/logger';
import throttle from 'lodash.throttle';
import TablerRefresh from '@/studioComponents/Icons/tabler/TablerRefresh.vue';
import StudioButton from '@/studioComponents/StudioButton.vue';
import StudioPageIntro from '@/studioComponents/StudioPageIntro.vue';
import StudioSpinner from '@/studioComponents/StudioSpinner.vue';
import Chip from '@/commonComponents/Chip.vue';
import { VDataTable } from 'vuetify/labs/VDataTable';
export default {
name: 'StudioRegistrantsWrapper',
components: {
StudioRegistrantsTableHeader,
StudioRegistrantsTableRow,
StudioRegistrantsActions,
StudioRegistrantsColumnSelectionPopup,
StudioAddRegistrant,
Chip,
StudioButton,
StudioSpinner,
StudioPageIntro,
TablerRefresh,
VDataTable
},
computed: {
...mapState('registration', {
appBaseUrl: 'appBaseUrl',
loadingRegistration: 'loadingRegistration',
appbaseError: 'appbaseError',
columns: 'columns',
roleNames: 'roleNames',
lastSearchedQueryResultSize: 'lastSearchedQueryResultSize'
}),
...mapGetters('registration', ['visibleColumns']),
...mapGetters('studioEventList', {
event: 'getCurrentEvent'
}),
appbaseCredentials() {
return this.event?.appbase_credentials;
},
selectedFilterValue() {
return (componentId, selectedValues) => {
if (componentId === 'role') {
return selectedValues[componentId].value
.map(role => {
return this.roleNames[role];
})
.join(',');
}
const value = selectedValues[componentId].value;
if (Array.isArray(value)) {
return value.join(',');
}
return value;
};
},
oredFilters() {
const ored = this.columns
.map(it => it.value)
.filter(it => {
return !['user__magic_link', 'id', 'event_id', 'profile_picture_url'].includes(it);
});
return ored.concat('SearchUsers').concat('role');
},
eventId() {
return this.$route.params.eventId;
},
summary() {
if (this.loadingRegistration) {
return '';
}
if (this.lastSearchedQueryResultSize <= 0) {
return '';
}
if (this.lastSearchedQueryResultSize === 1) {
return '1 Registrant';
}
return `${this.lastSearchedQueryResultSize} Registrants`;
}
},
data() {
return {
loadingColumns: true,
currentPage: 1,
show: false,
sortOptions: [
{
label: 'Full Name ↑',
dataField: 'full_name.keyword',
sortBy: 'asc'
},
{
label: 'Full Name ↓',
dataField: 'full_name.keyword',
sortBy: 'desc'
},
{
label: 'Email ↑',
dataField: 'email.keyword',
sortBy: 'asc'
},
{
label: 'Email ↓',
dataField: 'email.keyword',
sortBy: 'desc'
},
{
label: 'Date Registered ↑',
dataField: 'date_registered.keyword',
sortBy: 'asc'
},
{
label: 'Date Registered ↓',
dataField: 'date_registered.keyword',
sortBy: 'desc'
}
]
};
},
mounted() {
this.show = true;
this.fetchColumns().then(() => {
this.loadingColumns = false;
});
this.fetchEventMembers({ eventId: this.eventId });
},
beforeRouteLeave(to, from, next) {
this.toggleSelectAll(false);
this.toggleColumnPopup(false);
this.setSelectedQuery(null);
next();
},
methods: {
...mapActions('registration', ['fetchColumns']),
...mapActions('studioEventList', ['fetchEventMembers']),
...mapMutations('registration', [
'toggleSelectAll',
'toggleColumnPopup',
'setSelectedQuery',
'setLoadingRegistration',
'storeAppbaseQueryDSL',
'toggleSelection'
]),
// This cannot be a computed property because it is inside the render
// function of appbase and hence cannot know when to recompute unless
// its passed as a method
handleBanFinished({ timeout }) {
this.toggleSelectAll(false);
this.searchRegistrants();
// The banned data doesn't reflect in appbase immediately so wait to refresh
setTimeout(() => {
this.refreshList();
}, timeout);
},
refreshList: throttle(function () {
this.show = false;
if (!this.columns?.length) {
this.fetchColumns();
}
setTimeout(() => {
this.show = true;
}, 100);
}, 2000),
filteredText(componentId) {
return this.snakeCaseToCapitalized(componentId === 'blocked' ? 'banned' : componentId);
},
onQueryChange(prev, next) {
logger.info('Query change: ', prev, next);
this.storeAppbaseQueryDSL({
next,
numResults: -1
});
},
onResult(payload) {
const numResults = payload.resultStats.numberOfResults;
logger.info('Number of results in appbase query: ' + numResults);
this.storeAppbaseQueryDSL({
numResults
});
},
searchRegistrants() {
if (this.currentPage == 1) {
this.fetchEventMembers({ eventId: this.event.id });
} else {
this.currentPage = 1;
}
},
snakeCaseToCapitalized,
getFilteredValues(values = {}) {
const filteredValues = {};
Object.keys(values).forEach(componentId => {
if (
values[componentId].showFilter &&
(Array.isArray(values[componentId].value) ? values[componentId].value.length : !!values[componentId].value)
) {
filteredValues[componentId] = values[componentId];
}
});
return filteredValues;
},
defaultQuery() {
return {
track_total_hits: true,
query: { match_all: {} }
};
},
singleItemSelectionHandler(row) {
this.toggleSelection(row);
}
}
};
</script>
@siddharthlatest @SavvyShah can you guys please help
- Langage dominant
- JavaScript
- Étoiles
- 4.9k
- Forks
- 479
- Merge moyen
- 4 h 43 min
- PR mergées (30 j)
- 3
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de appbaseio/reactivesearch
-
ci: add Node.js version matrix, caching, and lint step to test workflowPeut-être pris @Talha12Shiekh l’a pris il y a 82 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
appbaseio/reactivesearch#2322 ·
Les mainteneurs répondent en général sous 1 jour
-
chore: add Dependabot config for automated dependency updatesPeut-être pris @Talha12Shiekh l’a pris il y a 82 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
appbaseio/reactivesearch#2321 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
security: user-controlled URL params injected directly into Redux store via JSON.parsePeut-être pris @Talha12Shiekh l’a pris il y a 82 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
appbaseio/reactivesearch#2319 ·
Les mainteneurs répondent en général sous 1 jour
-
refactor: consolidate 12 near-identical SVG icon components into one patternPeut-être pris @Talha12Shiekh l’a pris il y a 84 jours. Ouverte
Difficulté 4/5 3-5 jours Accessibilité débutants 48/100
appbaseio/reactivesearch#2324 ·
Les mainteneurs répondent en général sous 1 jour
-
refactor: SearchBox.js is 2692 lines — extract subcomponents for maintainabilityPeut-être pris @Talha12Shiekh l’a pris il y a 82 jours. Ouverte
Difficulté 4/5 3-5 jours Accessibilité débutants 55/100
appbaseio/reactivesearch#2323 ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de appbaseio/reactivesearch
Issues similaires
-
enhancement
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
ericcornelissen/depreman#591 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 1/5 Moins d'une heure Accessibilité débutants 88/100
NanmiCoder/dsh-agent-teams#269 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 1/5 Moins d'une heure Accessibilité débutants 65/100
Les mainteneurs répondent en général sous 1 jour
-
전문가 노하우 케이스 형식에 재검토 시점을 필수로 둔다Ouvertedocs
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
idean3885/claude-ops-agent#765 ·
Les mainteneurs répondent en général sous 1 jour
-
docs html v6
Difficulté 1/5 Moins d'une heure Accessibilité débutants 78/100
Les mainteneurs répondent en général sous 1 jour