@thepalaceproject/circulation-admin 0.0.3 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -15,15 +15,16 @@
15
15
  "scripts": {
16
16
  "prepublish": "npm run prod",
17
17
  "lint": "tslint -c tslint.json src/*.ts src/*.tsx src/**/*.ts src/**/*.tsx src/**/**/*.ts src/**/**/*.tsx && sass-lint -c .sass-lint.yml -v -q",
18
- "test": "npm run lint && tsc && cp -r src/stylesheets lib && mocha --require lib/testHelper.js lib/__tests__/*.js lib/**/__tests__/*.js lib/**/**/__tests__/*.js",
18
+ "test": "npm run lint && tsc && cp -r src/stylesheets lib && cp -r src/images lib && mocha --require lib/testHelper.js lib/__tests__/*.js lib/**/__tests__/*.js lib/**/**/__tests__/*.js",
19
19
  "test-list": "mocha --require lib/testHelper.js lib/__tests__/*.js lib/**/__tests__/*.js lib/**/**/__tests__/*.js --reporter ./testReporter.js",
20
- "test-file": "npm run lint && tsc && cp -r src/stylesheets lib && mocha --require lib/testHelper.js",
20
+ "test-file": "npm run lint && tsc && cp -r src/stylesheets lib && cp -r src/images lib && mocha --require lib/testHelper.js",
21
21
  "test-browser": "npm run test-chrome && npm run test-firefox",
22
22
  "test-chrome": "node_modules/.bin/selenium-standalone install && nightwatch -e chrome",
23
23
  "test-firefox": "node_modules/.bin/selenium-standalone install && nightwatch -e firefox",
24
- "dev": "webpack --watch --progress --display-modules --config webpack.dev.config",
24
+ "dev": "webpack --watch --progress --config webpack.dev.config",
25
+ "dev-server": "webpack serve --progress --hot --config webpack.dev-server.config",
25
26
  "dev-test-axe": "TEST_AXE=true npm run dev",
26
- "prod": "webpack -p --progress --display-modules --config webpack.prod.config",
27
+ "prod": "webpack --progress --config webpack.prod.config",
27
28
  "build-docs": "typedoc --tsconfig tsconfig.json"
28
29
  },
29
30
  "dependencies": {
@@ -36,7 +37,7 @@
36
37
  "library-simplified-reusable-components": "1.3.18",
37
38
  "numeral": "^2.0.6",
38
39
  "opds-feed-parser": "0.0.17",
39
- "opds-web-client": "^0.6.2",
40
+ "opds-web-client": "0.6.3",
40
41
  "prop-types": "^15.7.2",
41
42
  "qs": "^6.2.0",
42
43
  "react": "^16.8.6",
@@ -62,6 +63,7 @@
62
63
  "chai": "4.2.0",
63
64
  "clean-webpack-plugin": "^2.0.1",
64
65
  "colors-cli": "^1.0.27",
66
+ "copy-webpack-plugin": "6.4.0",
65
67
  "css-loader": "^5.2.4",
66
68
  "enzyme": "^3.9.0",
67
69
  "enzyme-adapter-react-16": "^1.12.1",
@@ -81,11 +83,11 @@
81
83
  "mini-css-extract-plugin": "1.6.0",
82
84
  "mocha": "^6.2.2",
83
85
  "nightwatch": "^1.0.19",
84
- "node-sass": "^4.14.1",
86
+ "node-sass": "^6.0.1",
85
87
  "prettier": "2.1.2",
86
88
  "react-axe": "^3.3.0",
87
89
  "sass-lint": "^1.13.1",
88
- "sass-loader": "^7.1.0",
90
+ "sass-loader": "^10.0.0",
89
91
  "selenium-standalone": "^6.16.0",
90
92
  "sinon": "7.5.0",
91
93
  "style-loader": "^0.13.1",
@@ -98,7 +100,8 @@
98
100
  "uglifyjs-webpack-plugin": "^2.2.0",
99
101
  "url-loader": "2.2.0",
100
102
  "webpack": "^4.29.6",
101
- "webpack-cli": "^3.3.0",
103
+ "webpack-cli": "^4.9.0",
104
+ "webpack-dev-server": "^4.3.1",
102
105
  "webpack-merge": "^4.2.1"
103
106
  },
