Edit and create seem to more or less work (including selection of the parent). Delete is pending.

This commit is contained in:
Tomas Bures 2017-06-07 01:13:15 +02:00
parent 61893d77f6
commit 5b82d3b540
12 changed files with 322 additions and 176 deletions

View file

@ -1,20 +0,0 @@
'use strict';
import React, { Component } from 'react';
import { translate } from 'react-i18next';
import { Title } from "../lib/page";
import csfrToken from 'csfrToken';
@translate()
export default class Create extends Component {
render() {
const t = this.props.t;
console.log('csfrToken = ' + csfrToken);
return (
<div>
<Title>{t('Create Namespace')}</Title>
</div>
);
}
}

View file

@ -0,0 +1,170 @@
'use strict';
import React, { Component } from 'react';
import { translate } from 'react-i18next';
import { withSectionHelpers, Title } from '../lib/page'
import { withForm, Form, FormSendMethod, InputField, TextArea, ButtonRow, Button, TreeTableSelect } from '../lib/form';
import axios from '../lib/axios';
import { withErrorHandling, withAsyncErrorHandler } from '../lib/error-handling';
import interoperableErrors from '../../../shared/interoperable-errors';
@translate()
@withForm
@withSectionHelpers
@withErrorHandling
export default class CreateOrEdit extends Component {
constructor(props) {
super(props);
this.initFormState();
}
isEditGlobal() {
return this.nsId === 1;
}
removeNsIdSubtree(data) {
for (let idx = 0; idx < data.length; idx++) {
const entry = data[idx];
if (entry.key === this.nsId) {
data.splice(idx, 1);
return true;
}
if (this.removeNsIdSubtree(entry.children)) {
return true;
}
}
}
@withAsyncErrorHandler
async loadTreeData() {
axios.get("/namespaces/rest/namespacesTree")
.then(response => {
const data = [response.data];
if (this.props.edit && !this.isEditGlobal()) {
this.removeNsIdSubtree(data);
}
this.setState({
treeData: data
});
});
}
componentDidMount() {
const edit = this.props.edit;
if (edit) {
this.nsId = parseInt(this.props.match.params.nsId);
this.getFormValuesFromURL(`/namespaces/rest/namespaces/${this.nsId}`, data => {
if (data.parent) data.parent = data.parent.toString();
});
} else {
this.populateFormValues({
name: '',
description: '',
parent: null
});
}
if (!this.isEditGlobal()) {
this.loadTreeData();
}
}
validateFormValues(state) {
const t = this.props.t;
if (!state.getIn(['name', 'value']).trim()) {
state.setIn(['name', 'error'], t('Name must not be empty'));
} else {
state.setIn(['name', 'error'], null);
}
if (!this.isEditGlobal()) {
if (!state.getIn(['parent', 'value'])) {
state.setIn(['parent', 'error'], t('Parent Namespace must be selected'));
} else {
state.setIn(['parent', 'error'], null);
}
}
}
async submitHandler() {
const t = this.props.t;
const edit = this.props.edit;
let sendMethod, url;
if (edit) {
sendMethod = FormSendMethod.PUT;
url = `/namespaces/rest/namespaces/${this.nsId}`
} else {
sendMethod = FormSendMethod.POST;
url = '/namespaces/rest/namespaces'
}
try {
this.disableForm();
this.setFormStatusMessage('info', t('Saving namespace ...'));
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
if (data.parent) data.parent = parseInt(data.parent);
});
if (submitSuccessful) {
this.navigateToWithFlashMessage('/namespaces', 'success', t('Namespace saved'));
} else {
this.enableForm();
this.setFormStatusMessage('warning', t('There are errors in the form. Please fix them and submit again.'));
}
} catch (error) {
if (error instanceof interoperableErrors.LoopDetectedError) {
this.disableForm();
this.setFormStatusMessage('danger',
<span>
<strong>{t('Your updates cannot be saved.')}</strong>{' '}
{t('There has been a loop detected in the assignment of the parent namespace. This is most likely because someone else has changed the parent of some namespace in the meantime. Refresh your page to start anew with fresh data. Please note that your changes will be lost.')}
</span>
);
return;
}
throw error;
}
}
async deleteHandler() {
this.setFormStatusMessage('Deleting namespace');
this.setFormStatusMessage();
}
render() {
const t = this.props.t;
const edit = this.props.edit;
return (
<div>
<Title>{edit ? t('Edit Namespace') : t('Create Namespace')}</Title>
<Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
<InputField id="name" label={t('Name')}/>
<TextArea id="description" label={t('Description')}/>
{!this.isEditGlobal() &&
<TreeTableSelect id="parent" label={t('Parent Namespace')} data={this.state.treeData}/>}
<ButtonRow>
<Button type="submit" className="btn-primary" icon="ok" label={t('Save')}/>
{edit && <Button className="btn-danger" icon="remove" label={t('Delete Namespace')}
onClickAsync={::this.deleteHandler}/>}
</ButtonRow>
</Form>
</div>
);
}
}

