Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix interference of entity prefetching data with store state #7207

Merged
merged 1 commit into from
Aug 1, 2024
Merged
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
16 changes: 16 additions & 0 deletions pkg/webui/console/store/actions/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,22 @@ export const [
},
] = createPaginationRequestActions(SHARED_NAME)

export const FETCH_APPS_LIST_BASE = 'FETCH_APPS_LIST'
export const [
{ request: FETCH_APPS_LIST, success: FETCH_APPS_LIST_SUCCESS, failure: FETCH_APPS_LIST_FAILURE },
{
request: fetchApplicationsList,
success: fetchApplicationsListSuccess,
failure: fetchApplicationsListFailure,
},
] = createRequestActions(
FETCH_APPS_LIST_BASE,
({ page, limit, query, order, deleted } = {}) => ({
params: { page, limit, query, order, deleted },
}),
(_, selectors = [], options = {}) => ({ selectors, options }),
)

export const GET_APPS_RIGHTS_LIST_BASE = createGetRightsListActionType(SHARED_NAME)
export const [
{
Expand Down
17 changes: 17 additions & 0 deletions pkg/webui/console/store/actions/devices.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,23 @@ export const [
{ request: getDevicesList, success: getDevicesListSuccess, failure: getDevicesListFailure },
] = createPaginationByIdRequestActions(SHARED_NAME)

export const FETCH_DEVICES_LIST_BASE = 'FETCH_END_DEVICE_LIST'
export const [
{
request: FETCH_DEVICES_LIST,
success: FETCH_DEVICES_LIST_SUCCESS,
failure: FETCH_DEVICES_LIST_FAILURE,
},
{ request: fetchDevicesList, success: fetchDevicesListSuccess, failure: fetchDevicesListFailure },
] = createRequestActions(
FETCH_DEVICES_LIST_BASE,
(id, { page, limit, query, order } = {}) => ({
id,
params: { page, limit, query, order },
}),
(id, params, selectors = [], options = {}) => ({ selectors, options }),
)

export const RESET_DEV_BASE = 'RESET_END_DEVICE'
export const [
{ request: RESET_DEV, success: RESET_DEV_SUCCESS, failure: RESET_DEV_FAILURE },
Expand Down
16 changes: 16 additions & 0 deletions pkg/webui/console/store/actions/gateways.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,22 @@ export const [
{ request: getGatewaysList, success: getGatewaysListSuccess, failure: getGatewaysListFailure },
] = createPaginationRequestActions(SHARED_NAME)

export const FETCH_GTWS_LIST_BASE = 'FETCH_GTWS_LIST'
export const [
{ request: FETCH_GTWS_LIST, success: FETCH_GTWS_LIST_SUCCESS, failure: FETCH_GTWS_LIST_FAILURE },
{
request: fetchGatewaysList,
success: fetchGatewaysListSuccess,
failure: fetchGatewaysListFailure,
},
] = createRequestActions(
FETCH_GTWS_LIST_BASE,
({ page, limit, query, order, deleted } = {}) => ({
params: { page, limit, query, order, deleted },
}),
(_, selectors = [], options = {}) => ({ selectors, options }),
)

export const GET_GTWS_RIGHTS_LIST_BASE = createGetRightsListActionType(SHARED_NAME)
export const [
{
Expand Down
3 changes: 1 addition & 2 deletions pkg/webui/console/store/middleware/logics/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@ const restoreApplicationLogic = createRequestLogic({
})

const getApplicationsLogic = createRequestLogic({
type: applications.GET_APPS_LIST,
latest: true,
type: [applications.GET_APPS_LIST, applications.FETCH_APPS_LIST],
process: async ({ action }, dispatch) => {
const {
params: { page, limit, query, order, deleted },
Expand Down
2 changes: 1 addition & 1 deletion pkg/webui/console/store/middleware/logics/devices.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ const deleteDeviceLogic = createRequestLogic({
})

const getDevicesListLogic = createRequestLogic({
type: devices.GET_DEVICES_LIST,
type: [devices.GET_DEVICES_LIST, devices.FETCH_DEVICES_LIST],
process: async ({ action }) => {
const {
id: appId,
Expand Down
3 changes: 1 addition & 2 deletions pkg/webui/console/store/middleware/logics/gateways.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ const restoreGatewayLogic = createRequestLogic({
})

const getGatewaysLogic = createRequestLogic({
type: gateways.GET_GTWS_LIST,
latest: true,
type: [gateways.GET_GTWS_LIST, gateways.FETCH_GTWS_LIST],
process: async ({ action }) => {
const {
params: { page, limit, query, order, deleted },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ const getOrganizationLogic = createRequestLogic({

const getOrganizationsLogic = createRequestLogic({
type: organizations.GET_ORGS_LIST,
latest: true,
process: async ({ action }, dispatch) => {
const {
params: { page, limit, order, query, deleted },
Expand Down
12 changes: 6 additions & 6 deletions pkg/webui/console/store/middleware/logics/top-entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ import { getTypeAndId } from '@console/lib/recency-frequency-entities'

import { GET_TOP_ENTITIES } from '@console/store/actions/top-entities'
import { getBookmarksList } from '@console/store/actions/user-preferences'
import { getApplication, getApplicationsList } from '@console/store/actions/applications'
import { getGateway, getGatewaysList } from '@console/store/actions/gateways'
import { getDevice, getDevicesList } from '@console/store/actions/devices'
import { fetchApplicationsList, getApplication } from '@console/store/actions/applications'
import { fetchGatewaysList, getGateway } from '@console/store/actions/gateways'
import { fetchDevicesList, getDevice } from '@console/store/actions/devices'

import { selectUserId } from '@account/store/selectors/user'
import {
Expand Down Expand Up @@ -134,11 +134,11 @@ const fetchTopEntities = async (getState, dispatch) => {
try {
await Promise.all([
dispatch(
attachPromise(getApplicationsList({ page: 1, limit: prefetchLimit, order }, ['name'])),
attachPromise(fetchApplicationsList({ page: 1, limit: prefetchLimit, order }, ['name'])),
),
dispatch(
attachPromise(
getGatewaysList(
fetchGatewaysList(
{ page: 1, limit: prefetchLimit, order },
['name', 'gateway_server_address'],
{
Expand Down Expand Up @@ -173,7 +173,7 @@ const fetchTopEntities = async (getState, dispatch) => {
try {
return await dispatch(
attachPromise(
getDevicesList(entityId, { page: 1, limit: 1000, order }, ['name', 'last_seen_at']),
fetchDevicesList(entityId, { page: 1, limit: 1000, order }, ['name', 'last_seen_at']),
),
)
} catch (error) {
Expand Down
2 changes: 2 additions & 0 deletions pkg/webui/console/store/reducers/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
DELETE_APP_SUCCESS,
GET_APP_EVENT_MESSAGE_SUCCESS,
GET_MQTT_INFO_SUCCESS,
FETCH_APPS_LIST_SUCCESS,
} from '@console/store/actions/applications'

const application = (state = {}, application) => ({
Expand All @@ -52,6 +53,7 @@ const applications = (state = defaultState, { type, payload, event, meta }) => {
selectedApplication: payload.id,
}
case GET_APPS_LIST_SUCCESS:
case FETCH_APPS_LIST_SUCCESS:
const entities = payload.entities.reduce(
(acc, app) => {
const id = getApplicationId(app)
Expand Down
2 changes: 2 additions & 0 deletions pkg/webui/console/store/reducers/devices.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
RESET_DEV_SUCCESS,
GET_DEVICE_EVENT_MESSAGE_SUCCESS,
DELETE_DEV_SUCCESS,
FETCH_DEVICES_LIST_SUCCESS,
} from '@console/store/actions/devices'
import { GET_APP_EVENT_MESSAGE_SUCCESS } from '@console/store/actions/applications'

Expand Down Expand Up @@ -156,6 +157,7 @@ const devices = (state = defaultState, { type, payload, event, meta }) => {
}

return mergeDerived(state, combinedId, defaultDerived)
case FETCH_DEVICES_LIST_SUCCESS:
case GET_DEVICES_LIST_SUCCESS:
const newEntities = payload.entities.reduce(
(acc, dev) => {
Expand Down
2 changes: 2 additions & 0 deletions pkg/webui/console/store/reducers/gateways.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
UPDATE_GTW_STATS_FAILURE,
START_GTW_STATS_SUCCESS,
START_GTW_STATS_FAILURE,
FETCH_GTWS_LIST_SUCCESS,
} from '@console/store/actions/gateways'

const defaultStatisticsState = {
Expand Down Expand Up @@ -123,6 +124,7 @@ const gateways = (state = defaultState, action) => {
selectedGateway: null,
entities: rest,
}
case FETCH_GTWS_LIST_SUCCESS:
case GET_GTWS_LIST_SUCCESS:
const entities = payload.entities.reduce(
(acc, gtw) => {
Expand Down
7 changes: 5 additions & 2 deletions pkg/webui/lib/store/actions/attach-promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,11 @@ export default actionOrActionCreator => {
* Helper function to retrieve the result action types based
* on the request action type.
*
* @param {string} typeString - The request action type.
* @param {string|Array<string>} type - The request action type.
* @param {string} status - The result type, either `SUCCESS`, `FAILURE` or `ABORT`.
* @returns {string} - The result action type.
*/
export const getResultActionFromType = (typeString, status) => typeString.replace('REQUEST', status)
export const getResultActionFromType = (type, status) =>
type instanceof Array
? type.map(t => t.replace('REQUEST', status))
: type.replace('REQUEST', status)
58 changes: 23 additions & 35 deletions pkg/webui/lib/store/logics/create-request-logic.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2019 The Things Network Foundation, The Things Industries B.V.
// Copyright © 2024 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -48,58 +48,46 @@ let lastError
* @param {object} options - The logic options (to be passed to `createLogic()`).
* @param {boolean} options.noCancelOnRouteChange - Flag to disable the decoration
* of the `cancelType` option.
* @param {(string|Function)} successType - The success action type or action creator.
* @param {(string|Function)} failType - The fail action type or action creator.
* @param {(string|Function)} abortType - The abort action type or action creator.
* @param {string} abortType - The type of the abort action.
* @returns {object} The `redux-logic` (decorated) logic.
*/
const createRequestLogic = (
{ noCancelOnRouteChange, ...options },
successType = getResultActionFromType(options.type, 'SUCCESS'),
failType = getResultActionFromType(options.type, 'FAILURE'),
abortType = getResultActionFromType(options.type, 'ABORT'),
) => {
if (!successType || !failType) {
if (
options.type === undefined ||
(options.type instanceof Array && options.type.length === 0) ||
(options.type instanceof Array &&
options.type.some(type => typeof type !== 'string' || type.indexOf('_REQUEST') === -1))
) {
throw new Error('Could not derive result actions from provided options')
}

let successAction = successType
let failAction = failType
let abortAction = abortType

if (typeof successType === 'string') {
successAction = payload => ({ type: successType, payload })
}
if (typeof failType === 'string') {
failAction = (error, originalAction) => ({
type: failType,
error: true,
payload: error,
meta: { requestPayload: originalAction.payload },
})
}
if (typeof abortType === 'string') {
abortAction = () => ({ type: abortType })
}

return createLogic({
...options,
cancelType: abortType,
process: async (deps, dispatch, done) => {
const { action, getState, cancelled$, action$ } = deps
const { action, getState, cancelled$ } = deps
const promiseAttached = action.meta && action.meta._attachPromise
const promisifiedDispatch = promisifyDispatch(dispatch)
let actionSubscription

// Compose response actions.
const successAction = payload => ({
type: getResultActionFromType(action.type, 'SUCCESS'),
payload,
})
const failAction = (error, originalAction) => ({
type: getResultActionFromType(action.type, 'FAILURE'),
error: true,
payload: error,
meta: { requestPayload: originalAction.payload },
})
const abortAction = () => ({ type: getResultActionFromType(action.type, 'ABORT') })

if (!noCancelOnRouteChange) {
// Subscribe to action observable to dispatch an abort action on route changes.
actionSubscription = action$.subscribe({
next: action => {
if (action.type === '@@router/LOCATION_CHANGE') {
dispatch(abortAction())
}
},
})
// TODO: Reintroduce the route change detection after removing the `connected-react-router`.
}

let success = false
Expand Down
Loading