Skip to content

Commit 7260816

Browse files
mtrezzadavimacedo
authored andcommitted
Add masterkey parameters (#1233)
* add master key only UI * added saving, retrieving * fixed style and wording * Improved parameter explanation Co-Authored-By: Tom Fox <[email protected]> * added show new field only for parse server >= 3.8.0
1 parent 1e2b167 commit 7260816

File tree

3 files changed

+61
-20
lines changed

3 files changed

+61
-20
lines changed

src/dashboard/Data/Config/Config.react.js

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class Config extends TableView {
3030
modalOpen: false,
3131
modalParam: '',
3232
modalType: 'String',
33-
modalValue: ''
33+
modalValue: '',
34+
modalMasterKeyOnly: false
3435
};
3536
}
3637

@@ -58,13 +59,16 @@ class Config extends TableView {
5859
if (!this.state.modalOpen) {
5960
return null;
6061
}
62+
const { currentApp = {} } = this.context;
6163
return (
6264
<ConfigDialog
6365
onConfirm={this.saveParam.bind(this)}
6466
onCancel={() => this.setState({ modalOpen: false })}
6567
param={this.state.modalParam}
6668
type={this.state.modalType}
67-
value={this.state.modalValue} />
69+
value={this.state.modalValue}
70+
masterKeyOnly={this.state.modalMasterKeyOnly}
71+
parseServerVersion={currentApp.serverInfo && currentApp.serverInfo.parseServerVersion} />
6872
);
6973
}
7074

@@ -103,9 +107,11 @@ class Config extends TableView {
103107
modalOpen: true,
104108
modalParam: data.param,
105109
modalType: type,
106-
modalValue: modalValue
110+
modalValue: modalValue,
111+
modalMasterKeyOnly: data.masterKeyOnly
107112
});
108-
let columnStyle = { width: '30%', cursor: 'pointer' };
113+
let columnStyleLarge = { width: '30%', cursor: 'pointer' };
114+
let columnStyleSmall = { width: '15%', cursor: 'pointer' };
109115

