Skip to content

Commit 038be15

Browse files
authored
Showing * for required Columns (#1720)
* passing down required field info * showing * for required columns * marked required columns for standard classes * showing required for new row * mark required fields as red on save new row * showing hidden when no value set * dynamically changing required text * showing (hidden) for hidden field * added new var isNewRow * update required fields if all are undefined _User * update required Fields after new col add * update required field on required col add
1 parent e4fab23 commit 038be15

File tree

6 files changed

+146
-10
lines changed

6 files changed

+146
-10
lines changed

src/components/BrowserCell/BrowserCell.react.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,13 @@ export default class BrowserCell extends Component {
214214
//#endregion
215215

216216
render() {
217-
let { type, value, hidden, width, current, onSelect, onEditChange, setCopyableValue, setRelation, onPointerClick, row, col, field, onEditSelectedRow, readonly } = this.props;
217+
let { type, value, hidden, width, current, onSelect, onEditChange, setCopyableValue, setRelation, onPointerClick, row, col, field, onEditSelectedRow, readonly, isRequired, markRequiredField } = this.props;
218218
let content = value;
219+
let isNewRow = row < 0;
219220
this.copyableValue = content;
220221
let classes = [styles.cell, unselectable];
221222
if (hidden) {
222-
content = '(hidden)';
223+
content = value !== undefined || !isNewRow ? '(hidden)' : isRequired ? '(required)' : '(undefined)';
223224
classes.push(styles.empty);
224225
} else if (value === undefined) {
225226
if (type === 'ACL') {
@@ -228,6 +229,7 @@ export default class BrowserCell extends Component {
228229
this.copyableValue = content = '(undefined)';
229230
classes.push(styles.empty);
230231
}
232+
content = isNewRow && isRequired && value === undefined ? '(required)' : content;
231233
} else if (value === null) {
232234
this.copyableValue = content = '(null)';
233235
classes.push(styles.empty);
@@ -303,6 +305,10 @@ export default class BrowserCell extends Component {
303305
classes.push(styles.current);
304306
}
305307

308+
if (markRequiredField && isRequired && !value) {
309+
classes.push(styles.required);
310+
}
311+
306312
return readonly ? (
307313
<Tooltip placement='bottom' tooltip='Read only (CTRL+C to copy)' visible={this.state.showTooltip} >
308314
<span
@@ -324,7 +330,7 @@ export default class BrowserCell extends Component {
324330
}
325331
}}
326332
>
327-
{row < 0 ? '(auto)' : content}
333+
{isNewRow ? '(auto)' : content}
328334
</span>
329335
</Tooltip>
330336
) : (

src/components/BrowserCell/BrowserCell.scss

+15
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,18 @@
3535
bottom: 0;
3636
}
3737
}
38+
39+
.required {
40+
position: relative;
41+
42+
&:after {
43+
position: absolute;
44+
pointer-events: none;
45+
content: '';
46+
border: 2px solid #ff395e;
47+
top: 0;
48+
left: 0;
49+
right: 0;
50+
bottom: 0;
51+
}
52+
}

src/components/BrowserRow/BrowserRow.react.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default class BrowserRow extends Component {
1919
}
2020

2121
render() {
22-
const { className, columns, currentCol, isUnique, obj, onPointerClick, order, readOnlyFields, row, rowWidth, selection, selectRow, setCopyableValue, setCurrent, setEditing, setRelation, onEditSelectedRow, setContextMenu, onFilterChange } = this.props;
22+
const { className, columns, currentCol, isUnique, obj, onPointerClick, order, readOnlyFields, row, rowWidth, selection, selectRow, setCopyableValue, setCurrent, setEditing, setRelation, onEditSelectedRow, setContextMenu, onFilterChange, markRequiredField, requiredColumnFields } = this.props;
2323
let attributes = obj.attributes;
2424
return (
2525
<div className={styles.tableRow} style={{ minWidth: rowWidth }}>
@@ -58,6 +58,7 @@ export default class BrowserRow extends Component {
5858
hidden = true;
5959
}
6060
}
61+
let isRequired = requiredColumnFields && requiredColumnFields.includes(name);
6162
return (
6263
<BrowserCell
6364
key={name}
@@ -80,6 +81,8 @@ export default class BrowserRow extends Component {
8081
objectId={obj.id}
8182
value={attr}
8283
hidden={hidden}
84+
isRequired={isRequired}
85+
markRequiredField={markRequiredField}
8386
setCopyableValue={setCopyableValue}
8487
setContextMenu={setContextMenu}
8588
onEditSelectedRow={onEditSelectedRow} />

src/dashboard/Data/Browser/Browser.react.js

+107-2
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ class Browser extends DashboardView {
7979

8080
isUnique: false,
8181
uniqueField: null,
82+
markRequiredField: false,
83+
requiredColumnFields: []
8284
};
8385

8486
this.prefetchData = this.prefetchData.bind(this);
@@ -123,6 +125,7 @@ class Browser extends DashboardView {
123125
this.onDialogToggle = this.onDialogToggle.bind(this);
124126
this.abortAddRow = this.abortAddRow.bind(this);
125127
this.saveNewRow = this.saveNewRow.bind(this);
128+
this.setRequiredColumnFields = this.setRequiredColumnFields.bind(this);
126129
}
127130

128131
componentWillMount() {
@@ -280,14 +283,26 @@ class Browser extends DashboardView {
280283
required,
281284
defaultValue
282285
};
283-
this.props.schema.dispatch(ActionTypes.ADD_COLUMN, payload).catch((err) => {
286+
this.props.schema.dispatch(ActionTypes.ADD_COLUMN, payload).then(() => {
287+
// if new required field column is added, then add field in requiredColumn
288+
if (required) {
289+
let requiredCols = [...this.state.requiredColumnFields, name];
290+
this.setState({
291+
requiredColumnFields: requiredCols
292+
});
293+
}
294+
}).catch((err) => {
284295
this.showNote(err.message, true);
285296
}).finally(() => {
286297
this.setState({ showAddColumnDialog: false });
287298
});
288299
}
289300

290301
addRow() {
302+
if (this.props.params.className === '_User') {
303+
// if User class row, then reload requiredFields
304+
this.setRequiredColumnFields();
305+
}
291306
if (!this.state.newObject) {
292307
const relation = this.state.relation;
293308
this.setState({
@@ -304,6 +319,11 @@ class Browser extends DashboardView {
304319
newObject: null
305320
});
306321
}
322+
if (this.state.markRequiredField) {
323+
this.setState({
324+
markRequiredField: false
325+
});
326+
}
307327
}
308328

309329
saveNewRow(){
@@ -312,6 +332,45 @@ class Browser extends DashboardView {
312332
return;
313333
}
314334

335+
// check if required fields are missing
336+
const className = this.props.params.className;
337+
let requiredCols = [];
338+
if (className) {
339+
let classColumns = this.props.schema.data.get('classes').get(className);
340+
classColumns.forEach(({ required }, name) => {
341+
if (name === 'objectId' || this.state.isUnique && name !== this.state.uniqueField) {
342+
return;
343+
}
344+
if (!!required) {
345+
requiredCols.push(name);
346+
}
347+
if (className === '_User' && (name === 'username' || name === 'password')) {
348+
if (!obj.get('authData')) {
349+
requiredCols.push(name);
350+
}
351+
}
352+
if (className === '_Role' && (name === 'name' || name === 'ACL')) {
353+
requiredCols.push(name);
354+
}
355+
});
356+
}
357+
if (requiredCols.length) {
358+
for (let idx = 0; idx < requiredCols.length; idx++) {
359+
const name = requiredCols[idx];
360+
if (!obj.get(name)) {
361+
this.showNote("Please enter all required fields", true);
362+
this.setState({
363+
markRequiredField: true
364+
});
365+
return;
366+
}
367+
}
368+
}
369+
if (this.state.markRequiredField) {
370+
this.setState({
371+
markRequiredField: false
372+
});
373+
}
315374
obj.save(null, { useMasterKey: true }).then(
316375
objectSaved => {
317376
let msg = objectSaved.className + ' with id \'' + objectSaved.id + '\' created';
@@ -483,6 +542,30 @@ class Browser extends DashboardView {
483542
delete filteredCounts[source];
484543
}
485544
this.setState({ data: data, filters, lastMax: MAX_ROWS_FETCHED , filteredCounts: filteredCounts});
545+
this.setRequiredColumnFields();
546+
}
547+
548+
setRequiredColumnFields() {
549+
if (!this.props.schema.data.get('classes')) {
550+
return;
551+
}
552+
let classes = this.props.schema.data.get('classes');
553+
const { className } = this.props.params;
554+
let requiredCols = [];
555+
classes.get(className).forEach(({ required }, name) => {
556+
if (!!required) {
557+
requiredCols.push(name);
558+
}
559+
if (className === '_User' && (name === 'username' || name === 'password' || name === 'authData')) {
560+
requiredCols.push(name);
561+
}
562+
if (className === '_Role' && (name === 'name' || name === 'ACL')) {
563+
requiredCols.push(name);
564+
}
565+
});
566+
this.setState({
567+
requiredColumnFields: requiredCols
568+
});
486569
}
487570

488571
async fetchRelation(relation, filters = new List()) {
@@ -636,7 +719,27 @@ class Browser extends DashboardView {
636719
} else {
637720
obj.set(attr, value);
638721
}
639-
if(isNewObject){
722+
723+
if (isNewObject) {
724+
// for dynamically changing required placeholder text for _User class new row object
725+
if (obj.className === '_User' && attr === 'authData' && value !== undefined) {
726+
// username & password are not required
727+
this.setState({
728+
requiredColumnFields: this.state.requiredColumnFields.filter(field => field !== 'username' && field !== 'password')
729+
})
730+
}
731+
732+
if (obj.className === '_User' && (attr === 'username' || attr === 'password') && value !== undefined) {
733+
// authData is not required
734+
this.setState({
735+
requiredColumnFields: this.state.requiredColumnFields.filter(field => field !== 'authData')
736+
})
737+
}
738+
739+
if (obj.className === '_User' && obj.get('username') === undefined && obj.get('password') === undefined && obj.get('authData') === undefined) {
740+
this.setRequiredColumnFields();
741+
}
742+
640743
this.setState({
641744
isNewObject: obj
642745
});
@@ -1076,6 +1179,8 @@ class Browser extends DashboardView {
10761179
onSaveNewRow={this.saveNewRow}
10771180
onAbortAddRow={this.abortAddRow}
10781181

1182+
markRequiredField={this.state.markRequiredField}
1183+
requiredColumnFields={this.state.requiredColumnFields}
10791184
columns={columns}
10801185
className={className}
10811186
fetchNextPage={this.fetchNextPage}

src/dashboard/Data/Browser/BrowserTable.react.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,16 @@ export default class BrowserTable extends React.Component {
9898
}
9999
}
100100

101-
let headers = this.props.order.map(({ name, width, visible, preventSort }) => (
101+
let headers = this.props.order.map(({ name, width, visible, preventSort, required }) => (
102102
{
103103
width: width,
104104
name: name,
105105
type: this.props.columns[name].type,
106106
targetClass: this.props.columns[name].targetClass,
107107
order: ordering.col === name ? ordering.direction : null,
108108
visible,
109-
preventSort
109+
preventSort,
110+
required
110111
}
111112
));
112113
let editor = null;
@@ -142,6 +143,8 @@ export default class BrowserTable extends React.Component {
142143
setCopyableValue={this.props.setCopyableValue}
143144
setContextMenu={this.props.setContextMenu}
144145
onEditSelectedRow={this.props.onEditSelectedRow}
146+
markRequiredField={this.props.markRequiredField}
147+
requiredColumnFields={this.props.requiredColumnFields}
145148
/>
146149
<Button
147150
value="Add"

src/lib/ColumnPreferences.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -87,21 +87,25 @@ export function getOrder(cols, appId, className, defaultPrefs) {
8787
for (let name in cols) {
8888
requested[name] = true;
8989
if (!seen[name]) {
90-
order.push({ name: name, width: DEFAULT_WIDTH, visible: !defaultPrefs });
90+
order.push({ name: name, width: DEFAULT_WIDTH, visible: !defaultPrefs, required: cols[name]['required'] });
9191
seen[name] = true;
9292
updated = true;
9393
}
9494
}
9595
let filtered = [];
9696
for (let i = 0; i < order.length; i++) {
97-
const { name, visible } = order[i];
97+
const { name, visible, required } = order[i];
9898

9999
// If "visible" attribute is not defined, sets to true
100100
// and updates the cached preferences.
101101
if (typeof visible === 'undefined') {
102102
order[i].visible = true;
103103
updated = true;
104104
}
105+
// If "required" attribute is not defined, set it to false
106+
if (typeof required === 'undefined') {
107+
order[i].required = false;
108+
}
105109
if (requested[name]) {
106110
filtered.push(order[i]);
107111
} else {

0 commit comments

Comments
 (0)