CCM NG: PageModels Editor Alpha finished

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5670 8810af33-2d31-482b-a856-94f89814c4df
jensp 2018-08-11 14:33:39 +00:00
parent 4f329a6961
commit 1b96a3c4e0
5 changed files with 224 additions and 32 deletions

View File

@ -77,7 +77,7 @@ class CategoryTreeComponentEditorDialog
pageModelName={this.props.pageModelName}> pageModelName={this.props.pageModelName}>
<label htmlFor={`${idPrefix}showFullTree`}>Show full tree?</label> <label htmlFor={`${idPrefix}showFullTree`}>Show full tree?</label>
<input checked={this.props.component.showFullTree} <input checked={this.state.showFullTree}
id={`${idPrefix}showFullTree`} id={`${idPrefix}showFullTree`}
onChange={this.handleChange} onChange={this.handleChange}
type="checkbox" /> type="checkbox" />
@ -637,41 +637,45 @@ interface ItemListComponent extends ComponentModel {
} }
ComponentModelEditor.registerEditorComponents( ComponentModelEditor.registerEditorComponents(
"org.librecms.pagemodel.CategoryTreeComponent",
{ {
componentTitle: "Category Tree",
componentType: "org.librecms.pagemodel.CategoryTreeComponent",
editorDialog: editorDialog:
CategoryTreeComponentEditorDialog as typeof React.Component, CategoryTreeComponentEditorDialog as typeof React.Component,
propertiesList: propertiesList:
CategoryTreeComponentPropertiesList as typeof React.Component, CategoryTreeComponentPropertiesList as typeof React.Component,
}, }
); );
ComponentModelEditor.registerEditorComponents( ComponentModelEditor.registerEditorComponents(
"org.librecms.pagemodel.ItemListComponent",
{ {
componentTitle: "Item List",
componentType: "org.librecms.pagemodel.ItemListComponent",
editorDialog: editorDialog:
ItemListComponentEditorDialog as typeof React.Component, ItemListComponentEditorDialog as typeof React.Component,
propertiesList: propertiesList:
ItemListComponentPropertiesList as typeof React.Component, ItemListComponentPropertiesList as typeof React.Component,
}, }
); );
ComponentModelEditor.registerEditorComponents( ComponentModelEditor.registerEditorComponents(
"org.librecms.pagemodel.FixedContentItemComponent",
{ {
componentTitle: "Fixed Content Item",
componentType: "org.librecms.pagemodel.FixedContentItemComponent",
editorDialog: editorDialog:
FixedContentItemComponentEditorDialog as typeof React.Component, FixedContentItemComponentEditorDialog as typeof React.Component,
propertiesList: propertiesList:
FixedContentItemComponentPropertiesList as typeof React.Component, FixedContentItemComponentPropertiesList as typeof React.Component,
}, }
); );
ComponentModelEditor.registerEditorComponents( ComponentModelEditor.registerEditorComponents(
"org.librecms.pagemodel.GreetingItemComponent",
{ {
componentTitle: "Greeting Item",
componentType: "org.librecms.pagemodel.GreetingItemComponent",
editorDialog: editorDialog:
GreetingItemComponentEditorDialog as typeof React.Component, GreetingItemComponentEditorDialog as typeof React.Component,
propertiesList: propertiesList:
GreetingItemComponentPropertiesList as typeof React.Component GreetingItemComponentPropertiesList as typeof React.Component
}, }
); );

View File

@ -82,7 +82,7 @@ public class CategoryTreeComponentJsonConverter
readBasePropertiesFromJson(jsonObject, categoryTree); readBasePropertiesFromJson(jsonObject, categoryTree);
if (!jsonObject.isNull(SHOW_FULL_TREE)) { if (jsonObject.containsKey(SHOW_FULL_TREE)) {
categoryTree.setShowFullTree(jsonObject.getBoolean(SHOW_FULL_TREE)); categoryTree.setShowFullTree(jsonObject.getBoolean(SHOW_FULL_TREE));
} }
} }

View File

