* List of PageModels for the PageModelEditor
* Implementation of Bebop ContextBar for the PagesAdminPage


git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5463 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2018-05-31 13:13:48 +00:00
parent d20ff5f711
commit c0cc56f727
8 changed files with 244 additions and 51 deletions

View File

@ -65,14 +65,13 @@ public class WorkspaceContextBar extends ContextBar {
final ApplicationRepository appRepo = cdiUtil.findBean( final ApplicationRepository appRepo = cdiUtil.findBean(
ApplicationRepository.class); ApplicationRepository.class);
final List<CcmApplication> apps = appRepo.findByType( final List<CcmApplication> apps = appRepo.findByType(
CmsConstants.CONTENT_SECTION_APP_TYPE); CmsConstants.CONTENT_CENTER_APP_TYPE);
final String centerPath = apps.get(0).getPrimaryUrl(); final String centerPath = apps.get(0).getPrimaryUrl();
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Got Url: " + centerPath); LOGGER.debug("Got Url: " + centerPath);
} }
final URL url = URL.there(state.getRequest(), centerPath); final URL url = URL.there(state.getRequest(), centerPath);
entries.add(new Entry(centerTitle, url)); entries.add(new Entry(centerTitle, url));
return entries; return entries;

View File

@ -43,14 +43,12 @@ import com.arsdigita.cms.ui.CMSApplicationPage;
import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.toolbox.ui.LayoutPanel; import com.arsdigita.toolbox.ui.LayoutPanel;
import com.arsdigita.ui.ReactApp; import com.arsdigita.ui.ReactApp;
import com.arsdigita.ui.admin.AdminUiConstants;
import com.arsdigita.ui.admin.categories.CategoriesTreeModel; import com.arsdigita.ui.admin.categories.CategoriesTreeModel;
import com.arsdigita.util.LockableImpl; import com.arsdigita.util.LockableImpl;
import org.libreccm.categorization.Category; import org.libreccm.categorization.Category;
import org.libreccm.categorization.CategoryRepository; import org.libreccm.categorization.CategoryRepository;
import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.cdi.utils.CdiUtil;
import org.libreccm.core.CoreConstants;
import org.libreccm.core.UnexpectedErrorException; import org.libreccm.core.UnexpectedErrorException;
import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.pagemodel.PageModel; import org.libreccm.pagemodel.PageModel;
@ -84,6 +82,7 @@ public class PagesAdminPage extends CMSApplicationPage {
private final SaveCancelSection saveCancelSection; private final SaveCancelSection saveCancelSection;
private Pages pagesInstance; private Pages pagesInstance;
private PagesContextBar pagesContextBar;
public PagesAdminPage() { public PagesAdminPage() {
@ -160,8 +159,11 @@ public class PagesAdminPage extends CMSApplicationPage {
// "admin:pageModelsManager", AdminUiConstants.ADMIN_XML_NS); // "admin:pageModelsManager", AdminUiConstants.ADMIN_XML_NS);
// pageModelsManager.add(new Text("Placeholder page models editor")); // pageModelsManager.add(new Text("Placeholder page models editor"));
final ReactApp pageModelsManager = new ReactApp( final ReactApp pageModelsManager = new ReactApp(
"page-models-editor", "dist/ccm-pagemodelseditor.js"); "page-models-editor", "scripts/dist/ccm-cms.js");
pagesContextBar = new PagesContextBar();
super.add(pagesContextBar);
final TabbedPane tabbedPane = new TabbedPane(); final TabbedPane tabbedPane = new TabbedPane();
tabbedPane.addTab(new Label(new GlobalizedMessage( tabbedPane.addTab(new Label(new GlobalizedMessage(
"cms.ui.pages.tab.pages", CmsConstants.CMS_BUNDLE)), "cms.ui.pages.tab.pages", CmsConstants.CMS_BUNDLE)),
@ -183,6 +185,7 @@ public class PagesAdminPage extends CMSApplicationPage {
public void setPagesInstance(final Pages pagesInstance) { public void setPagesInstance(final Pages pagesInstance) {
this.pagesInstance = pagesInstance; this.pagesInstance = pagesInstance;
pagesContextBar.setPagesInstance(pagesInstance);
} }
// @Override // @Override

View File

@ -66,6 +66,9 @@ public class ReactApp extends SimpleComponent {
reactAppElem reactAppElem
.addAttribute("ccmApplication", primaryUrl); .addAttribute("ccmApplication", primaryUrl);
reactAppElem
.addAttribute("dispatcherPrefix", Web.getWebappContextPath());
} }
private String getPrimaryUrl() { private String getPrimaryUrl() {

View File

@ -1,6 +1,11 @@
import * as React from "react"; import * as React from "react";
import { PageModel, PageModelVersion } from "./datatypes";
export { PageModelEditor }; export {
PageModelEditor,
// PageModelEditorProps,
// PageModelEditorState,
};
/** /**
* To render the PageModelEditor create a Typescript file with the following * To render the PageModelEditor create a Typescript file with the following
@ -17,34 +22,154 @@ export { PageModelEditor };
* ); * );
*/ */
class PageModelEditor extends React.Component<{}, {}> { interface PageModelsListProps {
private getCcmApplication(): string { ccmApplication: string;
dispatcherPrefix: string;
}
const dataElem: HTMLElement | null = document interface PageModelsListState {
.querySelector("#page-models-editor.react-data");
if (dataElem === null) { errorMsg: string | null;
return "???"; pageModels: PageModel[];
} else { }
const value: string | null = dataElem.getAttribute("data-ccm-application");
if (value === null) { class PageModelsList
return "???"; extends React.Component<PageModelsListProps, PageModelsListState> {
} else {
return value; constructor(props: PageModelsListProps) {
} super(props);
}
this.state = {
errorMsg: null,
pageModels: [],
};
}
public componentDidMount() {
const init: RequestInit = {
credentials: "same-origin",
method: "GET",
};
const url: string = `${this.props.dispatcherPrefix}`
+ `/page-models/${this.props.ccmApplication}`;
fetch(url, init)
.then((response: Response) => {
if (response.ok) {
response
.json()
.then((pageModels: PageModel[]) => {
this.setState({
...this.state,
pageModels,
});
})
.catch((error) => {
this.setState({
...this.state,
errorMsg: `Failed to retrieve PageModels from `
+ `${url}: ${error.message}`,
});
});
} else {
this.setState({
...this.state,
errorMsg: `Failed to retrieve PageModels from `
+ `\"${url}\": HTTP Status Code: `
+ `${response.status}; `
+ `message: ${response.statusText}`,
});
}
})
.catch((error) => {
this.setState({
...this.state,
errorMsg: `Failed to retrieve PageModels from `
+ `${url}: ${error.message}`,
});
});
} }
public render() { public render() {
return <div className="pageModelsList">
{this.state.errorMsg !== null &&
<div className="errorPanel">
{this.state.errorMsg}
</div>
}
{this.state.pageModels.length > 0 &&
<ul>
{this.state.pageModels.map((pageModel: PageModel) =>
<PageModelListItem pageModel={pageModel} />,
)}
</ul>
}
</div>;
}
}
interface PageModelListItemProps {
pageModel: PageModel;
}
// interface PageModelListItemState {
//
// }
class PageModelListItem
extends React.Component<PageModelListItemProps, {}> {
public render() {
return <li>
<a>
{this.props.pageModel.title}
</a>
</li>;
}
}
// interface PageModelEditorProps {
//
// }
//
// interface PageModelEditorState {
//
// }
class PageModelEditor
extends React.Component<{}, {}> {
public render() {
return <React.Fragment> return <React.Fragment>
<div id="left"> <div id="left">
<div className="column-head"></div> <div className="column-head"></div>
<div className="column-content"> <div className="column-content">
List of available page models placeholder <div className="bebop-left">
<div className="bebop-segmented-panel">
<div className="bebop-segment">
<h3 className="bebop-segment-header">
Available PageModels
</h3>
<div className="bebop-segment-body">
<button className="pagemodels addbutton">
<span>+</span> Create new PageModel
</button>
<PageModelsList
ccmApplication={this.getCcmApplication()}
dispatcherPrefix={this
.getDispatcherPrefix()} />
<button className="pagemodels addbutton">
<span>+</span> Create new PageModel
</button>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
<div id="right"> <div id="right">
@ -59,4 +184,40 @@ class PageModelEditor extends React.Component<{}, {}> {
</div> </div>
</React.Fragment>; </React.Fragment>;
} }
private getDispatcherPrefix(): string {
const dataElem: HTMLElement | null = document
.querySelector("#page-models-editor.react-data");
if (dataElem === null) {
return "";
} else {
const value: string | null
= dataElem.getAttribute("data-dispatcher-prefix");
if (value === null) {
return "";
} else {
return value;
}
}
}
private getCcmApplication(): string {
const dataElem: HTMLElement | null = document
.querySelector("#page-models-editor.react-data");
if (dataElem === null) {
return "???";
} else {
const value: string | null
= dataElem.getAttribute("data-ccm-application");
if (value === null) {
return "???";
} else {
return value;
}
}
}
} }

View File

@ -0,0 +1,19 @@
export { PageModel, PageModelVersion };
interface PageModel {
description: string;
modelUuid: string;
name: string;
pageModelId: number;
title: string;
type: string;
uuid: string;
version: PageModelVersion;
}
enum PageModelVersion {
DRAFT,
LIVE,
}

View File

@ -1,26 +0,0 @@
const path = require('path');
module.exports = {
devtool: "inline-source-map",
entry: {
pagemodeleditor: "./src/main/typescript/ccm-pagemodelseditor/index.tsx"
},
output: {
//path: path.resolve(__dirname, "src/main/resources/dist"),
path: path.resolve(__dirname, "target/generated-resources/dist"),
filename: "ccm-pagemodelseditor.js"
},
resolve: {
extensions: [".webpack.js", "web.js", ".ts", ".tsx", ".js"]
},
module: {
rules: [
{ test: /\.tsx?$/, loader: "ts-loader"}
]
}
};

View File

@ -167,11 +167,12 @@
<xsl:template match="load-react-app"> <xsl:template match="load-react-app">
<xsl:if test="$data-tree//bebop:reactApp"> <xsl:if test="$data-tree//bebop:reactApp">
<div class="react-data" <div class="react-data"
id="{$data-tree//bebop:reactApp/@appId}" id="{$data-tree//bebop:reactApp/@appId}"
data-ccm-application="{$data-tree//bebop:reactApp/@ccmApplication}"> data-ccm-application="{$data-tree//bebop:reactApp/@ccmApplication}"
data-dispatcher-prefix="{$data-tree//bebop:reactApp/@dispatcherPrefix}">
</div> </div>
<script src="{$data-tree//bebop:reactApp/@scriptPath}"></script> <script src="{$data-tree//bebop:reactApp/@scriptPath}"></script>
</xsl:if> </xsl:if>
</xsl:template> </xsl:template>
</xsl:stylesheet> </xsl:stylesheet>

View File

@ -1093,7 +1093,7 @@ div.bebop-segment {
} }
#left div.bebop-segment-body { #left div.bebop-segment-body {
padding-left: 10px; padding: 10px;
} }
div.bebop-left div.bebop-panel-row { div.bebop-left div.bebop-panel-row {
@ -1976,4 +1976,37 @@ span#quickLinksCascade {
.preformatted-text { .preformatted-text {
white-space: pre; white-space: pre;
}
button.pagemodels.addbutton {
border: none;
border-radius: 0.25em;
background-color: #383838;
color: #fff;
padding: 0.2em 0.33em;
}
button.pagemodels.addbutton > span {
border-right: 1px solid #eee;
font-weight: bold;
padding-right: 0.2em;
}
div.pageModelsList {
margin-top: 0.66em;
margin-bottom: 0.66em;
border-top: 1px solid #0776A0;
padding-top: 0.66em;
border-bottom: 1px solid #0776A0;
padding-bottom: 0.66em;
} }