@thepalaceproject/circulation-admin 0.0.5 → 0.0.8
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/CHANGELOG.md +14 -1
- package/README.md +31 -8
- package/dist/PalaceCollectionManagerLogo.svg +122 -0
- package/dist/circulation-admin.css +2 -1
- package/dist/circulation-admin.js +20 -20
- package/package.json +9 -6
- package/tests/browser/navigate.js +9 -9
- package/webpack.common.js +5 -0
- package/webpack.dev-server.config.js +187 -0
- package/webpack.dev.config.js +1 -1
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 --
|
|
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
|
|
27
|
+
"prod": "webpack --progress --config webpack.prod.config",
|
|
27
28
|
"build-docs": "typedoc --tsconfig tsconfig.json"
|
|
28
29
|
},
|
|
29
30
|
"dependencies": {
|
|
@@ -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",
|
|
@@ -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": "^
|
|
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.
|
|
117
|
+
"version": "0.0.8"
|
|
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("
|
|
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(`
|
|
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
|
+
};
|