View file

@ -1,74 +0,0 @@
'use strict';
import React, { Component } from 'react';
import { translate } from 'react-i18next';
import { withSectionHelpers } from '../lib/page'
import { withForm, Form, InputField, TextArea, ButtonRow, Button, TreeTableSelect } from '../lib/form';
import { Title } from "../lib/page";
import axios from '../lib/axios';
@translate()
@withForm
@withSectionHelpers
export default class Edit extends Component {
constructor(props) {
super(props);
this.nsId = parseInt(this.props.match.params.nsId);
console.log('Constructing Edit');
this.initFormState();
this.getFormValuesFromURL(`/namespaces/rest/namespaces/${this.nsId}`, data => {
if (data.parent) data.parent = data.parent.toString();
});
}
validateFormValues(state) {
const t = this.props.t;
if (!state.getIn(['name','value']).trim()) {
state.setIn(['name', 'error'], t('Name must not be empty'));
} else {
state.setIn(['name', 'error'], null);
}
}
async submitHandler() {
const t = this.props.t;
await this.validateAndPutFormValuesToURL(`/namespaces/rest/namespaces/${this.nsId}`, data => {
if (data.parent) data.parent = parseInt(data.parent);
});
this.navigateToWithFlashMessage('/namespaces', 'success', t('Namespace saved'));
// FIXME - the enable form in form.js gets called. This causes a warning. Check there whether the component is still mounted.
}
async deleteHandler() {
this.setFormStatusMessage('Deleting namespace');
this.setFormStatusMessage();
}
render() {
const t = this.props.t;
return (
<div>
<Title>{t('Edit Namespace')}</Title>
<Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
<InputField id="name" label={t('Name')}/>
<TextArea id="description" label={t('Description')}/>
<ButtonRow>
<Button type="submit" className="btn-primary" icon="ok" label={t('Update')}/>
<Button className="btn-danger" icon="remove" label={t('Delete Namespace')} onClickAsync={::this.deleteHandler}/>
</ButtonRow>
{this.nsId !== 1 && <TreeTableSelect id="parent" label={t('Parent Namespace')} dataUrl="/namespaces/rest/namespacesTree"/>}
</Form>
</div>
);
}
}

View file

@ -6,8 +6,7 @@ import { I18nextProvider } from 'react-i18next';
import i18n from '../lib/i18n';
import { Section } from '../lib/page'
import Create from './Create'
import Edit from './Edit'
import CreateOrEdit from './CreateOrEdit'
import List from './List'
const getStructure = t => ({
@ -23,12 +22,12 @@ const getStructure = t => ({
'edit' : {
title: t('Edit Namespace'),
params: [':nsId'],
component: Edit
render: props => (<CreateOrEdit edit {...props} />)
},
'create' : {
title: t('Create Namespace'),
link: '/namespaces/create',
component: Create
render: props => (<CreateOrEdit {...props} />)
}
}
}