From 016812b12ccfde4ff06af59136a80852e3eaa2fc Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Sun, 14 Jul 2024 14:10:08 -0400 Subject: [PATCH 01/10] Docker image for apm --- .dockerignore | 4 + .prettierrc | 2 +- .vscode/settings.json | 6 +- Dockerfile | 5 +- abappm/README.md | 3 + abappm/apm.ico | Bin 0 -> 7063 bytes abappm/apm_40x40.png | Bin 0 -> 1109 bytes abappm/apm_640x512.png | Bin 0 -> 11857 bytes abappm/apm_banner.png | Bin 0 -> 19560 bytes abappm/apm_banner_gray.png | Bin 0 -> 16583 bytes config.yaml | 225 ++++++++++++++++++ jest/config.js | 2 + packages/core/types/src/configuration.ts | 2 +- packages/plugins/ui-theme/package.json | 1 + .../plugins/ui-theme/src/i18n/crowdin/ui.json | 2 + packages/ui-components/package.json | 2 + .../components/ActionBar/ActionBarAction.tsx | 2 +- .../src/components/Engines/Engines.tsx | 27 ++- .../src/components/Engines/styles.ts | 2 +- .../src/components/Icons/DevsIcons/ABAP.tsx | 7 + .../components/Icons/DevsIcons/ABAPModule.tsx | 7 + .../src/components/Icons/DevsIcons/abap.svg | 5 + .../components/Icons/DevsIcons/abapmodule.svg | 5 + .../src/components/Icons/DevsIcons/index.ts | 2 + .../src/components/Icons/Managers/Apm.tsx | 7 + .../src/components/Icons/Managers/apm.svg | 7 + .../src/components/Icons/Managers/index.ts | 1 + .../src/components/Install/Install.tsx | 12 +- .../components/Install/InstallListItem.tsx | 20 +- .../src/components/Readme/utils.ts | 4 + .../src/components/Search/styles.ts | 13 +- .../components/SideBarTitle/SideBarTitle.tsx | 4 +- .../src/sections/Header/styles.ts | 2 +- .../src/test/test-react-testing-library.tsx | 3 + 34 files changed, 366 insertions(+), 18 deletions(-) create mode 100644 abappm/README.md create mode 100644 abappm/apm.ico create mode 100644 abappm/apm_40x40.png create mode 100644 abappm/apm_640x512.png create mode 100644 abappm/apm_banner.png create mode 100644 abappm/apm_banner_gray.png create mode 100644 config.yaml create mode 100644 packages/ui-components/src/components/Icons/DevsIcons/ABAP.tsx create mode 100644 packages/ui-components/src/components/Icons/DevsIcons/ABAPModule.tsx create mode 100644 packages/ui-components/src/components/Icons/DevsIcons/abap.svg create mode 100644 packages/ui-components/src/components/Icons/DevsIcons/abapmodule.svg create mode 100644 packages/ui-components/src/components/Icons/Managers/Apm.tsx create mode 100644 packages/ui-components/src/components/Icons/Managers/apm.svg diff --git a/.dockerignore b/.dockerignore index 7bd034374..22554f968 100644 --- a/.dockerignore +++ b/.dockerignore @@ -24,6 +24,10 @@ contrib docker-examples website systemd +e2e +assets +types +scripts # output from test runs and similar things *.log diff --git a/.prettierrc b/.prettierrc index d10be3bb6..83ad2ca06 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ { - "endOfLine": "lf", + "endOfLine": "auto", "useTabs": false, "printWidth": 100, "tabWidth": 2, diff --git a/.vscode/settings.json b/.vscode/settings.json index e2229d6bd..c99d14a44 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,14 @@ // Place your settings in this file to overwrite default and user settings. { "files.exclude": { + "**/node_modules/**/node_modules": true, "**/build": false, "**/coverage": true, ".idea": true, }, "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true + "editor.formatOnSave": false, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, } diff --git a/Dockerfile b/Dockerfile index 4909bb875..57a7ca6ed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ RUN apk --no-cache add openssl ca-certificates wget && \ WORKDIR /opt/verdaccio-build COPY . . -RUN npm -g i pnpm@8.9.0 && \ +RUN npm -g i pnpm@8.14.0 && \ pnpm config set registry $VERDACCIO_BUILD_REGISTRY && \ pnpm install --frozen-lockfile --ignore-scripts && \ rm -Rf test && \ @@ -40,7 +40,8 @@ RUN mkdir -p /verdaccio/storage /verdaccio/plugins /verdaccio/conf COPY --from=builder /opt/verdaccio-build . RUN ls packages/config/src/conf -ADD packages/config/src/conf/docker.yaml /verdaccio/conf/config.yaml +ADD config.yaml /verdaccio/conf/config.yaml +ADD abappm /verdaccio/abappm RUN adduser -u $VERDACCIO_USER_UID -S -D -h $VERDACCIO_APPDIR -g "$VERDACCIO_USER_NAME user" -s /sbin/nologin $VERDACCIO_USER_NAME && \ chmod -R +x $VERDACCIO_APPDIR/packages/verdaccio/bin $VERDACCIO_APPDIR/docker-bin && \ diff --git a/abappm/README.md b/abappm/README.md new file mode 100644 index 000000000..28f0831bf --- /dev/null +++ b/abappm/README.md @@ -0,0 +1,3 @@ +# abapPM + +Assets for Verdaccio diff --git a/abappm/apm.ico b/abappm/apm.ico new file mode 100644 index 0000000000000000000000000000000000000000..1411d409ec90017c5e21f81faf6d3e52dfc286a2 GIT binary patch literal 7063 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 literal 0 HcmV?d00001 diff --git a/abappm/apm_40x40.png b/abappm/apm_40x40.png new file mode 100644 index 0000000000000000000000000000000000000000..167d1c8a42f2960a01c78a042db6841366928e42 GIT binary patch literal 1109 zcmV-b1giUqP)G7 z3JEs!9rxh?000SaNLh0L01EH`01EH{Laa2H00004XF*Lt006O%3;baP000BzNkl-PU9*S6!?b7t37Ed0aAoXebVerIOR%>NJ_a~Xn_ zsHv$b-DEP|!r^^NImTHf&KkpMO{G@JC{G8{8_*D*$EY{IlYPJ_S7r-g+DzBG?`xVE;|+1A#!;1?i+p}32<0zi}Z zJ%ExgP&Ggp3>q676JSeAOZ(bFK8EXLSh$>dO+bL1!vju0T~&gqB;E(=4Y;wfK`xhz zhK7b{d3jl8G?$U{NoZ(j2VDBxUw{BRi=t_F`w5ZBrUsgqmq%S)T{Jp6O2fm$w6e0| zPb!aA5l`3G*V|iLTW1Z0g@w1v%ggVB+&}-M5Pq0MxwyDU7K@b8)>L?S_-aK(h21nW zGh@dbxd4ww@$vC{4ao{WOq8FWPu11cgb7b}yPf9d=7j$X1T-QdLion2sw#6zO3GI; zoIDi${rzGh^Ud7cT+y%|7}qN*DiUtSBOdaJi3t(x0n5tD#Ea`GGBT113JS!_;-BYF zJKmLeGWYfM?SZm=Que4XFg5Yqwo{Z?9>Iw>!N#?$Q5Y7ES>Fb-?ezN`|HA3yO^(rQZc-}A%6PGS5s4?m5cvd-y-tVs4pWv_yOn*rj!-&7_lY^s0rpRwqVtW zNew_PFr^X^4-hLp0Hwi{;>NEdK6?TB1Ev%^hIYi#E?~f5N}1qBYzF{SDz>(^wlNrB b$3njVqS2C00000NkvXXu0mjfcd7!+ literal 0 HcmV?d00001 diff --git a/abappm/apm_640x512.png b/abappm/apm_640x512.png new file mode 100644 index 0000000000000000000000000000000000000000..d973dd7caf4572dbe62bdf291a27fdfeeaa2df30 GIT binary patch literal 11857 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 literal 0 HcmV?d00001 diff --git a/abappm/apm_banner.png b/abappm/apm_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..269a18d3fbe18e57f922dd66d340e8e0a21d4722 GIT binary patch literal 19560 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 literal 0 HcmV?d00001 diff --git a/abappm/apm_banner_gray.png b/abappm/apm_banner_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..7c7908d7cbd4aaf0e28c4c11191d1903b3f7407b GIT binary patch literal 16583 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 + # scriptsBodyAfter: + # - '' + # HTML tags injected before ends + metaScripts: + - '' + # - '' + # - '' + # HTML tags injected first child at + scriptsbodyBefore: + - '
***BETA*** All published packages will be deleted before go-live! ***BETA***
' + # Public path for template manifest scripts (only manifest) + publicPath: https://registry.abappm.com/ + +auth: + htpasswd: + file: /verdaccio/storage/htpasswd + # Maximum amount of users allowed to register, defaults to "+inf". + # You can set this to -1 to disable registration. + max_users: 10 + algorithm: bcrypt + +# https://verdaccio.org/docs/configuration#uplinks +# a list of other known repositories we can talk to +uplinks: + +# Learn how to protect your packages +# https://verdaccio.org/docs/protect-your-dependencies/ +# https://verdaccio.org/docs/configuration#packages +packages: + '@*/*': + # scoped packages + access: none + publish: none + unpublish: none + #access: $all + #publish: $authenticated + #unpublish: $authenticated + #proxy: npmjs + + '**': + # allow all users (including non-authenticated users) to read and + # publish all packages + # + # you can specify usernames/groupnames (depending on your auth plugin) + # and three keywords: "$all", "$anonymous", "$authenticated" + access: $all + + # allow all known users to publish/publish packages + # (anyone can register by default, remember?) + publish: $authenticated + unpublish: $authenticated + + # if package is not available locally, proxy requests to 'npmjs' registry + # proxy: npmjs + +# To improve your security configuration and avoid dependency confusion +# consider removing the proxy property for private packages +# https://verdaccio.org/docs/best#remove-proxy-to-increase-security-at-private-packages + +# https://verdaccio.org/docs/configuration#server +# You can specify HTTP/1.1 server keep alive timeout in seconds for incoming connections. +# A value of 0 makes the http server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout. +# WORKAROUND: Through given configuration you can workaround following issue https://github.com/verdaccio/verdaccio/issues/301. Set to 0 in case 60 is not enough. +server: + keepAliveTimeout: 60 + +# https://verdaccio.org/docs/configuration#offline-publish +publish: + check_owner: true +# allow_offline: false + +# https://verdaccio.org/docs/configuration#url-prefix +# url_prefix: /verdaccio/ +# VERDACCIO_PUBLIC_URL='https://somedomain.org'; +# url_prefix: '/my_prefix' +# // url -> https://somedomain.org/my_prefix/ +# VERDACCIO_PUBLIC_URL='https://somedomain.org'; +# url_prefix: '/' +# // url -> https://somedomain.org/ +# VERDACCIO_PUBLIC_URL='https://somedomain.org/first_prefix'; +# url_prefix: '/second_prefix' +# // url -> https://somedomain.org/second_prefix/' +url_prefix: '/' + +# https://verdaccio.org/docs/configuration#security +security: + api: + legacy: false + jwt: + sign: + expiresIn: 29d + # verify: + # someProp: [value] + web: + sign: + expiresIn: 1h # 1 hour by default +# verify: +# someProp: [value] + +# https://verdaccio.org/docs/configuration#user-rate-limit +# userRateLimit: +# windowMs: 50000 +# max: 1000 + +# https://verdaccio.org/docs/configuration#max-body-size +max_body_size: 1mb + +# https://verdaccio.org/docs/configuration#listen-port +# listen: +# - localhost:4873 # default value +# - http://localhost:4873 # same thing +# - 0.0.0.0:4873 # listen on all addresses (INADDR_ANY) +# - https://example.org:4873 # if you want to use https +# - "[::1]:4873" # ipv6 +# - unix:/tmp/verdaccio.sock # unix socket + +# The HTTPS configuration is useful if you do not consider use a HTTP Proxy +# https://verdaccio.org/docs/configuration#https +# https: +# key: ./path/verdaccio-key.pem +# cert: ./path/verdaccio-cert.pem +# ca: ./path/verdaccio-csr.pem + +# https://verdaccio.org/docs/configuration#proxy +# http_proxy: http://something.local/ +# https_proxy: https://something.local/ + +# https://verdaccio.org/docs/configuration#notifications +# notify: +# method: POST +# headers: [{ "Content-Type": "application/json" }] +# endpoint: https://usagge.hipchat.com/v2/room/3729485/notification?auth_token=mySecretToken +# content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}' + +# https://verdaccio.org/docs/logger +# log settings +log: { type: stdout, format: pretty, level: http } +# { type: file, path: /verdaccio/storage/verdaccio.log, level: info } + +# experiments: +# # support for npm token command +# token: false +# # enable tarball URL redirect for hosting tarball with a different server, the tarball_url_redirect can be a template string +# tarball_url_redirect: 'https://mycdn.com/verdaccio/${packageName}/${filename}' +# # the tarball_url_redirect can be a function, takes packageName and filename and returns the url, when working with a js configuration file +# tarball_url_redirect(packageName, filename) { +# const signedUrl = // generate a signed url +# return signedUrl; +# } + +# translate your registry, api i18n not available yet +# i18n: +# list of the available translations https://github.com/verdaccio/verdaccio/blob/master/packages/plugins/ui-theme/src/i18n/ABOUT_TRANSLATIONS.md +# web: en-US + +middlewares: + audit: + enabled: true +# install-counts: +# enabled: true +# redis: +# host: red-ckfit036fquc73egihn0 +# port: 6379 + +# Using Redis as storage +# https://github.com/openupm/verdaccio-redis-storage +#store: +# storage-proxy: +# database_backend: redis-storage +# search_backend: redis-storage +# packument_backend: redis-storage +# tarball_backend: '@verdaccio/local-storage' +# backends: +# '@verdaccio/local-storage': {} +# redis-storage: +# host: red-ckfit036fquc73egihn0 +# port: 6379 diff --git a/jest/config.js b/jest/config.js index ba5826292..7d95a25a9 100644 --- a/jest/config.js +++ b/jest/config.js @@ -1,5 +1,7 @@ module.exports = { moduleFileExtensions: ['ts', 'js'], + maxWorkers: 3, + testTimeout: 20000, transform: { '^.+\\.(js|ts)$': 'babel-jest', }, diff --git a/packages/core/types/src/configuration.ts b/packages/core/types/src/configuration.ts index 3f303e521..f9c1de59d 100644 --- a/packages/core/types/src/configuration.ts +++ b/packages/core/types/src/configuration.ts @@ -77,7 +77,7 @@ export type FlagsConfig = { changePassword?: boolean; }; -export type PackageManagers = 'pnpm' | 'yarn' | 'npm'; +export type PackageManagers = 'pnpm' | 'yarn' | 'npm' | 'apm'; // FUTURE: WebConf and TemplateUIOptions should be merged . export type CommonWebConf = { diff --git a/packages/plugins/ui-theme/package.json b/packages/plugins/ui-theme/package.json index 4fc059a94..46193010c 100644 --- a/packages/plugins/ui-theme/package.json +++ b/packages/plugins/ui-theme/package.json @@ -39,6 +39,7 @@ "friendly-errors-webpack-plugin": "1.7.0", "harmony-reflect": "1.6.2", "highlight.js": "11.9.0", + "highlightjs-sap-abap": "0.3.0", "history": "4.10.1", "html-webpack-plugin": "5.6.0", "i18next": "20.6.1", diff --git a/packages/plugins/ui-theme/src/i18n/crowdin/ui.json b/packages/plugins/ui-theme/src/i18n/crowdin/ui.json index 60ffa238b..9a583ee06 100644 --- a/packages/plugins/ui-theme/src/i18n/crowdin/ui.json +++ b/packages/plugins/ui-theme/src/i18n/crowdin/ui.json @@ -132,9 +132,11 @@ "title": "Contributors" }, "engines": { + "apm-version": "apm Version", "npm-version": "Npm Version", "pnpm-version": "Pnpm Version", "yarn-version": "Yarn Version", + "abap": "ABAP Release", "node-js": "Node.js" } }, diff --git a/packages/ui-components/package.json b/packages/ui-components/package.json index ecde71b35..9c5e9c7ce 100644 --- a/packages/ui-components/package.json +++ b/packages/ui-components/package.json @@ -9,6 +9,7 @@ "types": "build/index.d.ts", "scripts": { "test": "cross-env TZ=UTC jest --config jest/jest.config.js", + "test:snap": "cross-env TZ=UTC jest --config jest/jest.config.js --updateSnapshot", "test:html": "cross-env TZ=UTC jest --config jest/jest.config.js --coverage-reporters=html", "clean": "rimraf ./build", "type-check": "tsc --noEmit -p tsconfig.build.json", @@ -36,6 +37,7 @@ "dayjs": "1.11.10", "dompurify": "3.0.8", "highlight.js": "11.9.0", + "highlightjs-sap-abap": "0.3.0", "history": "4.10.1", "i18next": "20.6.1", "js-base64": "3.7.6", diff --git a/packages/ui-components/src/components/ActionBar/ActionBarAction.tsx b/packages/ui-components/src/components/ActionBar/ActionBarAction.tsx index 4ff7fdbd3..a5ece90cb 100644 --- a/packages/ui-components/src/components/ActionBar/ActionBarAction.tsx +++ b/packages/ui-components/src/components/ActionBar/ActionBarAction.tsx @@ -20,7 +20,7 @@ export const Fab = styled(FabMUI)<{ theme?: Theme }>(({ theme }) => ({ '&:hover': { color: theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.cyanBlue, }, - color: theme?.palette.white, + color: theme?.palette.mode === 'light' ? theme?.palette.black : theme?.palette.white, })); type ActionType = 'VISIT_HOMEPAGE' | 'OPEN_AN_ISSUE' | 'DOWNLOAD_TARBALL' | 'RAW_DATA'; diff --git a/packages/ui-components/src/components/Engines/Engines.tsx b/packages/ui-components/src/components/Engines/Engines.tsx index 2cc2fda98..11f33ee7f 100644 --- a/packages/ui-components/src/components/Engines/Engines.tsx +++ b/packages/ui-components/src/components/Engines/Engines.tsx @@ -6,7 +6,7 @@ import React, { FC } from 'react'; import { useTranslation } from 'react-i18next'; import { PackageMetaInterface } from '../../types/packageMeta'; -import { NodeJS, Npm, Pnpm, Yarn } from '../Icons'; +import { ABAP as Abap, Apm, NodeJS, Npm, Pnpm, Yarn } from '../Icons'; import { EngineListItem, StyledText } from './styles'; /** @@ -36,7 +36,14 @@ const EngineItem: FC = ({ title, element, engineText }) => ( interface EngineMetadata extends Omit { latest: { - engines?: { npm?: string; node?: string; pnpm?: string; yarn?: string }; + engines?: { + abap?: string; + apm?: string; + npm?: string; + node?: string; + pnpm?: string; + yarn?: string; + }; }; } @@ -61,6 +68,22 @@ const Engine: React.FC = ({ packageMeta }) => { return ( + {engines.abap ? ( + } + engineText={engines.abap} + title={t('sidebar.engines.abap')} + /> + ) : null} + + {engines.apm ? ( + } + engineText={engines.apm} + title={t('sidebar.engines.apm-version')} + /> + ) : null} + {engines.node ? ( } diff --git a/packages/ui-components/src/components/Engines/styles.ts b/packages/ui-components/src/components/Engines/styles.ts index 390edbfcb..e6729e4ed 100644 --- a/packages/ui-components/src/components/Engines/styles.ts +++ b/packages/ui-components/src/components/Engines/styles.ts @@ -6,7 +6,7 @@ import { Theme } from '../../Theme'; export const StyledText = styled(Typography)<{ theme?: Theme }>((props) => ({ fontWeight: props.theme?.fontWeight.bold, - textTransform: 'capitalize', + // textTransform: 'capitalize', // apm })); export const EngineListItem = styled(ListItem)({ diff --git a/packages/ui-components/src/components/Icons/DevsIcons/ABAP.tsx b/packages/ui-components/src/components/Icons/DevsIcons/ABAP.tsx new file mode 100644 index 000000000..0c56b995d --- /dev/null +++ b/packages/ui-components/src/components/Icons/DevsIcons/ABAP.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +const icon = require('./abap.svg'); + +export function ABAP() { + return ABAP; +} diff --git a/packages/ui-components/src/components/Icons/DevsIcons/ABAPModule.tsx b/packages/ui-components/src/components/Icons/DevsIcons/ABAPModule.tsx new file mode 100644 index 000000000..e3976feba --- /dev/null +++ b/packages/ui-components/src/components/Icons/DevsIcons/ABAPModule.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +const icon = require('./abapmodule.svg'); + +export function ABAPModule() { + return ABAP module; +} diff --git a/packages/ui-components/src/components/Icons/DevsIcons/abap.svg b/packages/ui-components/src/components/Icons/DevsIcons/abap.svg new file mode 100644 index 000000000..3699b6ff1 --- /dev/null +++ b/packages/ui-components/src/components/Icons/DevsIcons/abap.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/ui-components/src/components/Icons/DevsIcons/abapmodule.svg b/packages/ui-components/src/components/Icons/DevsIcons/abapmodule.svg new file mode 100644 index 000000000..d4d1fdbe1 --- /dev/null +++ b/packages/ui-components/src/components/Icons/DevsIcons/abapmodule.svg @@ -0,0 +1,5 @@ + + + + module + diff --git a/packages/ui-components/src/components/Icons/DevsIcons/index.ts b/packages/ui-components/src/components/Icons/DevsIcons/index.ts index 6861201a8..bf9d5a36b 100644 --- a/packages/ui-components/src/components/Icons/DevsIcons/index.ts +++ b/packages/ui-components/src/components/Icons/DevsIcons/index.ts @@ -3,3 +3,5 @@ export { CommonJS } from './CommonJS'; export { ES6Modules } from './ES6Module'; export { NodeJS } from './NodeJS'; export { Git } from './Git'; +export { ABAP } from './ABAP'; +export { ABAPModule } from './ABAPModule'; diff --git a/packages/ui-components/src/components/Icons/Managers/Apm.tsx b/packages/ui-components/src/components/Icons/Managers/Apm.tsx new file mode 100644 index 000000000..81389a816 --- /dev/null +++ b/packages/ui-components/src/components/Icons/Managers/Apm.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +const icon = require('./apm.svg'); + +export function Apm() { + return apm package manager; +} diff --git a/packages/ui-components/src/components/Icons/Managers/apm.svg b/packages/ui-components/src/components/Icons/Managers/apm.svg new file mode 100644 index 000000000..b5f4f8f6e --- /dev/null +++ b/packages/ui-components/src/components/Icons/Managers/apm.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/ui-components/src/components/Icons/Managers/index.ts b/packages/ui-components/src/components/Icons/Managers/index.ts index b3ef70245..5df53fd63 100644 --- a/packages/ui-components/src/components/Icons/Managers/index.ts +++ b/packages/ui-components/src/components/Icons/Managers/index.ts @@ -1,3 +1,4 @@ +export { Apm } from './Apm'; export { Npm } from './Npm'; export { Pnpm } from './Pnpm'; export { Yarn } from './Yarn'; diff --git a/packages/ui-components/src/components/Install/Install.tsx b/packages/ui-components/src/components/Install/Install.tsx index 30f67cf9d..cfbe3394a 100644 --- a/packages/ui-components/src/components/Install/Install.tsx +++ b/packages/ui-components/src/components/Install/Install.tsx @@ -36,8 +36,9 @@ const Install: React.FC = ({ packageMeta, packageName, configOptions }) = const hasNpm = configOptions?.pkgManagers?.includes('npm'); const hasYarn = configOptions?.pkgManagers?.includes('yarn'); - const hasPnpm = configOptions?.pkgManagers?.includes('pnpm') ?? true; - const hasPkgManagers = hasNpm || hasPnpm || hasYarn; + const hasPnpm = configOptions?.pkgManagers?.includes('pnpm'); + const hasApm = configOptions?.pkgManagers?.includes('apm'); // apm + const hasPkgManagers = hasNpm || hasPnpm || hasYarn || hasApm; // apm return hasPkgManagers ? ( <> @@ -50,6 +51,13 @@ const Install: React.FC = ({ packageMeta, packageName, configOptions }) = } > + {hasApm && ( + + )} {hasNpm && ( = ({ const isLatest = localSettings[packageName]?.latest ?? false; const isGlobal = localSettings[packageName]?.global ?? false; switch (dependencyManager) { + case DependencyManager.APM: + return ( + + + + + + } + /> + + ); case DependencyManager.NPM: return ( diff --git a/packages/ui-components/src/components/Readme/utils.ts b/packages/ui-components/src/components/Readme/utils.ts index 58179fab9..c44ad9f01 100644 --- a/packages/ui-components/src/components/Readme/utils.ts +++ b/packages/ui-components/src/components/Readme/utils.ts @@ -7,6 +7,10 @@ const marked = new Marked( async: false, highlight(code, lang) { const hljs = require('highlight.js'); + // >>> apm + const hlabap = require('highlightjs-sap-abap'); + hljs.registerLanguage('abap', hlabap); + // <<< apm const language = hljs.getLanguage(lang) ? lang : 'plaintext'; return hljs.highlight(code, { language }).value; }, diff --git a/packages/ui-components/src/components/Search/styles.ts b/packages/ui-components/src/components/Search/styles.ts index f5efd35bb..b2993a833 100644 --- a/packages/ui-components/src/components/Search/styles.ts +++ b/packages/ui-components/src/components/Search/styles.ts @@ -14,7 +14,10 @@ export const StyledTextField = styled(TextField)<{ theme?: Theme }>((props) => ( border: 'none', }, ':after': { - borderColor: props.theme?.palette.white, + borderColor: + props.theme?.palette.mode === 'light' + ? props.theme?.palette.black + : props.theme?.palette.white, }, ':hover:before': { content: 'none', @@ -31,11 +34,15 @@ export const StyledTextField = styled(TextField)<{ theme?: Theme }>((props) => ( }, '& .MuiInputBase-input': { [`@media screen and (min-width: ${props.theme?.breakPoints.medium}px)`]: { - color: props.theme?.palette.white, + color: + props.theme?.palette.mode === 'light' + ? props.theme?.palette.black + : props.theme?.palette.white, }, }, })); export const StyledInputAdornment = styled(InputAdornment)<{ theme?: Theme }>((props) => ({ - color: props.theme?.palette.white, + color: + props.theme?.palette.mode === 'light' ? props.theme?.palette.black : props.theme?.palette.white, })); diff --git a/packages/ui-components/src/components/SideBarTitle/SideBarTitle.tsx b/packages/ui-components/src/components/SideBarTitle/SideBarTitle.tsx index d587faf3c..1b0a1d679 100644 --- a/packages/ui-components/src/components/SideBarTitle/SideBarTitle.tsx +++ b/packages/ui-components/src/components/SideBarTitle/SideBarTitle.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'; import { Theme } from '../../Theme'; import Heading from '../Heading'; -import { CommonJS, ES6Modules, TypeScript } from '../Icons'; +import { ABAPModule, CommonJS, TypeScript } from '../Icons'; import { formatDate, formatDateDistance } from './utils'; export type ModuleType = 'commonjs' | 'module'; @@ -34,7 +34,7 @@ const ModuleJS: React.FC<{ module: ModuleType | void }> = ({ module }) => { } else if (module === 'module') { return ( - + ); } else { diff --git a/packages/ui-components/src/sections/Header/styles.ts b/packages/ui-components/src/sections/Header/styles.ts index 1fca2c8e4..21dc70bd9 100644 --- a/packages/ui-components/src/sections/Header/styles.ts +++ b/packages/ui-components/src/sections/Header/styles.ts @@ -47,7 +47,7 @@ export const SearchWrapper = styled('div')({ export const NavBar = styled(AppBar)<{ theme?: Theme }>(({ theme }) => ({ backgroundColor: theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.cyanBlue, - color: theme?.palette.white, + color: theme?.palette.mode === 'light' ? theme?.palette.black : theme?.palette.white, minHeight: 60, display: 'flex', justifyContent: 'center', diff --git a/packages/ui-components/src/test/test-react-testing-library.tsx b/packages/ui-components/src/test/test-react-testing-library.tsx index 5b85552cd..b75cdb9f7 100644 --- a/packages/ui-components/src/test/test-react-testing-library.tsx +++ b/packages/ui-components/src/test/test-react-testing-library.tsx @@ -1,4 +1,5 @@ import { StyledEngineProvider } from '@mui/material/styles'; +import { configure } from '@testing-library/dom'; import { render } from '@testing-library/react'; import React from 'react'; import { I18nextProvider } from 'react-i18next'; @@ -10,6 +11,8 @@ import PersistenceSettingProvider from '../providers/PersistenceSettingProvider' import { Store } from '../store/store'; import i18nConfig from './i18n-config'; +configure({ asyncUtilTimeout: 10000 }); + const renderWithStore = (ui: React.ReactElement, store: Store) => render(ui, { wrapper: ({ children }) => ( From 03a903d9245a1bc00a8d8dbf24763e3045ec897c Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:41:02 -0400 Subject: [PATCH 02/10] fix favicon --- config.yaml | 13 +++++---- .../src/middlewares/web/render-web.ts | 10 ++++++- .../src/middlewares/web/utils/renderHTML.ts | 2 ++ packages/middleware/test/config/favicon.ico | Bin 0 -> 15086 bytes .../middleware/test/config/file-logo.yaml | 1 + .../middleware/test/config/http-logo.yaml | 26 ++++++++++++++++++ packages/middleware/test/config/no-logo.yaml | 1 + packages/middleware/test/render.spec.ts | 16 +++++++++++ 8 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 packages/middleware/test/config/favicon.ico create mode 100644 packages/middleware/test/config/http-logo.yaml diff --git a/config.yaml b/config.yaml index bc4744309..85bda98ee 100644 --- a/config.yaml +++ b/config.yaml @@ -23,9 +23,10 @@ plugins: /verdaccio/plugins web: enable: true title: apm - A Package Manager for ABAP - logo: /verdaccio/abappm/apm_banner_gray.png + logo: /verdaccio/abappm/apm_banner.png + logoDark: /verdaccio/abappm/apm_banner_gray.png favicon: /verdaccio/abappm/apm.ico - primary_color: '#a0a0a0' + primaryColor: '#c0c0c0' darkMode: true gravatar: true # by default packages are ordercer ascendant (asc|desc) @@ -38,7 +39,8 @@ web: pkgManagers: - apm showInfo: false - # showSettings: true + showUplinks: false + showSettings: false # In combination with darkMode you can force specific theme # showThemeSwitch: true # showFooter: true @@ -51,13 +53,14 @@ web: # HTML tags injected before ends metaScripts: - '' + - '' # - '' # - '' # HTML tags injected first child at scriptsbodyBefore: - - '
***BETA*** All published packages will be deleted before go-live! ***BETA***
' + - '
***PLAYGROUND*** Packages will be deleted every Sunday night! ***PLAYGROUND***
' # Public path for template manifest scripts (only manifest) - publicPath: https://registry.abappm.com/ + publicPath: https://playground.abappm.com/ auth: htpasswd: diff --git a/packages/middleware/src/middlewares/web/render-web.ts b/packages/middleware/src/middlewares/web/render-web.ts index 3064a42d3..a52c0588e 100644 --- a/packages/middleware/src/middlewares/web/render-web.ts +++ b/packages/middleware/src/middlewares/web/render-web.ts @@ -37,7 +37,15 @@ export function renderWebMiddleware(config, tokenMiddleware, pluginOptions) { // 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}`; + let file = `${staticPath}/${filename}`; + if (filename === 'favicon.ico' && config?.web?.favicon) { + file = config?.web?.favicon; + if (isURLhasValidProtocol(file)) { + debug('redirect to favicon %s', file); + req.url = file; + return next(); + } + } debug('render static file %o', file); res.sendFile(file, sendFileCallback(next)); }); diff --git a/packages/middleware/src/middlewares/web/utils/renderHTML.ts b/packages/middleware/src/middlewares/web/utils/renderHTML.ts index 65f1f1077..3d8976285 100644 --- a/packages/middleware/src/middlewares/web/utils/renderHTML.ts +++ b/packages/middleware/src/middlewares/web/utils/renderHTML.ts @@ -65,6 +65,7 @@ export default function renderHTML( const title = config?.web?.title ?? WEB_TITLE; const login = hasLogin(config); const scope = config?.web?.scope ?? ''; + const favicon = resolveLogo(config?.web?.favicon, config?.url_prefix, requestOptions); const logo = resolveLogo(config?.web?.logo, config?.url_prefix, requestOptions); const logoDark = resolveLogo(config?.web?.logoDark, config?.url_prefix, requestOptions); const pkgManagers = config?.web?.pkgManagers ?? ['yarn', 'pnpm', 'npm']; @@ -114,6 +115,7 @@ export default function renderHTML( version, logo, logoDark, + favicon, flags, login, pkgManagers, diff --git a/packages/middleware/test/config/favicon.ico b/packages/middleware/test/config/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..1a4beb4b677465975cb41cf7dc28ea1b3a745038 GIT binary patch literal 15086 zcmdU0TWnNS6ulK9iHXRcCdODJ8b65fLlJ4kmPb**SH;?DLBIzEiJ*dtQK`=lKNLk2 z1T91mHToe4sA#AXYZXiB1H^)KkcWLj3v^~kl*Y1dt+ahj=pdX=V))HE$KGx2+vrXA#G!#KtJlEIqxI%l|s^KcPu1`D36 z&u~3S=WjF`y|gPHpA(J6HbmpG9V`b~;w%(UPzGgppe|J>*PRYFr?NyenCmZLJv&+7 z*?>5M@Hz_}&;^}Nc>F%+Ix?bXq6Lh%p%*bb@oRu?VDO9AoR7;5jmD#!`T%zlpXerF zF=O-k9*@Vb?25WIT9F8 zb)BY;lbv*;vqK5KpFDj^@d=4T1278*wKfG`KYQ3xupjR@K`m{q)YQ^UP0dZz+}c9z zCyrC+sgsIBN;Xfz2h4&$v99*O6I2iS3~ar$>^&NppJS2S;zIKhhJQ8>gPOA8+6m4rmW>*i~N>UK@1# zz-i$Z+e^Pswmte0#>0(Mb7|UBkA&F<;=iYiKZxyROo!M8sqQ@tzCmm+_(N=iRQ62< z_Ec;y971dZ1CQGnwR<|sf+eKPVm91PqyFQimz|#kU?a{98wjZzdU1r;x`LEyBOe?-RMpIvGu*D8e z87$HUKF5K?uwB;<={xVNU7_Z|+yGwbyx7C-(wGwRXD*SqwXE2Z0~36z4q~8x^>Y$*EXoy*X9?$Iy-RS zX7C68oi$ZFZpYK;0()7$ew8s_y49Ee!hV|a?4LAra7_jHpCJqDk{(x{miuFOQar!!)_F0X~ycz2K4KoM%Zk*Y4 zpB74`CYNt>pa(e$NP$Qmp-ohD4Yj*Q3hpEM-ZLJ%j5C_zVon*b%ik| zxsK>E)aeIDEEdaVy$3vb2KS>5pl&w|u`{v7toOfO&@KMsf6!rvA;G&hb$4S(vV-2< z{%tP%OT+~rvcC*qw*%(>kmzfI&ohNS#5NHhgvi--0R5~Zx(w~0##n%U4(_;bF}L(d z%I0$j$fSp-Dm=gy00Z`^YJ3MMqwJ0QA2{TAxA@ANh*cm4 zRrJIx8qKjHIfKtC%A>KH**L7lx*Om?cKPKDVnJC zihi>V{BZNiBisuY%&_!%a344Qc3S=UT8nw5O`LVNMJj84 zw{VyGYX9m~XIUd=*3<9@>I}(Qu#Y;s?8l+uBirbgdV4iJqxWEQ)z|@)o^^_a*j1z6yfMYIY%T)Icy-JrTCHZNXxm-2-giA z(51o@tQ&C(ge5Xrj5vjHgPk8HeYkDT+@&}-XRb2nv3%oyMq6R zrP8L1{kY}4D1$msSD>;or*j>G*-7sUZ@o&7zw(Sd2Cm1%w@04uD}Lm)k@tbTM&hj5 zPKT4Nu*PA1!#)aYYvKHvJ=WGleRg)HZ57**s=3xdU5HiN}AidvDO{z zq-R$~=&9w6w7sg$C@=k4$_GtlETq$aF$U5ZKPZonj0LAY$=qzmZwJSQ%Q;S3nxTtc MoAY1EhcYPpKk8q&4gdfE literal 0 HcmV?d00001 diff --git a/packages/middleware/test/config/file-logo.yaml b/packages/middleware/test/config/file-logo.yaml index 468ad357a..50441befc 100644 --- a/packages/middleware/test/config/file-logo.yaml +++ b/packages/middleware/test/config/file-logo.yaml @@ -15,6 +15,7 @@ web: primary_color: '#ffffff' logo: './test/config/dark-logo.png' logoDark: './test/config/dark-logo.png' + favicon: './test/config/favicon.ico' html_cache: false url_prefix: /prefix diff --git a/packages/middleware/test/config/http-logo.yaml b/packages/middleware/test/config/http-logo.yaml new file mode 100644 index 000000000..6f59e43d7 --- /dev/null +++ b/packages/middleware/test/config/http-logo.yaml @@ -0,0 +1,26 @@ +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: https://raw.githubusercontent.com/verdaccio/verdaccio/master/assets/svg/logo-small.svg + logoDark: https://raw.githubusercontent.com/verdaccio/verdaccio/master/assets/svg/logo-blackwhite.svg + favicon: https://raw.githubusercontent.com/verdaccio/verdaccio/master/website/static/img/favicon/favicon.ico + html_cache: false + +url_prefix: /prefix + +log: { type: stdout, format: pretty, level: trace } + +flags: + changePassword: true diff --git a/packages/middleware/test/config/no-logo.yaml b/packages/middleware/test/config/no-logo.yaml index 794b8a441..0a7c19308 100644 --- a/packages/middleware/test/config/no-logo.yaml +++ b/packages/middleware/test/config/no-logo.yaml @@ -14,6 +14,7 @@ web: showRaw: true primary_color: '#ffffff' logo: + favicon: html_cache: false url_prefix: /prefix diff --git a/packages/middleware/test/render.spec.ts b/packages/middleware/test/render.spec.ts index 810f3adb8..96916abcd 100644 --- a/packages/middleware/test/render.spec.ts +++ b/packages/middleware/test/render.spec.ts @@ -86,6 +86,21 @@ describe('test web server', () => { expect(__VERDACCIO_BASENAME_UI_OPTIONS.logoDark).toMatch('/prefix/-/static/dark-logo.png'); }); + test('should render favicon as file', async () => { + const { + window: { __VERDACCIO_BASENAME_UI_OPTIONS }, + } = await render('file-logo.yaml'); + expect(__VERDACCIO_BASENAME_UI_OPTIONS.favicon).toMatch('/prefix/-/static/favicon.ico'); + }); + + test('should render logo and favicon as URL', async () => { + const { + window: { __VERDACCIO_BASENAME_UI_OPTIONS }, + } = await render('http-logo.yaml'); + expect(__VERDACCIO_BASENAME_UI_OPTIONS.logo).toMatch(/https:.*logo-small.svg/i); + expect(__VERDACCIO_BASENAME_UI_OPTIONS.favicon).toMatch(/https:.*favicon.ico/i); + }); + test('should not render logo as absolute file is wrong', async () => { const { window: { __VERDACCIO_BASENAME_UI_OPTIONS }, @@ -98,6 +113,7 @@ describe('test web server', () => { window: { __VERDACCIO_BASENAME_UI_OPTIONS }, } = await render('no-logo.yaml'); expect(__VERDACCIO_BASENAME_UI_OPTIONS.logo).toEqual(''); + expect(__VERDACCIO_BASENAME_UI_OPTIONS.favicon).toEqual(''); }); test.todo('should default title'); From 6626e77766e90567f4b6a15e992d0d37eac88f8d Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:59:12 -0400 Subject: [PATCH 03/10] config --- Dockerfile | 2 +- config.yaml | 28 +++++++--------------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/Dockerfile b/Dockerfile index 57a7ca6ed..b992e7717 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=${BUILDPLATFORM:-linux/amd64} node:21-alpine as builder +FROM --platform=${BUILDPLATFORM:-linux/amd64} node:21-alpine AS builder ENV NODE_ENV=development \ VERDACCIO_BUILD_REGISTRY=https://registry.npmjs.org diff --git a/config.yaml b/config.yaml index 85bda98ee..d92ec8460 100644 --- a/config.yaml +++ b/config.yaml @@ -58,9 +58,9 @@ web: # - '' # HTML tags injected first child at scriptsbodyBefore: - - '
***PLAYGROUND*** Packages will be deleted every Sunday night! ***PLAYGROUND***
' + # - '
***PLAYGROUND*** Packages will be deleted every Sunday night! ***PLAYGROUND***
' # Public path for template manifest scripts (only manifest) - publicPath: https://playground.abappm.com/ + # publicPath: https://playground.abappm.com/ auth: htpasswd: @@ -80,29 +80,15 @@ uplinks: packages: '@*/*': # scoped packages - access: none - publish: none - unpublish: none - #access: $all - #publish: $authenticated - #unpublish: $authenticated - #proxy: npmjs - - '**': - # allow all users (including non-authenticated users) to read and - # publish all packages - # - # you can specify usernames/groupnames (depending on your auth plugin) - # and three keywords: "$all", "$anonymous", "$authenticated" access: $all - - # allow all known users to publish/publish packages - # (anyone can register by default, remember?) publish: $authenticated unpublish: $authenticated - # if package is not available locally, proxy requests to 'npmjs' registry - # proxy: npmjs + '**': + # global packages + access: $all + publish: $authenticated + unpublish: $authenticated # To improve your security configuration and avoid dependency confusion # consider removing the proxy property for private packages From d60bf44c438a563049d54b685aa3b70c48077460 Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Mon, 15 Jul 2024 18:19:34 -0400 Subject: [PATCH 04/10] lockfile --- pnpm-lock.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e55868ee..171cf46a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1259,6 +1259,9 @@ importers: highlight.js: specifier: 11.9.0 version: 11.9.0 + highlightjs-sap-abap: + specifier: 0.3.0 + version: 0.3.0 history: specifier: 4.10.1 version: 4.10.1 @@ -1930,6 +1933,9 @@ importers: highlight.js: specifier: 11.9.0 version: 11.9.0 + highlightjs-sap-abap: + specifier: 0.3.0 + version: 0.3.0 history: specifier: 4.10.1 version: 4.10.1 @@ -20342,6 +20348,9 @@ packages: resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==} engines: {node: '>=12.0.0'} + /highlightjs-sap-abap@0.3.0: + resolution: {integrity: sha512-nSiUvEOCycjtFA3pHaTowrbAAk5+lciBHyoVkDsd6FTRBtW9sT2dt42o2jAKbXjZVUidtacdk+j0Y2xnd233Mw==, tarball: https://registry.npmjs.org/highlightjs-sap-abap/-/highlightjs-sap-abap-0.3.0.tgz} + /history@4.10.1: resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==} dependencies: From 919795c80494968531588aeb38787bdb19c0556f Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Tue, 16 Jul 2024 10:12:05 -0400 Subject: [PATCH 05/10] Create docker-apm.yml --- .github/workflows/docker-apm.yml | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/docker-apm.yml diff --git a/.github/workflows/docker-apm.yml b/.github/workflows/docker-apm.yml new file mode 100644 index 000000000..08d191e42 --- /dev/null +++ b/.github/workflows/docker-apm.yml @@ -0,0 +1,50 @@ +name: Docker publish apm to docker.io + +on: + workflow_dispatch: + push: + paths: + - '.github/workflows/docker-apm.yml' + - 'packages/**' + - 'docker-bin/**' + - 'package.json' + - 'pnpm-*.yaml' + - 'Dockerfile' + - '.dockerignore' + branches: + - 'apm' + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + docker: + runs-on: ubuntu-latest + if: github.repository == 'mbtools/verdaccio' + steps: + - uses: actions/checkout@v4 + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + with: + driver-opts: network=host + - uses: docker/login-action@v3 + name: Login Docker Hub + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + - name: Prepare docker image tags + id: docker_meta + uses: docker/metadata-action@v5 + with: + images: abappm/registry + tags: | + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'apm') }} + - name: Build & Push + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.docker_meta.outputs.tags }} + labels: ${{ steps.docker_meta.outputs.labels }} From a985ddc246107160e0b105e10247404b9f2cd3c6 Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Tue, 16 Jul 2024 19:19:00 -0400 Subject: [PATCH 06/10] Docker, healthcheck, list hover --- Dockerfile | 2 ++ abappm/healthcheck.sh | 11 +++++++++++ .../ui-components/src/components/Package/styles.ts | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 abappm/healthcheck.sh diff --git a/Dockerfile b/Dockerfile index b992e7717..d64ce79fb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -57,3 +57,5 @@ VOLUME /verdaccio/storage ENTRYPOINT ["uid_entrypoint"] CMD $VERDACCIO_APPDIR/packages/verdaccio/bin/verdaccio --config /verdaccio/conf/config.yaml --listen $VERDACCIO_PROTOCOL://0.0.0.0:$VERDACCIO_PORT + +HEALTHCHECK --interval=5s --timeout=1s CMD /verdaccio/abappm/healthcheck.sh diff --git a/abappm/healthcheck.sh b/abappm/healthcheck.sh new file mode 100644 index 000000000..5c2518056 --- /dev/null +++ b/abappm/healthcheck.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +if pgrep -f "/usr/bin/dumb-init" > /dev/null; then + if pgrep -f "apm" > /dev/null; then + exit 0 + else + exit 1 + fi +else + exit 1 +fi diff --git a/packages/ui-components/src/components/Package/styles.ts b/packages/ui-components/src/components/Package/styles.ts index 5191d9c64..db85e8cbb 100644 --- a/packages/ui-components/src/components/Package/styles.ts +++ b/packages/ui-components/src/components/Package/styles.ts @@ -72,7 +72,7 @@ export const GridRightAligned = styled(Grid)({ export const Wrapper = styled(List)<{ theme?: Theme }>(({ theme }) => ({ '&:hover': { backgroundColor: - theme?.palette?.type == 'dark' ? theme?.palette?.secondary.main : theme?.palette?.greyLight2, + theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.cyanBlue, }, })); From 39f71f5d7d60235d490c2e7d648ffeb452062b2c Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:35:02 -0400 Subject: [PATCH 07/10] apm: remove chip from searchitem --- .../src/components/Search/SearchItem.tsx | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/ui-components/src/components/Search/SearchItem.tsx b/packages/ui-components/src/components/Search/SearchItem.tsx index 5606122c2..a94342821 100644 --- a/packages/ui-components/src/components/Search/SearchItem.tsx +++ b/packages/ui-components/src/components/Search/SearchItem.tsx @@ -9,6 +9,7 @@ import Stack from '@mui/material/Stack'; import React from 'react'; import { useTranslation } from 'react-i18next'; +import { useConfig } from '../../'; import { cleanDescription } from './utils'; type SearchItemProps = { @@ -74,6 +75,7 @@ const SearchItem: React.FC = ({ ...props }) => { const { t } = useTranslation(); + const { configOptions } = useConfig(); const handleDelete = () => { // no action assigned by default }; @@ -87,37 +89,39 @@ const SearchItem: React.FC = ({ {version && {version}} - - - {isPrivate && ( - } - label={t('search.isPrivate')} - onDelete={handleDelete} - size="small" - /> - )} - {isRemote && !isPrivate && ( - } - label={t('search.isRemote')} - onDelete={handleDelete} - size="small" - variant="outlined" - /> - )} - {isCached && ( - } - label={t('search.isCached')} - onDelete={handleDelete} - size="small" - variant="outlined" - /> - )} - - + {configOptions?.showUplinks && ( + + + {isPrivate && ( + } + label={t('search.isPrivate')} + onDelete={handleDelete} + size="small" + /> + )} + {isRemote && !isPrivate && ( + } + label={t('search.isRemote')} + onDelete={handleDelete} + size="small" + variant="outlined" + /> + )} + {isCached && ( + } + label={t('search.isCached')} + onDelete={handleDelete} + size="small" + variant="outlined" + /> + )} + + + )} ); }; From 5bcfd7e2e27ea42328548c96c4435645d12dbcc2 Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Fri, 19 Jul 2024 13:02:49 -0400 Subject: [PATCH 08/10] apm: update docker --- .dockerignore | 44 +++++++++++++-------- .github/workflows/docker-apm.yml | 14 ++++--- Dockerfile | 66 ++++++++++++++++++++++---------- 3 files changed, 81 insertions(+), 43 deletions(-) diff --git a/.dockerignore b/.dockerignore index 22554f968..8ad2f7f8d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,26 +8,22 @@ .* # you can add exceptions like in .gitignore to maintain a whitelist: # e.g. -!.babelrc -!.eslintrc -!.prettierrc.json -!.prettierignore +!babel.config.js +!eslintrc.js +!.prettierrc !.eslintignore !.stylelintrc +!.jest.config.js +!.jestEnvironment.js +!.yarnrc.yml +!.yarn/releases/yarn-*.cjs +!.yarn/plugins/* +!.pnp.js -# do not copy over node_modules we will run `pnpm install` anyway +# just in case, yarn 2 pnp is enabled node_modules -website -jest -docs -contrib -docker-examples -website -systemd -e2e -assets -types -scripts +.husky/ +.git/ # output from test runs and similar things *.log @@ -37,7 +33,21 @@ coverage/ # IDE config files jsconfig.json *.iml - # let's not get too recursive ;) Dockerfile* docker-compose*.yaml +.github/ +.husky/ +*.log +coverage/ +.vscode/ +*.md +contrib/ +docs/ +docker-examples/ +systemd/ +assets/ +jest*.js +test/ +wiki/ +debug/ diff --git a/.github/workflows/docker-apm.yml b/.github/workflows/docker-apm.yml index 08d191e42..c157d5c12 100644 --- a/.github/workflows/docker-apm.yml +++ b/.github/workflows/docker-apm.yml @@ -4,13 +4,17 @@ on: workflow_dispatch: push: paths: - - '.github/workflows/docker-apm.yml' - - 'packages/**' + - .github/workflows/docker-publish.yml + - 'src/**' + - 'conf/**' + - 'types/**' - 'docker-bin/**' + - 'bin/**' - 'package.json' - - 'pnpm-*.yaml' - - 'Dockerfile' - - '.dockerignore' + - 'yarn.lock' + - '.yarn/**' + - '.yarnrc.yaml' + - '.pnp.js' branches: - 'apm' diff --git a/Dockerfile b/Dockerfile index d64ce79fb..686633b80 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,13 @@ -FROM --platform=${BUILDPLATFORM:-linux/amd64} node:21-alpine AS builder +FROM --platform=${BUILDPLATFORM:-linux/amd64} node:20.15.1-alpine AS builder -ENV NODE_ENV=development \ - VERDACCIO_BUILD_REGISTRY=https://registry.npmjs.org +ENV NODE_ENV=production \ + VERDACCIO_BUILD_REGISTRY=https://registry.npmjs.org \ + HUSKY_SKIP_INSTALL=1 \ + CI=true \ + HUSKY_DEBUG=1 -RUN apk --no-cache add openssl ca-certificates wget && \ +RUN apk add --force-overwrite && \ + apk --no-cache add openssl ca-certificates wget && \ apk --no-cache add g++ gcc libgcc libstdc++ linux-headers make python3 && \ wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \ wget -q https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.35-r0/glibc-2.35-r0.apk && \ @@ -11,17 +15,24 @@ RUN apk --no-cache add openssl ca-certificates wget && \ WORKDIR /opt/verdaccio-build COPY . . -RUN npm -g i pnpm@8.14.0 && \ - pnpm config set registry $VERDACCIO_BUILD_REGISTRY && \ - pnpm install --frozen-lockfile --ignore-scripts && \ - rm -Rf test && \ - pnpm run build -# FIXME: need to remove devDependencies from the build -# NODE_ENV=production pnpm install --frozen-lockfile --ignore-scripts -# RUN pnpm install --prod --ignore-scripts -FROM node:21-alpine -LABEL maintainer="https://github.com/verdaccio/verdaccio" +## build the project and create a tarball of the project for later +## global installation +RUN yarn config set npmRegistryServer $VERDACCIO_BUILD_REGISTRY && \ + yarn config set enableProgressBars true && \ + yarn config set enableScripts false && \ + yarn install --immutable && \ + yarn build +## pack the project +RUN yarn pack --dry-run \ + && yarn pack --out verdaccio.tgz \ + && mkdir -p /opt/tarball \ + && mv /opt/verdaccio-build/verdaccio.tgz /opt/tarball +## clean up and reduce bundle size +RUN rm -Rf /opt/verdaccio-build + +FROM node:20.15.1-alpine +LABEL maintainer="https://github.com/abapPM/abapPM" ENV VERDACCIO_APPDIR=/opt/verdaccio \ VERDACCIO_USER_NAME=verdaccio \ @@ -33,18 +44,33 @@ ENV PATH=$VERDACCIO_APPDIR/docker-bin:$PATH \ WORKDIR $VERDACCIO_APPDIR +# https://github.com/Yelp/dumb-init RUN apk --no-cache add openssl dumb-init RUN mkdir -p /verdaccio/storage /verdaccio/plugins /verdaccio/conf -COPY --from=builder /opt/verdaccio-build . +COPY --from=builder /opt/tarball . -RUN ls packages/config/src/conf -ADD config.yaml /verdaccio/conf/config.yaml +USER root +# install verdaccio as a global package so is fully handled by npm +# ensure none dependency is being missing and is prod by default +RUN npm install -g $VERDACCIO_APPDIR/verdaccio.tgz \ + ## clean up cache + && npm cache clean --force \ + && rm -Rf .npm/ \ + && rm $VERDACCIO_APPDIR/verdaccio.tgz \ + # yarn is not need it after this step + # Also remove the symlinks added in the [`node:alpine` Docker image](https://github.com/nodejs/docker-node/blob/02a64a08a98a472c6141cd583d2e9fc47bcd9bfd/18/alpine3.16/Dockerfile#L91-L92). + && rm -Rf /opt/yarn-v1.22.19/ /usr/local/bin/yarn /usr/local/bin/yarnpkg + +# apm assets and config ADD abappm /verdaccio/abappm +ADD config.yaml /verdaccio/conf/config.yaml + +ADD docker-bin $VERDACCIO_APPDIR/docker-bin RUN adduser -u $VERDACCIO_USER_UID -S -D -h $VERDACCIO_APPDIR -g "$VERDACCIO_USER_NAME user" -s /sbin/nologin $VERDACCIO_USER_NAME && \ - chmod -R +x $VERDACCIO_APPDIR/packages/verdaccio/bin $VERDACCIO_APPDIR/docker-bin && \ + chmod -R +x /usr/local/lib/node_modules/verdaccio/bin/verdaccio $VERDACCIO_APPDIR/docker-bin && \ chown -R $VERDACCIO_USER_UID:root /verdaccio/storage && \ chmod -R g=u /verdaccio/storage /etc/passwd @@ -56,6 +82,4 @@ VOLUME /verdaccio/storage ENTRYPOINT ["uid_entrypoint"] -CMD $VERDACCIO_APPDIR/packages/verdaccio/bin/verdaccio --config /verdaccio/conf/config.yaml --listen $VERDACCIO_PROTOCOL://0.0.0.0:$VERDACCIO_PORT - -HEALTHCHECK --interval=5s --timeout=1s CMD /verdaccio/abappm/healthcheck.sh +CMD verdaccio --config /verdaccio/conf/config.yaml --listen $VERDACCIO_PROTOCOL://0.0.0.0:$VERDACCIO_PORT From d0dacd75c547ef039b9920964f8c4cbd02645034 Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Fri, 19 Jul 2024 13:18:02 -0400 Subject: [PATCH 09/10] apm: update action --- .github/workflows/docker-apm.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker-apm.yml b/.github/workflows/docker-apm.yml index c157d5c12..b46522f22 100644 --- a/.github/workflows/docker-apm.yml +++ b/.github/workflows/docker-apm.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: paths: - - .github/workflows/docker-publish.yml + - .github/workflows/docker-apm.yml - 'src/**' - 'conf/**' - 'types/**' @@ -15,6 +15,9 @@ on: - '.yarn/**' - '.yarnrc.yaml' - '.pnp.js' + - '.dockerignore' + - 'docker-compose.yml' + - 'Dockerfile' branches: - 'apm' From 2274e483acab52b8dc8bd5a33b16866089503674 Mon Sep 17 00:00:00 2001 From: Marc Bernard <59966492+mbtools@users.noreply.github.com> Date: Fri, 19 Jul 2024 13:19:00 -0400 Subject: [PATCH 10/10] apm: update action --- .github/workflows/docker-apm.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/docker-apm.yml b/.github/workflows/docker-apm.yml index b46522f22..c6a5a9874 100644 --- a/.github/workflows/docker-apm.yml +++ b/.github/workflows/docker-apm.yml @@ -1,10 +1,9 @@ name: Docker publish apm to docker.io on: - workflow_dispatch: push: paths: - - .github/workflows/docker-apm.yml + - '.github/workflows/docker-apm.yml' - 'src/**' - 'conf/**' - 'types/**'