@ -83,22 +83,25 @@ public abstract class AbstractComponentModelJsonConverter
Objects.requireNonNull(jsonObject); Objects.requireNonNull(jsonObject);
Objects.requireNonNull(componentModel); Objects.requireNonNull(componentModel);
componentModel.setComponentModelId( //UUIDs are solely managed by the server!
jsonObject.getInt("componentModelId")); // if (jsonObject.containsKey("uuid")) {
componentModel.setUuid(jsonObject.getString("uuid")); // componentModel.setUuid(jsonObject.getString("uuid"));
componentModel.setModelUuid(jsonObject.getString("modelUuid")); // }
// if (jsonObject.containsKey("modelUuid")) {
// componentModel.setModelUuid(jsonObject.getString("modelUuid"));
// }
componentModel.setKey(jsonObject.getString("key")); componentModel.setKey(jsonObject.getString("key"));
if (jsonObject.getString("idAttribute") != null) { if (jsonObject.getString("idAttribute", null) != null) {
componentModel.setIdAttribute(jsonObject.getString("idAttribute")); componentModel.setIdAttribute(jsonObject.getString("idAttribute"));
} }
if (jsonObject.getString("classAttribute") != null) { if (jsonObject.getString("classAttribute", null) != null) {
componentModel componentModel
.setClassAttribute(jsonObject.getString("classAttribute")); .setClassAttribute(jsonObject.getString("classAttribute"));
} }
if (jsonObject.getString("styleAttribute") != null) { if (jsonObject.getString("styleAttribute", null) != null) {
componentModel componentModel
.setStyleAttribute(jsonObject.getString("styleAttribute")); .setStyleAttribute(jsonObject.getString("styleAttribute"));
} }

View File

