Integration of Vue.js now working

Former-commit-id: 982f4f1fd5
restapi
Jens Pelzetter 2020-08-27 20:48:00 +02:00
parent dfe36e2614
commit 46ea2de206
14 changed files with 172 additions and 49 deletions

View File

@ -245,6 +245,9 @@
<configuration>
<skip>false</skip>
<propertiesFile>${project.basedir}/wildfly.properties</propertiesFile>
<java-opts>
<java-opt>-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8787</java-opt>
</java-opts>
</configuration>
</plugin>

View File

@ -101,5 +101,10 @@
<Logger name="com.arsdigita.web.DefaultApplicationFileResolver"
level="debug">
</Logger>
<Logger name="org.libreccm.ui.admin.AdminUi"
level="debug">
</Logger>
</Loggers>
</Configuration>

View File

@ -1142,6 +1142,16 @@
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
"dev": true
},
"@nuxt/opencollective": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.3.0.tgz",
"integrity": "sha512-Vf09BxCdj1iT2IRqVwX5snaY2WCTkvM0O4cWWSO1ThCFuc4if0Q/nNwAgCxRU0FeYHJ7DdyMUNSdswCLKlVqeg==",
"requires": {
"chalk": "^2.4.2",
"consola": "^2.10.1",
"node-fetch": "^2.6.0"
}
},
"@soda/friendly-errors-webpack-plugin": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.1.tgz",
@ -2446,7 +2456,6 @@
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
@ -2973,6 +2982,23 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
"dev": true
},
"bootstrap": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.2.tgz",
"integrity": "sha512-vlGn0bcySYl/iV+BGA544JkkZP5LB3jsmkeKLFQakCOwCM3AOk7VkldBz4jrzSe+Z0Ezn99NVXa1o45cQY4R6A=="
},
"bootstrap-vue": {
"version": "2.16.0",
"resolved": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-2.16.0.tgz",
"integrity": "sha512-gLETwPmeRHCe5WHmhGxzb5PtTEuKqQPGl0TFvZ2Odbkg/7UuIHdqIexrJRerpnomP4ZzDQ+qYGL91Ls9lcQsJQ==",
"requires": {
"@nuxt/opencollective": "^0.3.0",
"bootstrap": ">=4.5.0 <5.0.0",
"popper.js": "^1.16.1",
"portal-vue": "^2.1.7",
"vue-functional-data-merge": "^3.1.0"
}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -3414,7 +3440,6 @@
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
@ -3739,7 +3764,6 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
@ -3747,8 +3771,7 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"color-string": {
"version": "1.5.3",
@ -3864,6 +3887,11 @@
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
"dev": true
},
"consola": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz",
"integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ=="
},
"console-browserify": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
@ -5103,8 +5131,7 @@
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"eslint": {
"version": "6.8.0",
@ -6311,8 +6338,7 @@
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"has-symbols": {
"version": "1.0.1",
@ -8175,6 +8201,11 @@
"lower-case": "^1.1.1"
}
},
"node-fetch": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
},
"node-forge": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz",
@ -8971,6 +9002,16 @@
"ts-pnp": "^1.1.6"
}
},
"popper.js": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
},
"portal-vue": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/portal-vue/-/portal-vue-2.1.7.tgz",
"integrity": "sha512-+yCno2oB3xA7irTt0EU5Ezw22L2J51uKAacE/6hMPMoO/mx3h4rXFkkBkT4GFsMDv/vEe8TNKC3ujJJ0PTwb6g=="
},
"portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@ -11336,7 +11377,6 @@
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
@ -12187,6 +12227,11 @@
}
}
},
"vue-functional-data-merge": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-3.1.0.tgz",
"integrity": "sha512-leT4kdJVQyeZNY1kmnS1xiUlQ9z1B/kdBFCILIjYYQDqZgLqCLa0UhjSSeRX6c3mUe6U5qYeM8LrEqkHJ1B4LA=="
},
"vue-hot-reload-api": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",

View File

@ -8,6 +8,8 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"bootstrap": "^4.5.2",
"bootstrap-vue": "^2.16.0",
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-class-component": "^7.2.3",
@ -36,7 +38,8 @@
"vue-template-compiler": "^2.6.11"
},
"vue": {
"filenameHashing": false
"filenameHashing": false,
"publicPath": "./"
},
"eslintConfig": {
"root": true,

View File

@ -3,10 +3,18 @@ import App from "./App.vue";
import router from "./router";
import store from "./store";
import { BootstrapVue, IconsPlugin } from "bootstrap-vue";
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.config.productionTip = false;
Vue.use(BootstrapVue);
Vue.use(IconsPlugin);
new Vue({
router,
store,
render: h => h(App)
render: h => h(App),
}).$mount("#app");

View File

@ -1,6 +1,7 @@
import Vue from "vue";
import VueRouter, { RouteConfig } from "vue-router";
import Home from "../views/Home.vue";
import About from "../views/About.vue";
Vue.use(VueRouter);
@ -16,13 +17,12 @@ const routes: Array<RouteConfig> = [
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/About.vue")
component: About
}
];
const router = new VueRouter({
mode: "history",
mode: "hash",
base: process.env.BASE_URL,
routes
});

View File

@ -1,5 +1,17 @@
<template>
<div class="home">
<b-navbar toggleable="lg" type="dark" variant="info">
<b-navbar-brand href="#">LibreCCM</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-item href="#">Link 1</b-nav-item>
<b-nav-item href="#">Link 2</b-nav-item>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<img alt="Vue logo" src="../assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
</div>
@ -11,8 +23,8 @@ import HelloWorld from "@/components/HelloWorld.vue"; // @ is an alias to /src
@Component({
components: {
HelloWorld
}
HelloWorld,
},
})
export default class Home extends Vue {}
</script>

