| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview Module of functions which produce a new page state in response |
| * to an action. Reducers (in the same sense as Array.prototype.reduce) must be |
| * pure functions: they must not modify existing state objects, or make any API |
| * calls. |
| */ |
| |
| import type {App} from 'chrome://resources/cr_components/app_management/app_management.mojom-webui.js'; |
| import {assertNotReached} from 'chrome://resources/js/assert.js'; |
| |
| import type {AddAppAction, AppManagementActions, ChangeAppAction, RemoveAppAction} from './actions.js'; |
| import type {AppManagementPageState, AppMap} from './store.js'; |
| |
| function addApp(apps: AppMap, action: AddAppAction): AppMap { |
| if (apps[action.app.id]) { |
| const stringifyApp = (app: App): string => { |
| return `id: ${app.id}, type: ${app.type}, install source: ${ |
| app.installReason} title: ${app.title}`; |
| }; |
| const errorMessage = `Attempted to add an app that already exists. |
| New app: ${stringifyApp(action.app)}. |
| Old app: ${stringifyApp(apps[action.app.id])}.`; |
| assertNotReached(errorMessage); |
| } |
| return {...apps, [action.app.id]: action.app}; |
| } |
| |
| function changeApp(apps: AppMap, action: ChangeAppAction): AppMap { |
| // If the app doesn't exist, that means that the app that has been changed |
| // does not need to be shown in App Management. |
| if (!apps[action.app.id]) { |
| return apps; |
| } |
| return {...apps, [action.app.id]: action.app}; |
| } |
| |
| function removeApp(apps: AppMap, action: RemoveAppAction): AppMap { |
| if (!apps.hasOwnProperty(action.id)) { |
| return apps; |
| } |
| |
| delete apps[action.id]; |
| return {...apps}; |
| } |
| |
| export function updateApps(apps: AppMap, action: AppManagementActions): AppMap { |
| switch (action.name) { |
| case 'add-app': |
| return addApp(apps, action as AddAppAction); |
| case 'change-app': |
| return changeApp(apps, action as ChangeAppAction); |
| case 'remove-app': |
| return removeApp(apps, action as RemoveAppAction); |
| default: |
| return apps; |
| } |
| } |
| |
| function updateSelectedAppId( |
| selectedAppId: string|null, action: AppManagementActions): string|null { |
| switch (action.name) { |
| case 'update-selected-app-id': |
| return action.value; |
| case 'remove-app': |
| if (selectedAppId === action.id) { |
| return null; |
| } |
| return selectedAppId; |
| default: |
| return selectedAppId; |
| } |
| } |
| |
| function updateSubAppToParentAppId( |
| subAppToParentAppId: Record<string, string>, |
| action: AppManagementActions): Record<string, string> { |
| switch (action.name) { |
| case 'update-sub-app-to-parent-app-id': |
| if (action.parent) { |
| return {...subAppToParentAppId, [action.subApp]: action.parent}; |
| } |
| delete subAppToParentAppId[action.subApp]; |
| return {...subAppToParentAppId}; |
| default: |
| return subAppToParentAppId; |
| } |
| } |
| |
| /** |
| * Root reducer for the App Management page. This is called by the store in |
| * response to an action, and the return value is used to update the UI. |
| */ |
| export function reduceAction( |
| state: AppManagementPageState, |
| action: AppManagementActions): AppManagementPageState { |
| return { |
| apps: updateApps(state.apps, action), |
| selectedAppId: updateSelectedAppId(state.selectedAppId, action), |
| subAppToParentAppId: |
| updateSubAppToParentAppId(state.subAppToParentAppId, action), |
| }; |
| } |