104
107
  "husky": {
@@ -111,5 +114,5 @@
111
114
  "*.{js,jsx,ts,tsx,css,md}": "prettier --write",
112
115
  "*.{js,css,md}": "prettier --write"
113
116
  },
114
- "version": "0.0.3"
117
+ "version": "0.0.7"
115
118
  }
@@ -110,23 +110,23 @@ module.exports = {
110
110
  .verify.noError()
111
111
  .verify.urlEquals(bookUrl)
112
112
  .verify.containsText(bookTitleSelector, bookTitle)
113
-
113
+
114
114
  // go to the edit tab
115
115
  .click(editTabSelector)
116
116
  .waitForElementPresent(titleInputSelector, 5000)
117
117
  .verify.urlContains("tab/edit")
118
118
  .verify.value(titleInputSelector, bookTitle)
119
-
119
+
120
120
  // go to the classifications tab
121
121
  .click(classificationsTabSelector)
122
122
  .waitForElementPresent(genreInputSelector, 5000)
123
123
  .verify.urlContains("tab/classifications")
124
-
124
+
125
125
  // go to the image cover tab
126
126
  .click(coverTabSelector)
127
127
  .waitForElementPresent(coverInputSelector, 5000)
128
128
  .verify.urlContains("tab/cover")
129
-
129
+
130
130
  // go to the complaints tab
131
131
  .click(complaintsTabSelector)
132
132
  .waitForElementPresent(complaintInputSelector, 5000)
@@ -140,7 +140,7 @@ module.exports = {
140
140
  .click(listsTabSelector)
141
141
  .waitForElementPresent(listInputSelector, 5000)
142
142
  .verify.urlContains("tab/list")
143
-
143
+
144
144
  // go back to the complaints tab
145
145
  .back()
146
146
  // go back to the cover tab
@@ -217,7 +217,7 @@ module.exports = {
217
217
  circulationAllStatsSelector,
218
218
  } = catalogPage.elements;
219
219
  const { nthBreadcrumbSelector } = catalogPage;
220
-
220
+
221
221
  browser
222
222
  .goHome()
223
223
  .getAttribute(nthBreadcrumbSelector(1), "title", function(result) {
@@ -233,7 +233,7 @@ module.exports = {
233
233
  .assert.noError()
234
234
  .verify.elementPresent(circulationLibraryStatsSelector)
235
235
  .verify.elementPresent(circulationAllStatsSelector)
236
- .verify.titleContains("Circulation Manager - Dashboard")
236
+ .verify.titleContains("Palace Collection Manager - Dashboard")
237
237
 
238
238
  // click the main navigation link
239
239
  .click(catalogSelector)
@@ -241,7 +241,7 @@ module.exports = {
241
241
  .assert.noError()
242
242
  .verify.elementPresent(nthBreadcrumbSelector(1))
243
243
  .verify.urlEquals(catalogUrl)
244
- .verify.titleContains(`Circulation Manager - ${libraryName}`);
244
+ .verify.titleContains(`Palace Collection Manager - ${libraryName}`);
245
245
  });
246
246
  });
247
247
  });
@@ -291,4 +291,4 @@ module.exports = {
291
291
  after: (browser) => {
292
292
  browser.end();
293
293
  }
294
- };
294
+ };
package/webpack.common.js CHANGED
@@ -5,6 +5,7 @@ const webpack = require("webpack");
5
5
  const MiniCssExtractPlugin = require("mini-css-extract-plugin");
6
6
  const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
7
7
  const TerserPlugin = require("terser-webpack-plugin");