@ -19,7 +19,6 @@
package org.libreccm.pagemodel.rs; package org.libreccm.pagemodel.rs;
import org.libreccm.core.CoreConstants; import org.libreccm.core.CoreConstants;
import org.libreccm.core.UnexpectedErrorException;
import org.libreccm.pagemodel.ComponentModel; import org.libreccm.pagemodel.ComponentModel;
import org.libreccm.pagemodel.ComponentModelJsonConverter; import org.libreccm.pagemodel.ComponentModelJsonConverter;
import org.libreccm.pagemodel.ComponentModelRepository; import org.libreccm.pagemodel.ComponentModelRepository;
@ -31,9 +30,6 @@ import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege; import org.libreccm.security.RequiresPrivilege;
import org.libreccm.web.CcmApplication; import org.libreccm.web.CcmApplication;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -53,7 +49,6 @@ import javax.json.Json;
import javax.json.JsonArray; import javax.json.JsonArray;
import javax.json.JsonArrayBuilder; import javax.json.JsonArrayBuilder;
import javax.json.JsonObject; import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonValue; import javax.json.JsonValue;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
@ -243,7 +238,9 @@ public class Components {
componentRepo.save(componentModel); componentRepo.save(componentModel);
return mapComponentModelToJson(componentModel); final ComponentModel saved = controller
.findComponentModel(app, pageModel, container, componentKey);
return mapComponentModelToJson(saved);
} }
/** /**
@ -427,7 +424,7 @@ public class Components {
try { try {
final Class<?> clazz = Class.forName(type); final Class<?> clazz = Class.forName(type);
if (clazz.isAssignableFrom(ComponentModel.class)) { if (ComponentModel.class.isAssignableFrom(clazz)) {
return (Class<? extends ComponentModel>) clazz; return (Class<? extends ComponentModel>) clazz;
} else { } else {
throw new BadRequestException(String.format( throw new BadRequestException(String.format(

View File

@ -775,6 +775,8 @@ interface ContainerModelComponentProps {
interface ContainerModelComponentState { interface ContainerModelComponentState {
addComponentOfType: string;
addComponentWithKey: string;
components: ComponentModel[]; components: ComponentModel[];
errorMessages: string[]; errorMessages: string[];
} }
@ -789,9 +791,15 @@ class ContainerModelComponent
this.state = { this.state = {
addComponentOfType: "",
addComponentWithKey: "",
components: [], components: [],
errorMessages: [], errorMessages: [],
}; };
this.handleKeyChange = this.handleKeyChange.bind(this);
this.handleTypeSelectChange = this.handleTypeSelectChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
} }
public componentDidMount() { public componentDidMount() {
@ -812,7 +820,41 @@ class ContainerModelComponent
Delete Delete
</button> </button>
</div> </div>
{this.state.errorMessages.length > 0
&& <div className="errorPanel">
<ul>
{this.state.errorMessages.map((msg, index) =>
<li key={index}>{msg}</li>
)}
</ul>
</div>
}
<div className="components-list"> <div className="components-list">
<form onSubmit={this.handleSubmit}>
<label htmlFor={`${this.props.container.key}_add_component_type`}>
Add component of type
</label>
<select id={`${this.props.container.key}_add_component_type`}
onChange={this.handleTypeSelectChange}>
<option value=""></option>
{ComponentModelEditor.getAvailableComponents()
.map((component) =>
<option key={component.componentType}
value={component.componentType}>
{component.componentTitle}
</option>
)}
</select>
<label htmlFor={`${this.props.container.key}_add_component_key`}>
with key
</label>
<input id={`${this.props.container.key}_add_component_key`}
onChange={this.handleKeyChange}
type="text" />
<button>
Add component
</button>
</form>
<ul> <ul>
{this.state.components.map((component: ComponentModel) => {this.state.components.map((component: ComponentModel) =>
<ComponentModelEditor <ComponentModelEditor
@ -829,6 +871,15 @@ class ContainerModelComponent
</li>; </li>;
} }
private deleteContainer(
event: React.MouseEvent<HTMLButtonElement>,
containerKey: string): void {
event.preventDefault();
this.props.deleteContainer(containerKey);
}
private fetchComponents(): void { private fetchComponents(): void {
const componentsUrl = `${this.props.dispatcherPrefix}` const componentsUrl = `${this.props.dispatcherPrefix}`
@ -893,13 +944,126 @@ class ContainerModelComponent
}); });
} }
private deleteContainer( private handleKeyChange(event: React.ChangeEvent<HTMLInputElement>): void {
event: React.MouseEvent<HTMLButtonElement>,
containerKey: string): void { const target: HTMLInputElement = event.currentTarget;
this.setState({
...this.state,
addComponentWithKey: target.value,
});
}
private handleTypeSelectChange(
event: React.ChangeEvent<HTMLSelectElement>): void {
const target: HTMLSelectElement = event.currentTarget;
this.setState({
...this.state,
addComponentOfType: target.value,
});
}
private handleSubmit(event: React.FormEvent<HTMLFormElement>): void {
event.preventDefault(); event.preventDefault();
this.props.deleteContainer(containerKey); if (this.state.addComponentOfType === ""
|| this.state.addComponentWithKey === "") {
this.setState({
...this.state,
errorMessages: [
...this.state.errorMessages,
`Type and key are mandantory!`,
],
});
return;
}
const headers: Headers = new Headers();
headers.append("Content-Type", "application/json");
const init: RequestInit = {
body: JSON.stringify({
type: this.state.addComponentOfType,
key: this.state.addComponentWithKey,
}),
credentials: "same-origin",
headers,
method: "PUT",
}
const url: string = `${this.props.dispatcherPrefix}`
+ `/page-models/${this.props.ccmApplication}/`
+ `${this.props.pageModelName}`
+ `/containers/`
+ `${this.props.container.key}`
+ `/components/`
+ `${this.state.addComponentWithKey}`;
fetch(url, init)
.then((response: Response) => {
if (response.ok) {
response
.json()
.then((newComponent) => {
const components = [
...this.state.components,
newComponent,
];
components.sort((component1, component2) => {
const key1: string = component1.key;
const key2: string = component2.key;
return key1.localeCompare(key2);
});
this.setState({
...this.state,
addComponentWithKey: "",
addComponentOfType: "",
components,
});
})
.catch((error) => {
this.setState({
...this.state,
errorMessages: [
...this.state.errorMessages,
`Failed to parse response: `
+ `${error.message}`,
],
});
});
} else {
this.setState({
...this.state,
errorMessages: [
...this.state.errorMessages,
`Failed to add component to container`
+ `${response.status} ${response.statusText}`,
]
});
}
})
.catch((error) => {
this.setState({
...this.state,
errorMessages: [
...this.state.errorMessages,
`Failed to add component to container`
+ ` ${this.props.container.key}: ${error.message}`
],
});
});
} }
} }
@ -1104,6 +1268,8 @@ class BasicComponentModelEditorDialog
interface EditorComponents { interface EditorComponents {
componentType: string;
componentTitle: string;
editorDialog: typeof React.Component; editorDialog: typeof React.Component;
propertiesList: typeof React.Component; propertiesList: typeof React.Component;
} }
@ -1120,10 +1286,30 @@ interface ComponentModelEditorProps {
class ComponentModelEditor class ComponentModelEditor
extends React.Component<ComponentModelEditorProps, {}> { extends React.Component<ComponentModelEditorProps, {}> {
public static registerEditorComponents(type: string, public static getAvailableComponents(): EditorComponents[] {
components: EditorComponents) {
ComponentModelEditor.editorComponents.set(type, components); const components: EditorComponents[] = [];
for(let editorComponents
of ComponentModelEditor.editorComponents.values()) {
components.push(editorComponents);
}
components.sort((component1, component2) => {
return component1
.componentTitle
.localeCompare(component2.componentTitle);
});
return components;
}
public static registerEditorComponents(components: EditorComponents) {
ComponentModelEditor.editorComponents.set(components.componentType,
components);
} }
private static editorComponents: Map<string, EditorComponents> private static editorComponents: Map<string, EditorComponents>
@ -1162,6 +1348,8 @@ class ComponentModelEditor
.editorComponents.get(type) as EditorComponents; .editorComponents.get(type) as EditorComponents;
} else { } else {
const basicComponents: EditorComponents = { const basicComponents: EditorComponents = {
componentType: type,
componentTitle: "",
editorDialog: editorDialog:
BasicComponentModelEditorDialog as typeof React.Component, BasicComponentModelEditorDialog as typeof React.Component,
propertiesList: propertiesList: