diff --git a/pkg/webui/console/store/actions/user-preferences.js b/pkg/webui/console/store/actions/user-preferences.js new file mode 100644 index 0000000000..ef172fa152 --- /dev/null +++ b/pkg/webui/console/store/actions/user-preferences.js @@ -0,0 +1,41 @@ +// 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import createRequestActions from '@ttn-lw/lib/store/actions/create-request-actions' +import { + createPaginationBaseActionType, + createPaginationByIdRequestActions, +} from '@ttn-lw/lib/store/actions/pagination' + +export const GET_BOOKMARKS_LIST_BASE = createPaginationBaseActionType('BOOKMARKS') +export const [ + { + request: GET_BOOKMARKS_LIST, + success: GET_BOOKMARKS_LIST_SUCCESS, + failure: GET_BOOKMARKS_LIST_FAILURE, + }, + { request: getBookmarksList, success: getBookmarksListSuccess, failure: getBookmarksListFailure }, +] = createPaginationByIdRequestActions('BOOKMARKS') + +export const ADD_BOOKMARK_BASE = 'ADD_BOOKMARK' +export const [ + { request: ADD_BOOKMARK, success: ADD_BOOKMARK_SUCCESS, failure: ADD_BOOKMARK_FAILURE }, + { request: addBookmark, success: addBookmarkSuccess, failure: addBookmarkFailure }, +] = createRequestActions(ADD_BOOKMARK_BASE, (userId, entity) => ({ userId, entity })) + +export const DELETE_BOOKMARK_BASE = 'DELETE_BOOKMARK' +export const [ + { request: DELETE_BOOKMARK, success: DELETE_BOOKMARK_SUCCESS, failure: DELETE_BOOKMARK_FAILURE }, + { request: deleteBookmark, success: deleteBookmarkSuccess, failure: deleteBookmarkFailure }, +] = createRequestActions(DELETE_BOOKMARK_BASE, (userId, entity) => ({ userId, entity })) diff --git a/pkg/webui/console/store/middleware/logics/index.js b/pkg/webui/console/store/middleware/logics/index.js index 1dc26adeb1..8a0e5d27b8 100644 --- a/pkg/webui/console/store/middleware/logics/index.js +++ b/pkg/webui/console/store/middleware/logics/index.js @@ -37,6 +37,7 @@ import networkServer from './network-server' import qrCodeGenerator from './qr-code-generator' import searchAccounts from './search-accounts' import notifications from './notifications' +import userPreferences from './user-preferences' export default [ ...status, @@ -63,4 +64,5 @@ export default [ ...qrCodeGenerator, ...searchAccounts, ...notifications, + ...userPreferences, ] diff --git a/pkg/webui/console/store/middleware/logics/init.js b/pkg/webui/console/store/middleware/logics/init.js index d64916a0b9..6d0f6608cc 100644 --- a/pkg/webui/console/store/middleware/logics/init.js +++ b/pkg/webui/console/store/middleware/logics/init.js @@ -66,6 +66,7 @@ const consoleAppLogic = createRequestLogic({ 'name', 'primary_email_address_validated_at', 'profile_picture', + 'console_preferences', ]) userResult.isAdmin = info.is_admin || false dispatch(user.getUserMeSuccess(userResult)) diff --git a/pkg/webui/console/store/middleware/logics/user-preferences.js b/pkg/webui/console/store/middleware/logics/user-preferences.js new file mode 100644 index 0000000000..6c6ef01255 --- /dev/null +++ b/pkg/webui/console/store/middleware/logics/user-preferences.js @@ -0,0 +1,56 @@ +// 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import tts from '@console/api/tts' + +import createRequestLogic from '@ttn-lw/lib/store/logics/create-request-logic' + +import * as userPreferences from '@console/store/actions/user-preferences' + +const getBookmarksListLogic = createRequestLogic({ + type: userPreferences.GET_BOOKMARKS_LIST, + process: async ({ action }) => { + const { + id: userId, + params: { page, limit, order, deleted }, + } = action.payload + const data = await tts.Users.getBookmarks(userId, { page, limit, order, deleted }) + + return { entities: data.bookmarks, totalCount: data.totalCount } + }, +}) + +const addBookmarkLogic = createRequestLogic({ + type: userPreferences.ADD_BOOKMARK, + process: async ({ action }) => { + const { + payload: { userId, entity }, + } = action + + return await tts.Users.addBookmark(userId, entity) + }, +}) + +const deleteBookmarkLogic = createRequestLogic({ + type: userPreferences.DELETE_BOOKMARK, + process: async ({ action }) => { + const { + payload: { userId, entity }, + } = action + + return await tts.Users.deleteBookmark(userId, entity) + }, +}) + +export default [getBookmarksListLogic, addBookmarkLogic, deleteBookmarkLogic] diff --git a/pkg/webui/console/store/reducers/index.js b/pkg/webui/console/store/reducers/index.js index ff7187ff6a..52a529420b 100644 --- a/pkg/webui/console/store/reducers/index.js +++ b/pkg/webui/console/store/reducers/index.js @@ -64,6 +64,7 @@ import deviceRepository from './device-repository' import packetBroker from './packet-broker' import ns from './network-server' import notifications from './notifications' +import userPreferences from './user-preferences' export default combineReducers({ user, @@ -123,4 +124,5 @@ export default combineReducers({ ns, searchAccounts, notifications, + userPreferences, }) diff --git a/pkg/webui/console/store/reducers/user-preferences.js b/pkg/webui/console/store/reducers/user-preferences.js new file mode 100644 index 0000000000..4ca500aa8d --- /dev/null +++ b/pkg/webui/console/store/reducers/user-preferences.js @@ -0,0 +1,50 @@ +// 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { GET_BOOKMARKS_LIST_SUCCESS } from '@console/store/actions/user-preferences' +import { GET_USER_ME_SUCCESS } from '@console/store/actions/logout' + +const initialState = { + bookmarks: { + bookmarks: [], + totalCount: 0, + }, + consolePreferences: {}, +} + +const userPreferences = (state = initialState, { type, payload }) => { + switch (type) { + case GET_BOOKMARKS_LIST_SUCCESS: + return { + ...state, + bookmarks: { + ...state.bookmarks, + bookmarks: payload.entities, + totalCount: payload.totalCount, + }, + } + case GET_USER_ME_SUCCESS: + return { + ...state, + consolePreferences: { + ...state.consolePreferences, + ...payload.console_preferences, + }, + } + default: + return state + } +} + +export default userPreferences diff --git a/pkg/webui/console/store/selectors/user-preferences.js b/pkg/webui/console/store/selectors/user-preferences.js new file mode 100644 index 0000000000..008cf112da --- /dev/null +++ b/pkg/webui/console/store/selectors/user-preferences.js @@ -0,0 +1,23 @@ +// 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const selectUserPreferencesStore = state => state.userPreferences + +export const selectConsolePreferences = state => + selectUserPreferencesStore(state).consolePreferences + +export const selectBookmarksList = state => selectUserPreferencesStore(state).bookmarks.bookmarks + +export const selectBookmarksTotalCount = state => + selectUserPreferencesStore(state).bookmarks.totalCount diff --git a/sdk/js/src/service/users.js b/sdk/js/src/service/users.js index 1b6d67c848..26e605965e 100644 --- a/sdk/js/src/service/users.js +++ b/sdk/js/src/service/users.js @@ -202,6 +202,45 @@ class Users { return Marshaler.unwrapInvitation(response) } + + // Preferences - Bookmarks. + async getBookmarks(userId, params) { + const response = await this._api.UserBookmarkRegistry.List( + { + routeParams: { 'user_ids.user_id': userId }, + }, + { + ...params, + }, + ) + + return Marshaler.unwrapBookmarks(response) + } + + async addBookmark(userId, entity) { + const response = await this._api.UserBookmarkRegistry.Create(undefined, { + user_ids: { user_id: userId }, + entity_ids: entity, + }) + + return Marshaler.unwrapBookmark(response) + } + + async deleteBookmark(userId, entity) { + const entityIdRoute = `entity_ids.${entity.name}_ids.${entity.name}_id` + const routeParams = { + 'user_ids.user_id': userId, + [entityIdRoute]: entity.id, + } + if (entity === 'device') { + routeParams['entity_ids.device_ids.application_ids.application_id'] = entity.applicationId + } + const response = await this._api.UserBookmarkRegistry.Delete({ + routeParams, + }) + + return Marshaler.unwrapBookmark(response) + } } export default Users diff --git a/sdk/js/src/util/marshaler.js b/sdk/js/src/util/marshaler.js index 4a8b189ecf..84b75a121d 100644 --- a/sdk/js/src/util/marshaler.js +++ b/sdk/js/src/util/marshaler.js @@ -130,6 +130,14 @@ class Marshaler { return this.payloadSingleResponse(result) } + static unwrapBookmarks(result) { + return this.payloadListResponse('bookmarks', result) + } + + static unwrapBookmark(result) { + return this.payloadSingleResponse(result) + } + static fieldMaskFromPatch(patch, whitelist, remaps = []) { const paths = []