View File

@ -26,10 +26,13 @@ import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.security.Shiro;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
@ -42,11 +45,12 @@ import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.RedirectionException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
/**
*
@ -56,6 +60,8 @@ import javax.ws.rs.core.UriBuilder;
@Path("/")
public class AdminUi {
private static final Logger LOGGER = LogManager.getLogger(AdminUi.class);
@Inject
private AdminUiApps adminUiApps;
@ -94,8 +100,8 @@ public class AdminUi {
@Produces(MediaType.TEXT_HTML)
// @AuthorizationRequired
// @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
public String getDashboard() {
return getApp("dashboard");
public Response getDashboard(@Context final UriInfo uriInfo) {
return getApp("dashboard", uriInfo);
}
@GET
@ -103,17 +109,32 @@ public class AdminUi {
@Produces(MediaType.TEXT_HTML)
// @AuthorizationRequired
// @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
public String getApp(@PathParam("appName") final String appName) {
public Response getApp(
@PathParam("appName") final String appName,
@Context UriInfo uriInfo
) {
if (!shiro.getUser().isPresent()
|| !shiro.getSubject().isAuthenticated()) {
final UriBuilder uriBuilder = UriBuilder.fromUri("/ccm/register");
uriBuilder.queryParam(
final URI uri = UriBuilder
.fromUri(
String.format(
"%s://%s:%d%s/ccm/register",
uriInfo.getBaseUri().getScheme(),
uriInfo.getBaseUri().getHost(),
uriInfo.getBaseUri().getPort(),
servletContext.getContextPath()
)
)
.queryParam(
"return_url",
String.format("%s/@admin", servletContext.getContextPath())
);
throw new RedirectionException(
Response.Status.TEMPORARY_REDIRECT, uriBuilder.build()
);
String.format(
"%s/@admin/%s",
servletContext.getContextPath(),
appName
)
).build();
LOGGER.debug("Redirecting to {}...", uri.toString());
return Response.temporaryRedirect(uri).build();
}
final AdminUiApp app = adminUiApps
@ -141,6 +162,7 @@ public class AdminUi {
data.put("adminUiApps", adminUiApps.getAdminUiApps());
data.put("activeApp", app);
data.put("currentUser", shiro.getUser().get());
data.put("contextPath", servletContext.getContextPath());
final StringWriter writer = new StringWriter();
try {
@ -153,7 +175,7 @@ public class AdminUi {
);
}
return writer.toString();
return Response.ok(writer.toString()).build();
}
}

View File

@ -31,7 +31,7 @@ public interface AdminUiApp {
*
* @return
*/
String getName();
String getSlug();
/**
* Localized label for the application

View File

@ -39,7 +39,7 @@ public class AdminUiApps {
public Optional<AdminUiApp> getAdminUiApp(final String name) {
return adminUiApps
.stream()
.filter(app -> app.getName().equals(name))
.filter(app -> app.getSlug().equals(name))
.findAny();
}

View File

@ -42,12 +42,13 @@ public class DashboardApp implements AdminUiApp {
@PostConstruct
private void init() {
adminBundle = ResourceBundle.getBundle(
"org.libreccm.ui.admin", globalizationHelper.getNegotiatedLocale()
"org.libreccm.ui.admin",
globalizationHelper.getNegotiatedLocale()
);
}
@Override
public String getName() {
public String getSlug() {
return "dashboard";
}

View File

@ -47,7 +47,7 @@ public class SystemInformationApp implements AdminUiApp {
}
@Override
public String getName() {
public String getSlug() {
return "systeminformation";
}
@ -69,14 +69,17 @@ public class SystemInformationApp implements AdminUiApp {
@Override
public String[] getJsFilesUrls() {
return new String[]{
"/@admin/systeminformation/js/app.js",
"/@admin/systeminformation/js/chunk-vendors.js",};
"/_admin/systeminformation/js/chunk-vendors.js",
"/_admin/systeminformation/js/app.js"
};
}
@Override
public String[] getCssFilesUrls() {
return new String[]{
"/@admin/systeminformation/css/app.css",};
"/_admin/systeminformation/css/chunk-vendors.css",
"/_admin/systeminformation/css/app.css"
};
}
@Override

View File

@ -1,19 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<title>Admin UI</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<!-- ToDo: Favicon link rel="icon" href="<%= BASE_URL %>favicon.ico"> -->
<#list activeApp.cssFilesUrls as cssFile>
<link href="${contextPath}${cssFile}" rel="preload" as="style">
</#list>
<#list activeApp.jsFilesUrls as jsFile>
<link href="${contextPath}${jsFile}" rel="preload" as="script">
</#list>
<#list activeApp.cssFilesUrls as cssFile>
<link rel="stylesheet" href="${contextPath}${cssFile}">
</#list>
<title>LibreCCM - ${activeApp.label}</title>
</head>
<body>
<div id="app"></div>
<#list activeApp.jsFilesUrls as jsFile>
<script src="${contextPath}${jsFile}"></script>
</#list>
<!--
<h1>Admin UI</h1>
<p>
Current user ${currentUser.name}
</p>
<ul>
<#list adminUiApps as app>
<li>
<dl>
<dt>Name</dt>
<dd>${app.name}</dd>
<dd>${app.slug}</dd>
<dt>Label</dt>
<dd>${app.label}</dd>
<dt>Description</dt>
@ -56,5 +76,6 @@
</li>
</#list>
</ul>
-->
</body>
</html>