fix: missing logo on header (#3636)

This commit is contained in:
Juan Picado 2023-02-19 11:43:28 +01:00 committed by GitHub
parent 3dc0fd41f4
commit 4fc21146ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 128 additions and 40 deletions

View File

@ -0,0 +1,8 @@
---
'@verdaccio/types': patch
'@verdaccio/middleware': patch
'@verdaccio/ui-theme': patch
'@verdaccio/web': patch
---
fix: missing logo on header

View File

@ -128,7 +128,6 @@ export type TemplateUIOptions = {
base: string;
primaryColor: string;
version?: string;
logoURI?: string;
flags: FlagsConfig;
} & CommonWebConf;

View File

@ -7,7 +7,7 @@ import { HTTP_STATUS } from '@verdaccio/core';
import { isURLhasValidProtocol } from '@verdaccio/url';
import { setSecurityWebHeaders } from './security';
import renderHTML, { isHTTPProtocol } from './utils/renderHTML';
import renderHTML from './utils/renderHTML';
const debug = buildDebug('verdaccio:web:render');
@ -31,23 +31,10 @@ export function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
if (typeof tokenMiddleware === 'function') {
router.use(tokenMiddleware);
}
router.use(setSecurityWebHeaders);
// Logo
let logoURI = config?.web?.logo ?? '';
if (logoURI && !isURLhasValidProtocol(logoURI)) {
// URI related to a local file
// Note: `path.join` will break on Windows, because it transforms `/` to `\`
// Use POSIX version `path.posix.join` instead.
logoURI = path.posix.join('/-/static/', path.basename(logoURI));
router.get(logoURI, function (req, res, next) {
res.sendFile(path.resolve(config.web.logo), sendFileCallback(next));
debug('render static');
});
}
// Static
// any match within the static is routed to the file system
router.get('/-/static/*', function (req, res, next) {
const filename = req.params[0];
const file = `${staticPath}/${filename}`;
@ -55,13 +42,13 @@ export function renderWebMiddleware(config, tokenMiddleware, pluginOptions) {
res.sendFile(file, sendFileCallback(next));
});
// logo
if (config?.web?.logo && !isHTTPProtocol(config?.web?.logo)) {
// check the origin of the logo
if (config?.web?.logo && !isURLhasValidProtocol(config?.web?.logo)) {
// URI related to a local file
const absoluteLocalFile = path.posix.resolve(config.web.logo);
debug('serve local logo %s', absoluteLocalFile);
try {
// TODO: remove existsSync by async alternative
// TODO: replace existsSync by async alternative
if (
fs.existsSync(absoluteLocalFile) &&
typeof fs.accessSync(absoluteLocalFile, fs.constants.R_OK) === 'undefined'

View File

@ -6,6 +6,7 @@ import { URL } from 'url';
import { WEB_TITLE } from '@verdaccio/config';
import { HEADERS } from '@verdaccio/core';
import { TemplateUIOptions } from '@verdaccio/types';
import { isURLhasValidProtocol } from '@verdaccio/url';
import { getPublicUrl } from '@verdaccio/url';
import renderTemplate from './template';
@ -21,20 +22,12 @@ const defaultManifestFiles = {
ico: 'favicon.ico',
};
/**
* Check if URI is starting with "http://", "https://" or "//"
* @param {string} uri
*/
export function isHTTPProtocol(uri: string): boolean {
return /^(https?:)?\/\//.test(uri);
}
export function resolveLogo(config, req) {
const isLocalFile = config?.web?.logo && !isHTTPProtocol(config?.web?.logo);
const isLocalFile = config?.web?.logo && !isURLhasValidProtocol(config?.web?.logo);
if (isLocalFile) {
return `${getPublicUrl(config?.url_prefix, req)}-/static/${path.basename(config?.web?.logo)}`;
} else if (isHTTPProtocol(config?.web?.logo)) {
} else if (isURLhasValidProtocol(config?.web?.logo)) {
return config?.web?.logo;
} else {
return '';
@ -53,7 +46,7 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
const title = config?.web?.title ?? WEB_TITLE;
const login = hasLogin(config);
const scope = config?.web?.scope ?? '';
const logoURI = resolveLogo(config, req);
const logo = resolveLogo(config, req);
const pkgManagers = config?.web?.pkgManagers ?? ['yarn', 'pnpm', 'npm'];
const version = config?.web?.version;
const flags = {
@ -94,7 +87,7 @@ export default function renderHTML(config, manifest, manifestFiles, req, res) {
base,
primaryColor,
version,
logoURI,
logo,
flags,
login,
pkgManagers,

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,24 @@
web:
title: verdaccio web
login: true
scope: '@scope'
pkgManagers:
- pnpm
- yarn
showInfo: true
showSettings: true
showSearch: true
showFooter: true
showThemeSwitch: true
showDownloadTarball: true
showRaw: true
primary_color: '#ffffff'
logo: './test/config/dark-logo.png'
html_cache: false
url_prefix: /prefix
log: { type: stdout, format: pretty, level: trace }
flags:
changePassword: true

View File

@ -8,6 +8,7 @@ auth:
web:
title: verdaccio
login: false
html_cache: false
publish:
allow_offline: false

View File

@ -0,0 +1,24 @@
web:
title: verdaccio web
login: true
scope: '@scope'
pkgManagers:
- pnpm
- yarn
showInfo: true
showSettings: true
showSearch: true
showFooter: true
showThemeSwitch: true
showDownloadTarball: true
showRaw: true
primary_color: '#ffffff'
logo:
html_cache: false
url_prefix: /prefix
log: { type: stdout, format: pretty, level: trace }
flags:
changePassword: true

View File

@ -13,7 +13,8 @@ web:
showDownloadTarball: true
showRaw: true
primary_color: '#ffffff'
logoURI: 'http://logo.org/logo.png'
logo: 'http://logo.org/logo.png'
html_cache: false
url_prefix: /prefix

View File

@ -0,0 +1,24 @@
web:
title: verdaccio web
login: true
scope: '@scope'
pkgManagers:
- pnpm
- yarn
showInfo: true
showSettings: true
showSearch: true
showFooter: true
showThemeSwitch: true
showDownloadTarball: true
showRaw: true
primary_color: '#ffffff'
logo: './does_not_exist/config/dark-logo.png'
html_cache: false
url_prefix: /prefix
log: { type: stdout, format: pretty, level: trace }
flags:
changePassword: true

View File

@ -37,6 +37,10 @@ describe('test web server', () => {
return new JSDOM(response.text, { runScripts: 'dangerously' });
};
const loadLogo = async (config = 'default-test.yaml', url) => {
return supertest(initializeServer(config)).get(url).expect(HTTP_STATUS.OK);
};
test('should match render set ui properties', async () => {
const {
window: { __VERDACCIO_BASENAME_UI_OPTIONS },
@ -56,7 +60,7 @@ describe('test web server', () => {
// FIXME: mock these values, avoid random
// base: 'http://127.0.0.1:60864/prefix/',
// version: '6.0.0-6-next.28',
logoURI: '',
logo: 'http://logo.org/logo.png',
flags: { changePassword: true },
login: true,
pkgManagers: ['pnpm', 'yarn'],
@ -67,6 +71,28 @@ describe('test web server', () => {
);
});
test('should render logo as file', async () => {
const {
window: { __VERDACCIO_BASENAME_UI_OPTIONS },
} = await render('file-logo.yaml');
expect(__VERDACCIO_BASENAME_UI_OPTIONS.logo).toMatch('/prefix/-/static/dark-logo.png');
return loadLogo('file-logo.yaml', '/-/static/dark-logo.png');
});
test('should not render logo as absolute file is wrong', async () => {
const {
window: { __VERDACCIO_BASENAME_UI_OPTIONS },
} = await render('wrong-logo.yaml');
expect(__VERDACCIO_BASENAME_UI_OPTIONS.logo).toEqual('');
});
test('should render not render a logo', async () => {
const {
window: { __VERDACCIO_BASENAME_UI_OPTIONS },
} = await render('no-logo.yaml');
expect(__VERDACCIO_BASENAME_UI_OPTIONS.logo).toEqual('');
});
test.todo('should default title');
test.todo('should need html cache');
});

View File

@ -109,9 +109,10 @@
"test": "cross-env TZ=UTC jest --config ./jest/jest.config.js",
"test:update-snapshot": "yarn run test -- -u",
"lint": "pnpm lint:js && pnpm lint:css",
"clean": "rimraf ./static",
"lint:css": "yarn stylelint \"src/**/styles.ts\"",
"verdaccio:server": "node tools/verdaccio.js",
"build": "webpack --config tools/webpack.prod.config.babel.js",
"build": "pnpm clean && webpack --config tools/webpack.prod.config.babel.js",
"build:stats": "webpack --config tools/webpack.prod.config.babel.js --json > stats.json",
"build:size": "webpack --config tools/webpack.prod.config.babel.js --json | webpack-bundle-size-analyzer"
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -20,7 +20,7 @@ web:
showDownloadTarball: true
showRaw: true
primary_color: '#ffffff'
logoURI: 'http://logo.org/logo.png'
logo: 'http://logo.org/logo.png'
flags:
- something: false

View File

@ -10248,7 +10248,7 @@ packages:
/axios/0.21.3_debug@4.3.4:
resolution: {integrity: sha512-JtoZ3Ndke/+Iwt5n+BgSli/3idTvpt5OjKyoCmz4LX5+lPiY5l7C1colYezhlxThjNa/NhngCUWZSZFypIFuaA==}
dependencies:
follow-redirects: 1.14.9_debug@4.3.4
follow-redirects: 1.14.9_debug@4.3.3
transitivePeerDependencies:
- debug
dev: false
@ -10256,7 +10256,7 @@ packages:
/axios/0.25.0_debug@4.3.4:
resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==}
dependencies:
follow-redirects: 1.14.9_debug@4.3.4
follow-redirects: 1.14.9_debug@4.3.3
transitivePeerDependencies:
- debug
@ -25406,7 +25406,7 @@ packages:
resolution: {integrity: sha512-FnHq5sTMxC0sk957wHDzRnemFnNBvt/gSY99HzK8F7UP5WAbvP70yX5bd7CjEQkN+TjdxwI7g7lJ6podqrG2/w==}
/truncate-utf8-bytes/1.0.2:
resolution: {integrity: sha1-QFkjkJWS1W94pYGENLC3hInKXys=}
resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==}
dependencies:
utf8-byte-length: 1.0.4
dev: false
@ -26157,7 +26157,7 @@ packages:
dev: false
/utf8-byte-length/1.0.4:
resolution: {integrity: sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=}
resolution: {integrity: sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==}
dev: false
/util-deprecate/1.0.2: