blob: 2f0101b770a944dbf1a9b116fa6c5b1f4d793acb [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * @fileoverview Permissions actions, selectors, and reducers organized into
7 * a single Redux "Duck" that manages updating and retrieving permissions state
8 * on the frontend.
9 *
10 * The Permissions data is stored in a normalized format.
11 * `permissions` stores all PermissionSets[] indexed by resource name.
12 *
13 * Reference: https://github.com/erikras/ducks-modular-redux
14 */
15
16import {combineReducers} from 'redux';
17import {createReducer, createRequestReducer} from './redux-helpers.js';
18
19import {prpcClient} from 'prpc-client-instance.js';
20
21import 'shared/typedef.js';
22
23/** @typedef {import('redux').AnyAction} AnyAction */
24
25// Permissions
26
27// Field Permissions
28export const FIELD_DEF_EDIT = 'FIELD_DEF_EDIT';
29export const FIELD_DEF_VALUE_EDIT = 'FIELD_DEF_VALUE_EDIT';
30
31// Actions
32export const BATCH_GET_START = 'permissions/BATCH_GET_START';
33export const BATCH_GET_SUCCESS = 'permissions/BATCH_GET_SUCCESS';
34export const BATCH_GET_FAILURE = 'permissions/BATCH_GET_FAILURE';
35
36/* State Shape
37{
38 byName: Object<string, PermissionSet>,
39
40 requests: {
41 batchGet: ReduxRequestState,
42 },
43}
44*/
45
46// Reducers
47
48/**
49 * All PermissionSets indexed by resource name.
50 * @param {Object<string, PermissionSet>} state The existing items.
51 * @param {AnyAction} action
52 * @param {Array<PermissionSet>} action.permissionSets
53 * @return {Object<string, PermissionSet>}
54 */
55export const byNameReducer = createReducer({}, {
56 [BATCH_GET_SUCCESS]: (state, {permissionSets}) => {
57 const newState = {...state};
58 for (const permissionSet of permissionSets) {
59 newState[permissionSet.resource] = permissionSet;
60 }
61 return newState;
62 },
63});
64
65const requestsReducer = combineReducers({
66 batchGet: createRequestReducer(
67 BATCH_GET_START, BATCH_GET_SUCCESS, BATCH_GET_FAILURE),
68});
69
70export const reducer = combineReducers({
71 byName: byNameReducer,
72
73 requests: requestsReducer,
74});
75
76// Selectors
77
78/**
79 * Returns all the PermissionSets in the store as a mapping.
80 * @param {any} state
81 * @return {Object<string, PermissionSet>}
82 */
83export const byName = (state) => state.permissions.byName;
84
85/**
86 * Returns the Permissions requests.
87 * @param {any} state
88 * @return {Object<string, ReduxRequestState>}
89 */
90export const requests = (state) => state.permissions.requests;
91
92// Action Creators
93
94/**
95 * Action creator to fetch PermissionSets.
96 * @param {Array<string>} names The resource names to get.
97 * @return {function(function): Promise<Array<PermissionSet>>}
98 */
99export const batchGet = (names) => async (dispatch) => {
100 dispatch({type: BATCH_GET_START});
101
102 try {
103 /** @type {{permissionSets: Array<PermissionSet>}} */
104 const {permissionSets} = await prpcClient.call(
105 'monorail.v3.Permissions', 'BatchGetPermissionSets', {names});
106
107 for (const permissionSet of permissionSets) {
108 if (!permissionSet.permissions) {
109 permissionSet.permissions = [];
110 }
111 }
112 dispatch({type: BATCH_GET_SUCCESS, permissionSets});
113
114 return permissionSets;
115 } catch (error) {
116 dispatch({type: BATCH_GET_FAILURE, error});
117 };
118};