110116
let openModalValueColumn = () => {
111117
if (data.value instanceof Parse.File) {
@@ -116,9 +122,10 @@ class Config extends TableView {
116122

117123
return (
118124
<tr key={data.param}>
119-
<td style={columnStyle} onClick={openModal}>{data.param}</td>
120-
<td style={columnStyle} onClick={openModal}>{type}</td>
121-
<td style={columnStyle} onClick={openModalValueColumn}>{value}</td>
125+
<td style={columnStyleLarge} onClick={openModal}>{data.param}</td>
126+
<td style={columnStyleSmall} onClick={openModal}>{type}</td>
127+
<td style={columnStyleLarge} onClick={openModalValueColumn}>{value}</td>
128+
<td style={columnStyleSmall} onClick={openModal}>{data.masterKeyOnly.toString()}</td>
122129
<td style={{ textAlign: 'center' }}>
123130
<a onClick={this.deleteParam.bind(this, data.param)}>
124131
<Icon width={16} height={16} name='trash-solid' fill='#ff395e' />
@@ -131,8 +138,9 @@ class Config extends TableView {
131138
renderHeaders() {
132139
return [
133140
<TableHeader key='parameter' width={30}>Parameter</TableHeader>,
134-
<TableHeader key='type' width={30}>Type</TableHeader>,
135-
<TableHeader key='value' width={30}>Value</TableHeader>
141+
<TableHeader key='type' width={15}>Type</TableHeader>,
142+
<TableHeader key='value' width={30}>Value</TableHeader>,
143+
<TableHeader key='masterKeyOnly' width={15}>Master key only</TableHeader>
136144
];
137145
}
138146

@@ -151,20 +159,20 @@ class Config extends TableView {
151159
let data = undefined;
152160
if (this.props.config.data) {
153161
let params = this.props.config.data.get('params');
162+
let masterKeyOnlyParams = this.props.config.data.get('masterKeyOnly') || {};
154163
if (params) {
155164
data = [];
156165
params.forEach((value, param) => {
166+
let masterKeyOnly = masterKeyOnlyParams.get(param) || false;
157167
let type = typeof value;
158168
if (type === 'object' && value.__type == 'File') {
159169
value = Parse.File.fromJSON(value);
160170
}
161171
else if (type === 'object' && value.__type == 'GeoPoint') {
162172
value = new Parse.GeoPoint(value);
163173
}
164-
165-
data.push({ param: param, value: value })
174+
data.push({ param: param, value: value, masterKeyOnly: masterKeyOnly })
166175
});
167-
168176
data.sort((object1, object2) => {
169177
return object1.param.localeCompare(object2.param);
170178
});
@@ -173,10 +181,10 @@ class Config extends TableView {
173181
return data;
174182
}
175183

176-
saveParam({ name, value }) {
184+
saveParam({ name, value, masterKeyOnly }) {
177185
this.props.config.dispatch(
178186
ActionTypes.SET,
179-
{ param: name, value: value }
187+
{ param: name, value: value, masterKeyOnly: masterKeyOnly }
180188
).then(() => {
181189
this.setState({ modalOpen: false });
182190
}, () => {
@@ -196,7 +204,8 @@ class Config extends TableView {
196204
modalOpen: true,
197205
modalParam: '',
198206
modalType: 'String',
199-
modalValue: ''
207+
modalValue: '',
208+
modalMasterKeyOnly: false
200209
});
201210
}
202211
}

src/dashboard/Data/Config/ConfigDialog.react.js

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import React from 'react';
1818
import TextInput from 'components/TextInput/TextInput.react';
1919
import Toggle from 'components/Toggle/Toggle.react';
2020
import validateNumeric from 'lib/validateNumeric';
21+
import styles from 'dashboard/Data/Browser/Browser.scss';
22+
import semver from 'semver';
2123

2224
const PARAM_TYPES = [
2325
'Boolean',
@@ -108,13 +110,15 @@ export default class ConfigDialog extends React.Component {
108110
this.state = {
109111
value: null,
110112
type: 'String',
111-
name: ''
113+
name: '',
114+
masterKeyOnly: false
112115
};
113116
if (props.param.length > 0) {
114117
this.state = {
115118
name: props.param,
116119
type: props.type,
117120
value: props.value,
121+
masterKeyOnly: props.masterKeyOnly
118122
};
119123
}
120124
}
@@ -176,6 +180,7 @@ export default class ConfigDialog extends React.Component {
176180
this.props.onConfirm({
177181
name: this.state.name,
178182
value: GET_VALUE[this.state.type](this.state.value),
183+
masterKeyOnly: this.state.masterKeyOnly
179184
});
180185
}
181186

@@ -228,6 +233,30 @@ export default class ConfigDialog extends React.Component {
228233
description='Use this to configure your app. You can change it at any time.' />
229234
}
230235
input={EDITORS[this.state.type](this.state.value, (value) => { this.setState({ value }) })} />
236+
237+
{
238+
/*
239+
Add `Requires master key` field if parse-server version >= 3.8.0,
240+
that is the minimum version that supports this feature.
241+
*/
242+
semver.valid(this.props.parseServerVersion) && semver.gte(this.props.parseServerVersion, '3.8.0')
243+
? <Field
244+
label={
245+
<Label
246+
text='Requires master key?'
247+
description='When set to yes the parameter is returned only when requested with the master key. You can change it at any time.' />
248+
}
249+
input={
250+
<Toggle
251+
type={Toggle.Types.YES_NO}
252+
value={this.state.masterKeyOnly}
253+
onChange={(masterKeyOnly) => this.setState({ masterKeyOnly })}
254+
additionalStyles={{ margin: '0px' }} />
255+
}
256+
className={styles.addColumnToggleWrapper}
257+
/>
258+
: null
259+
}
231260
</Modal>
232261
);
233262
}

src/lib/stores/ConfigStore.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const ActionTypes = keyMirror(['FETCH', 'SET', 'DELETE']);
1616
// Config state should be an Immutable Map with the following fields:
1717
// - lastFetch: the last time all data was fetched from the server
1818
// - params: An Immutable Map of parameter strings to values
19+
// - masterKeyOnly: An Immutable Map of parameter properties for read with master key only
1920

2021
function ConfigStore(state, action) {
2122
action.app.setParseKeys();
@@ -27,22 +28,24 @@ function ConfigStore(state, action) {
2728
{},
2829
{ useMasterKey: true }
2930
).then((result) => {
30-
return Map({ lastFetch: new Date(), params: Map(result.params) });
31+
return Map({ lastFetch: new Date(), params: Map(result.params), masterKeyOnly: Map(result.masterKeyOnly) });
3132
});
3233
case ActionTypes.SET:
3334
return Parse._request(
3435
'PUT',
3536
'config',
36-
{ params: { [action.param]: Parse._encode(action.value) } },
37+
{ params: { [action.param]: Parse._encode(action.value) }, masterKeyOnly: { [action.param]: action.masterKeyOnly} },
3738
{ useMasterKey: true }
3839
).then(() => {
39-
return state.setIn(['params', action.param], action.value);
40+
return state
41+
.setIn(['params', action.param], action.value)
42+
.setIn(['masterKeyOnly', action.param], action.masterKeyOnly);
4043
});
4144
case ActionTypes.DELETE:
4245
return Parse._request(
4346
'PUT',
4447
'config',
45-
{ params: { [action.param]: { __op: 'Delete' } } },
48+
{ params: { [action.param]: { __op: 'Delete' } }, masterKeyOnly: { [action.param]: { __op: 'Delete' } } },
4649
{ useMasterKey: true }
4750
).then(() => {
4851
return state.deleteIn(['params', action.param]);

0 commit comments

Comments
 (0)