8
+ const CopyPlugin = require("copy-webpack-plugin");
8
9
  /* eslint-enable @typescript-eslint/no-var-requires */
9
10
 
10
11
  module.exports = {
@@ -29,6 +30,10 @@ module.exports = {
29
30
  new webpack.DefinePlugin({
30
31
  "process.env.TEST_AXE": JSON.stringify(process.env.TEST_AXE),
31
32
  }),
33
+ // Publish the logo to dist.
34
+ new CopyPlugin({
35
+ patterns: ["src/images/PalaceCollectionManagerLogo.svg"],
36
+ }),
32
37
  ],
33
38
  optimization: {
34
39
  minimizer: [new TerserPlugin({ terserOptions: { compress: false } })],
@@ -0,0 +1,187 @@
1
+ /* eslint-disable @typescript-eslint/no-var-requires */
2
+
3
+ /**
4
+ * This webpack config establishes a proxy server to enable a local build of circulation-admin to
5
+ * connect to a remote Circulation Manager back-end. Requests for webpack assets are served from
6
+ * memory; other requests are proxied to the specified Circulation Manager.
7
+ *
8
+ * Usage:
9
+ * npm run dev-server -- --env=backend=https://gorgon.tpp-qa.lyrasistechnology.org
10
+ * or
11
+ * npx webpack serve --config webpack.dev-server.config --env=backend=https://gorgon.tpp-qa.lyrasistechnology.org
12
+ *
13
+ * This makes the circulation-admin webapp available at http://localhost:8080/admin.
14
+ */
15
+
16
+ const {
17
+ createProxyMiddleware,
18
+ responseInterceptor,
19
+ } = require("http-proxy-middleware");
20
+
21
+ const merge = require("webpack-merge");
22
+ const { URL } = require("url");
23
+ const dev = require("./webpack.dev.config.js");
24
+
25
+ /**
26
+ * The public path to local webpack assets. This is chosen to have low chance of collision with any
27
+ * path on the back-end (e.g., a library ID, or "/admin"). This should start and end with slashes.
28
+ */
29
+ const devAssetsPublicPath = "/webpack-dev-assets/";
30
+
31
+ /**
32
+ * Build the webpack configuration.
33
+ * See https://webpack.js.org/configuration/configuration-types/#exporting-a-function
34
+ *
35
+ * @param {object} env The environment.
36
+ * @returns The webpack configuration.
37
+ */
38
+ module.exports = (env) => {
39
+ const { backend } = env;
40
+
41
+ if (!backend) {
42
+ console.error("Please specify the URL of a Circulation Manager back-end.");
43
+
44
+ console.error(
45
+ "Example: npm run dev-server -- --env=backend=https://gorgon.tpp-qa.lyrasistechnology.org"
46
+ );
47
+
48
+ throw "No back-end URL was specified.";
49
+ }
50
+
51
+ console.info(`Using Circulation Manager back-end: ${backend}`);
52
+
53
+ const backendUrl = new URL(backend);
54
+
55
+ /**
56
+ * Rewrite a location header (as received in a 3xx response). This changes back-end URLs to
57
+ * point to the local server instead. The CM may redirect to a URL that contains a "redirect"
58
+ * parameter that contains another URL. The "redirect" parameter is also rewritten.
59
+ *
60
+ * @param res The response.
61
+ * @param req The request.
62
+ */
63
+ const rewriteLocationHeader = (res, req) => {
64
+ const location = res.getHeader("location");
65
+
66
+ if (!location) {
67
+ return;
68
+ }
69
+
70
+ const locationUrl = new URL(location);
71
+
72
+ if (locationUrl.host !== backendUrl.host) {
73
+ return;
74
+ }
75
+
76
+ const requestHost = req.headers.host;
77
+
78
+ if (!requestHost) {
79
+ return;
80
+ }
81
+
82
+ locationUrl.protocol = "http";
83
+ locationUrl.host = requestHost;
84
+
85
+ const redirectParam = locationUrl.searchParams.get("redirect");
86
+
87
+ if (redirectParam) {
88
+ const redirectUrl = new URL(redirectParam);
89
+
90
+ if (redirectUrl.host == backendUrl.host) {
91
+ redirectUrl.protocol = "http";
92
+ redirectUrl.host = requestHost;
93
+
94
+ locationUrl.searchParams.set("redirect", redirectUrl.href);
95
+ }
96
+ }
97
+
98
+ res.setHeader("location", locationUrl.href);
99
+ };
100
+
101
+ /**
102
+ * Rewrites an OPDS response. This changes back-end URLs in the feed to point to the local server
103
+ * instead. This is a simple find-and-replace.
104
+ *
105
+ * @param responseBuffer A buffer containing the response body.
106
+ * @param req The request.
107
+ * @returns
108
+ */
109
+ const rewriteOPDS = (responseBuffer, req) => {
110
+ const requestHost = req.headers.host;
111
+
112
+ if (!requestHost) {
113
+ return responseBuffer;
114
+ }
115
+
116
+ const feed = responseBuffer.toString("utf8");
117
+
118
+ return feed.replace(
119
+ new RegExp(backendUrl.origin, "g"),
120
+ `http://${requestHost}`
121
+ );
122
+ };
123
+
124
+ /**
125
+ * Rewrites an HTML response. This changes jsdelivr CDN URLs in the page to point to the webpack
126
+ * assets on the local server instead. This is a simple find-and-replace.
127
+ *
128
+ * @param responseBuffer A buffer containing the response body.
129
+ * @param req The request.
130
+ * @returns
131
+ */
132
+ const rewriteHTML = (responseBuffer, req) => {
133
+ const requestHost = req.headers.host;
134
+
135
+ if (!requestHost) {
136
+ return responseBuffer;
137
+ }
138
+
139
+ const page = responseBuffer.toString("utf8");
140
+ const packageName = process.env.npm_package_name;
141
+ const cdnUrlPattern = `"https://cdn.jsdelivr.net/npm/${packageName}(@.*?)?/dist/(.*?)"`;
142
+
143
+ return page.replace(
144
+ new RegExp(cdnUrlPattern, "g"),
145
+ `"http://${requestHost}${devAssetsPublicPath}$2"`
146
+ );
147
+ };
148
+
149
+ const proxyMiddleware = createProxyMiddleware({
150
+ changeOrigin: true,
151
+ onProxyRes: responseInterceptor(
152
+ async (responseBuffer, proxyRes, req, res) => {
153
+ rewriteLocationHeader(res, req);
154
+
155
+ const contentType = res.getHeader("content-type");
156
+
157
+ if (contentType.startsWith("application/atom+xml")) {
158
+ return rewriteOPDS(responseBuffer, req);
159
+ }
160
+
161
+ if (contentType.startsWith("text/html")) {
162
+ return rewriteHTML(responseBuffer, req);
163
+ }
164
+
165
+ return responseBuffer;
166
+ }
167
+ ),
168
+ proxyTimeout: 5000,
169
+ secure: false,
170
+ selfHandleResponse: true,
171
+ target: backend,
172
+ timeout: 5000,
173
+ });
174
+
175
+ const config = merge(dev, {
176
+ devServer: {
177
+ onAfterSetupMiddleware: (devServer) => {
178
+ devServer.app.use("/", proxyMiddleware);
179
+ },
180
+ },
181
+ output: {
182
+ publicPath: devAssetsPublicPath,
183
+ },
184
+ });
185
+
186
+ return config;
187
+ };
@@ -3,7 +3,7 @@ const common = require('./webpack.common.js');
3
3
 
4
4
  var config = merge(common, {
5
5
  mode: "development",
6
- devtool: "inline-source-map",
6
+ devtool: "eval-source-map",
7
7
  });
8
8
 
9
9
  module.exports = config;