Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/components/BrowserCell/BrowserCell.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,13 @@ export default class BrowserCell extends Component {
//#endregion

render() {
let { type, value, hidden, width, current, onSelect, onEditChange, setCopyableValue, setRelation, onPointerClick, row, col, field, onEditSelectedRow, readonly } = this.props;
let { type, value, hidden, width, current, onSelect, onEditChange, setCopyableValue, setRelation, onPointerClick, row, col, field, onEditSelectedRow, readonly, isRequired, markRequiredField } = this.props;
let content = value;
let isNewRow = row < 0;
this.copyableValue = content;
let classes = [styles.cell, unselectable];
if (hidden) {
content = '(hidden)';
content = value !== undefined || !isNewRow ? '(hidden)' : isRequired ? '(required)' : '(undefined)';
classes.push(styles.empty);
} else if (value === undefined) {
if (type === 'ACL') {
Expand All @@ -228,6 +229,7 @@ export default class BrowserCell extends Component {
this.copyableValue = content = '(undefined)';
classes.push(styles.empty);
}
content = isNewRow && isRequired && value === undefined ? '(required)' : content;
} else if (value === null) {
this.copyableValue = content = '(null)';
classes.push(styles.empty);
Expand Down Expand Up @@ -303,6 +305,10 @@ export default class BrowserCell extends Component {
classes.push(styles.current);
}

if (markRequiredField && isRequired && !value) {
classes.push(styles.required);
}

return readonly ? (
<Tooltip placement='bottom' tooltip='Read only (CTRL+C to copy)' visible={this.state.showTooltip} >
<span
Expand All @@ -324,7 +330,7 @@ export default class BrowserCell extends Component {
}
}}
>
{row < 0 ? '(auto)' : content}
{isNewRow ? '(auto)' : content}
</span>
</Tooltip>
) : (
Expand Down
15 changes: 15 additions & 0 deletions src/components/BrowserCell/BrowserCell.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,18 @@
bottom: 0;
}
}

.required {
position: relative;

&:after {
position: absolute;
pointer-events: none;
content: '';
border: 2px solid #ff395e;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
5 changes: 4 additions & 1 deletion src/components/BrowserRow/BrowserRow.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default class BrowserRow extends Component {
}

render() {
const { className, columns, currentCol, isUnique, obj, onPointerClick, order, readOnlyFields, row, rowWidth, selection, selectRow, setCopyableValue, setCurrent, setEditing, setRelation, onEditSelectedRow, setContextMenu, onFilterChange } = this.props;
const { className, columns, currentCol, isUnique, obj, onPointerClick, order, readOnlyFields, row, rowWidth, selection, selectRow, setCopyableValue, setCurrent, setEditing, setRelation, onEditSelectedRow, setContextMenu, onFilterChange, markRequiredField, requiredColumnFields } = this.props;
let attributes = obj.attributes;
return (
<div className={styles.tableRow} style={{ minWidth: rowWidth }}>
Expand Down Expand Up @@ -58,6 +58,7 @@ export default class BrowserRow extends Component {
hidden = true;
}
}
let isRequired = requiredColumnFields && requiredColumnFields.includes(name);
return (
<BrowserCell
key={name}
Expand All @@ -80,6 +81,8 @@ export default class BrowserRow extends Component {
objectId={obj.id}
value={attr}
hidden={hidden}
isRequired={isRequired}
markRequiredField={markRequiredField}
setCopyableValue={setCopyableValue}
setContextMenu={setContextMenu}
onEditSelectedRow={onEditSelectedRow} />
Expand Down
109 changes: 107 additions & 2 deletions src/dashboard/Data/Browser/Browser.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class Browser extends DashboardView {

isUnique: false,
uniqueField: null,
markRequiredField: false,
requiredColumnFields: []
};

this.prefetchData = this.prefetchData.bind(this);
Expand Down Expand Up @@ -123,6 +125,7 @@ class Browser extends DashboardView {
this.onDialogToggle = this.onDialogToggle.bind(this);
this.abortAddRow = this.abortAddRow.bind(this);
this.saveNewRow = this.saveNewRow.bind(this);
this.setRequiredColumnFields = this.setRequiredColumnFields.bind(this);
}

componentWillMount() {
Expand Down Expand Up @@ -280,14 +283,26 @@ class Browser extends DashboardView {
required,
defaultValue
};
this.props.schema.dispatch(ActionTypes.ADD_COLUMN, payload).catch((err) => {
this.props.schema.dispatch(ActionTypes.ADD_COLUMN, payload).then(() => {
// if new required field column is added, then add field in requiredColumn
if (required) {
let requiredCols = [...this.state.requiredColumnFields, name];
this.setState({
requiredColumnFields: requiredCols
});
}
}).catch((err) => {
this.showNote(err.message, true);
}).finally(() => {
this.setState({ showAddColumnDialog: false });
});
}

addRow() {
if (this.props.params.className === '_User') {
// if User class row, then reload requiredFields
this.setRequiredColumnFields();
}
if (!this.state.newObject) {
const relation = this.state.relation;
this.setState({
Expand All @@ -304,6 +319,11 @@ class Browser extends DashboardView {
newObject: null
});
}
if (this.state.markRequiredField) {
this.setState({
markRequiredField: false
});
}
}

saveNewRow(){
Expand All @@ -312,6 +332,45 @@ class Browser extends DashboardView {
return;
}

// check if required fields are missing
const className = this.props.params.className;
let requiredCols = [];
if (className) {
let classColumns = this.props.schema.data.get('classes').get(className);
classColumns.forEach(({ required }, name) => {
if (name === 'objectId' || this.state.isUnique && name !== this.state.uniqueField) {
return;
}
if (!!required) {
requiredCols.push(name);
}
if (className === '_User' && (name === 'username' || name === 'password')) {
if (!obj.get('authData')) {
requiredCols.push(name);
}
}
if (className === '_Role' && (name === 'name' || name === 'ACL')) {
requiredCols.push(name);
}
});
}
if (requiredCols.length) {
for (let idx = 0; idx < requiredCols.length; idx++) {
const name = requiredCols[idx];
if (!obj.get(name)) {
this.showNote("Please enter all required fields", true);
this.setState({
markRequiredField: true
});
return;
}
}
}
if (this.state.markRequiredField) {
this.setState({
markRequiredField: false
});
}
obj.save(null, { useMasterKey: true }).then(
objectSaved => {
let msg = objectSaved.className + ' with id \'' + objectSaved.id + '\' created';
Expand Down Expand Up @@ -483,6 +542,30 @@ class Browser extends DashboardView {
delete filteredCounts[source];
}
this.setState({ data: data, filters, lastMax: MAX_ROWS_FETCHED , filteredCounts: filteredCounts});
this.setRequiredColumnFields();
}

setRequiredColumnFields() {
if (!this.props.schema.data.get('classes')) {
return;
}
let classes = this.props.schema.data.get('classes');
const { className } = this.props.params;
let requiredCols = [];
classes.get(className).forEach(({ required }, name) => {
if (!!required) {
requiredCols.push(name);
}
if (className === '_User' && (name === 'username' || name === 'password' || name === 'authData')) {
requiredCols.push(name);
}
if (className === '_Role' && (name === 'name' || name === 'ACL')) {
requiredCols.push(name);
}
});
this.setState({
requiredColumnFields: requiredCols
});
}

async fetchRelation(relation, filters = new List()) {
Expand Down Expand Up @@ -636,7 +719,27 @@ class Browser extends DashboardView {
} else {
obj.set(attr, value);
}
if(isNewObject){

if (isNewObject) {
// for dynamically changing required placeholder text for _User class new row object
if (obj.className === '_User' && attr === 'authData' && value !== undefined) {
// username & password are not required
this.setState({
requiredColumnFields: this.state.requiredColumnFields.filter(field => field !== 'username' && field !== 'password')
})
}

if (obj.className === '_User' && (attr === 'username' || attr === 'password') && value !== undefined) {
// authData is not required
this.setState({
requiredColumnFields: this.state.requiredColumnFields.filter(field => field !== 'authData')
})
}

if (obj.className === '_User' && obj.get('username') === undefined && obj.get('password') === undefined && obj.get('authData') === undefined) {
this.setRequiredColumnFields();
}

this.setState({
isNewObject: obj
});
Expand Down Expand Up @@ -1076,6 +1179,8 @@ class Browser extends DashboardView {
onSaveNewRow={this.saveNewRow}
onAbortAddRow={this.abortAddRow}

markRequiredField={this.state.markRequiredField}
requiredColumnFields={this.state.requiredColumnFields}
columns={columns}
className={className}
fetchNextPage={this.fetchNextPage}
Expand Down
7 changes: 5 additions & 2 deletions src/dashboard/Data/Browser/BrowserTable.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,16 @@ export default class BrowserTable extends React.Component {
}
}

let headers = this.props.order.map(({ name, width, visible, preventSort }) => (
let headers = this.props.order.map(({ name, width, visible, preventSort, required }) => (
{
width: width,
name: name,
type: this.props.columns[name].type,
targetClass: this.props.columns[name].targetClass,
order: ordering.col === name ? ordering.direction : null,
visible,
preventSort
preventSort,
required
}
));
let editor = null;
Expand Down Expand Up @@ -142,6 +143,8 @@ export default class BrowserTable extends React.Component {
setCopyableValue={this.props.setCopyableValue}
setContextMenu={this.props.setContextMenu}
onEditSelectedRow={this.props.onEditSelectedRow}
markRequiredField={this.props.markRequiredField}
requiredColumnFields={this.props.requiredColumnFields}
/>
<Button
value="Add"
Expand Down
8 changes: 6 additions & 2 deletions src/lib/ColumnPreferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,25 @@ export function getOrder(cols, appId, className, defaultPrefs) {
for (let name in cols) {
requested[name] = true;
if (!seen[name]) {
order.push({ name: name, width: DEFAULT_WIDTH, visible: !defaultPrefs });
order.push({ name: name, width: DEFAULT_WIDTH, visible: !defaultPrefs, required: cols[name]['required'] });
seen[name] = true;
updated = true;
}
}
let filtered = [];
for (let i = 0; i < order.length; i++) {
const { name, visible } = order[i];
const { name, visible, required } = order[i];

// If "visible" attribute is not defined, sets to true
// and updates the cached preferences.
if (typeof visible === 'undefined') {
order[i].visible = true;
updated = true;
}
// If "required" attribute is not defined, set it to false
if (typeof required === 'undefined') {
order[i].required = false;
}
if (requested[name]) {
filtered.push(order[i]);
} else {
Expand Down