@verdaccio/ui-components 3.0.0-next-7.7 → 3.0.0-next-7.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.
Files changed (300) hide show
  1. package/.eslintrc +1 -1
  2. package/CHANGELOG.md +6 -0
  3. package/build/Theme/theme.js +3 -3
  4. package/build/components/ActionBar/ActionBar.js +3 -1
  5. package/build/components/ActionBar/ActionBarAction.js +7 -6
  6. package/build/components/Author/Author.js +13 -42
  7. package/build/components/CopyClipboard/utils.js +3 -12
  8. package/build/components/Dependencies/Dependencies.js +12 -13
  9. package/build/components/Dependencies/DependencyBlock.js +5 -4
  10. package/build/components/Developers/DeveloperType.js +12 -0
  11. package/build/components/Developers/Developers.js +20 -22
  12. package/build/components/Developers/Title.js +5 -9
  13. package/build/components/Developers/index.js +4 -4
  14. package/build/components/Distribution/Dist.js +1 -1
  15. package/build/components/Distribution/styles.js +10 -23
  16. package/build/components/Engines/Engines.js +7 -1
  17. package/build/components/Engines/styles.js +6 -6
  18. package/build/components/FundButton/FundButton.js +7 -8
  19. package/build/components/HeaderInfoDialog/HeaderInfoDialog.js +2 -1
  20. package/build/components/Icons/DevsIcons/CommonJS.js +1 -12
  21. package/build/components/Icons/DevsIcons/ES6Module.js +2 -13
  22. package/build/components/Icons/DevsIcons/Git.js +1 -12
  23. package/build/components/Icons/DevsIcons/NodeJS.js +1 -12
  24. package/build/components/Icons/DevsIcons/TypeScript.js +1 -12
  25. package/build/components/Icons/FileBinary.js +11 -5
  26. package/build/components/Icons/Law.js +12 -6
  27. package/build/components/Icons/Managers/Npm.js +1 -12
  28. package/build/components/Icons/Managers/Pnpm.js +1 -12
  29. package/build/components/Icons/Managers/Yarn.js +1 -12
  30. package/build/components/Install/Install.js +23 -18
  31. package/build/components/Install/InstallListItem.js +19 -18
  32. package/build/components/Keywords/KeywordListItems.js +34 -0
  33. package/build/components/Keywords/Keywords.js +39 -0
  34. package/build/{sections/Header/RegistryInfoDialog → components/Keywords}/index.js +2 -2
  35. package/build/components/Link/Link.js +4 -16
  36. package/build/components/Link/index.js +1 -1
  37. package/build/components/LinkExternal/LinkExternal.js +32 -0
  38. package/build/components/LinkExternal/index.js +14 -0
  39. package/build/components/Loading/styles.js +3 -2
  40. package/build/components/LoginDialog/LoginDialog.js +12 -1
  41. package/build/components/LoginDialog/LoginDialogCloseButton.js +3 -2
  42. package/build/components/LoginDialog/LoginDialogForm.js +2 -14
  43. package/build/components/LoginDialog/LoginDialogFormError.js +3 -2
  44. package/build/components/Logo/Logo.js +13 -6
  45. package/build/components/Package/Package.js +43 -34
  46. package/build/components/Package/styles.js +46 -58
  47. package/build/components/Person/Person.js +48 -0
  48. package/build/components/Person/PersonTooltip.js +22 -0
  49. package/build/components/{Package/Tag → Person}/index.js +2 -2
  50. package/build/components/Person/utils.js +17 -0
  51. package/build/components/RawViewer/RawViewer.js +11 -5
  52. package/build/components/Readme/Readme.js +15 -6
  53. package/build/components/Readme/Readme.js.map +1 -1
  54. package/build/components/Readme/Readme.spec.js +19 -0
  55. package/build/components/Readme/Readme.spec.js.map +1 -1
  56. package/build/components/Readme/utils.js +2 -5
  57. package/build/components/RegistryInfoDialog/styles.js +9 -10
  58. package/build/components/Repository/Repository.js +19 -31
  59. package/build/components/Search/AutoComplete/styles.js +4 -41
  60. package/build/components/Search/Search.js +4 -2
  61. package/build/components/Search/SearchItem.js +51 -38
  62. package/build/components/Search/utils.js +23 -0
  63. package/build/components/SettingsMenu/SettingsMenu.js +35 -9
  64. package/build/components/SideBarTitle/SideBarTitle.js +16 -6
  65. package/build/components/UpLinks/UpLinks.js +35 -6
  66. package/build/components/UpLinks/UplinkLink.js +22 -0
  67. package/build/components/UpLinks/styles.js +5 -4
  68. package/build/components/Versions/HistoryList.js +8 -5
  69. package/build/components/Versions/TagList.js +8 -4
  70. package/build/components/Versions/Versions.js +30 -7
  71. package/build/index.js +27 -3
  72. package/build/providers/AppConfigurationProvider/AppConfigurationProvider.js +1 -0
  73. package/build/providers/PersistenceSettingProvider/PersistenceSettingProvider.js +1 -0
  74. package/build/sections/Detail/Detail.js +6 -2
  75. package/build/sections/Detail/Tabs.js +4 -3
  76. package/build/sections/Footer/Footer.js +17 -8
  77. package/build/sections/Footer/styles.js +13 -10
  78. package/build/sections/Header/HeaderLeft.js +14 -17
  79. package/build/sections/Header/HeaderMenu.js +1 -1
  80. package/build/sections/Header/HeaderRight.js +12 -3
  81. package/build/sections/Header/HeaderSettingsDialog.js +2 -2
  82. package/build/sections/Header/styles.js +43 -82
  83. package/build/sections/SideBar/Sidebar.js +10 -15
  84. package/build/src/Theme/ThemeProvider.test.d.ts +1 -0
  85. package/build/src/components/Author/Author.d.ts +0 -5
  86. package/build/src/components/CopyClipboard/CopyToClipBoard.test.d.ts +1 -0
  87. package/build/src/components/Dependencies/Dependencies.d.ts +0 -1
  88. package/build/src/components/Developers/DeveloperType.d.ts +4 -0
  89. package/build/src/components/Developers/Developers.d.ts +1 -4
  90. package/build/src/components/Developers/Title.d.ts +1 -4
  91. package/build/src/components/Developers/index.d.ts +2 -1
  92. package/build/src/components/Distribution/styles.d.ts +0 -1
  93. package/build/src/components/ErrorBoundary/ErrorBoundary.test.d.ts +1 -0
  94. package/build/src/components/HeaderInfoDialog/HeaderInfoDialog.test.d.ts +1 -0
  95. package/build/src/components/Heading/Heading.test.d.ts +1 -0
  96. package/build/src/components/Icons/Icons.test.d.ts +1 -0
  97. package/build/src/components/Install/InstallListItem.d.ts +1 -1
  98. package/build/src/components/Keywords/KeywordListItems.d.ts +5 -0
  99. package/build/src/components/Keywords/Keywords.d.ts +6 -0
  100. package/build/src/components/Keywords/Keywords.stories.d.ts +5 -0
  101. package/build/src/components/Keywords/Keywords.test.d.ts +1 -0
  102. package/build/src/components/Keywords/index.d.ts +1 -0
  103. package/build/src/components/Link/Link.d.ts +0 -3
  104. package/build/src/components/Link/Link.test.d.ts +1 -0
  105. package/build/src/components/Link/index.d.ts +1 -1
  106. package/build/src/components/LinkExternal/LinkExternal.d.ts +3 -0
  107. package/build/src/components/LinkExternal/LinkExternal.test.d.ts +1 -0
  108. package/build/src/components/LinkExternal/index.d.ts +1 -0
  109. package/build/src/components/Logo/Logo.d.ts +1 -0
  110. package/build/src/components/Logo/Logo.stories.d.ts +5 -0
  111. package/build/src/components/Package/Package.d.ts +1 -1
  112. package/build/src/components/Package/styles.d.ts +0 -8
  113. package/build/src/components/Person/Person.d.ts +9 -0
  114. package/build/src/components/Person/Person.test.d.ts +1 -0
  115. package/build/src/components/Person/PersonTooltip.d.ts +6 -0
  116. package/build/src/components/Person/index.d.ts +1 -0
  117. package/build/src/components/Person/utils.d.ts +3 -0
  118. package/build/src/components/Readme/Readme.d.ts +0 -1
  119. package/build/src/components/Search/AutoComplete/styles.d.ts +0 -8
  120. package/build/src/components/Search/utils.d.ts +1 -0
  121. package/build/src/components/SettingsMenu/SettingsMenu.d.ts +2 -2
  122. package/build/src/components/SettingsMenu/SettingsMenu.test.d.ts +1 -0
  123. package/build/src/components/UpLinks/UplinkLink.d.ts +6 -0
  124. package/build/src/components/Versions/Versions.d.ts +1 -0
  125. package/build/src/index.d.ts +4 -1
  126. package/build/src/sections/Detail/Tabs.d.ts +1 -0
  127. package/build/src/sections/Header/styles.d.ts +0 -7
  128. package/build/src/store/models/routes.d.ts +8 -0
  129. package/build/src/store/models/utils.d.ts +1 -0
  130. package/build/src/types/packageMeta.d.ts +7 -5
  131. package/build/src/utils/routes.d.ts +1 -0
  132. package/build/src/utils/utils.d.ts +1 -0
  133. package/build/store/models/configuration.js +2 -1
  134. package/build/store/models/login.js +4 -2
  135. package/build/store/models/manifest.js +5 -3
  136. package/build/store/models/packages.js +4 -2
  137. package/build/store/models/routes.js +18 -0
  138. package/build/store/models/search.js +4 -2
  139. package/build/store/models/utils.js +10 -0
  140. package/build/utils/routes.js +1 -0
  141. package/build/utils/utils.js +20 -1
  142. package/package.json +2 -2
  143. package/src/AppTest/AppRoute.test.tsx +65 -0
  144. package/src/Theme/ThemeProvider.test.tsx +27 -0
  145. package/src/Theme/theme.ts +3 -3
  146. package/src/components/ActionBar/ActionBar.test.tsx +36 -15
  147. package/src/components/ActionBar/ActionBar.tsx +1 -1
  148. package/src/components/ActionBar/ActionBarAction.tsx +8 -5
  149. package/src/components/Author/Author.test.tsx +7 -1
  150. package/src/components/Author/Author.tsx +3 -41
  151. package/src/components/CopyClipboard/CopyToClipBoard.test.tsx +23 -0
  152. package/src/components/CopyClipboard/utils.ts +2 -13
  153. package/src/components/Dependencies/Dependencies.tsx +9 -9
  154. package/src/components/Dependencies/DependencyBlock.tsx +2 -1
  155. package/src/components/Developers/DeveloperType.tsx +4 -0
  156. package/src/components/Developers/Developers.test.tsx +37 -10
  157. package/src/components/Developers/Developers.tsx +13 -13
  158. package/src/components/Developers/Title.tsx +1 -5
  159. package/src/components/Developers/index.ts +2 -1
  160. package/src/components/Distribution/Dist.test.tsx +1 -1
  161. package/src/components/Distribution/Dist.tsx +2 -4
  162. package/src/components/Distribution/styles.ts +0 -6
  163. package/src/components/Engines/Engines.tsx +6 -2
  164. package/src/components/Engines/styles.ts +1 -1
  165. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +39 -0
  166. package/src/components/FundButton/FundButton.tsx +5 -5
  167. package/src/components/HeaderInfoDialog/HeaderInfoDialog.test.tsx +51 -0
  168. package/src/components/HeaderInfoDialog/HeaderInfoDialog.tsx +2 -2
  169. package/src/components/Heading/Heading.test.tsx +20 -0
  170. package/src/components/Icons/DevsIcons/CommonJS.tsx +1 -7
  171. package/src/components/Icons/DevsIcons/ES6Module.tsx +2 -8
  172. package/src/components/Icons/DevsIcons/Git.tsx +1 -7
  173. package/src/components/Icons/DevsIcons/NodeJS.tsx +1 -7
  174. package/src/components/Icons/DevsIcons/TypeScript.tsx +1 -7
  175. package/src/components/Icons/FileBinary.tsx +2 -1
  176. package/src/components/Icons/Icons.stories.tsx +21 -5
  177. package/src/components/Icons/Icons.test.tsx +70 -0
  178. package/src/components/Icons/Law.tsx +2 -1
  179. package/src/components/Icons/Managers/Npm.tsx +1 -7
  180. package/src/components/Icons/Managers/Pnpm.tsx +1 -7
  181. package/src/components/Icons/Managers/Yarn.tsx +1 -7
  182. package/src/components/Install/Install.test.tsx +54 -13
  183. package/src/components/Install/Install.tsx +12 -11
  184. package/src/components/Install/InstallListItem.tsx +12 -11
  185. package/src/components/Keywords/KeywordListItems.tsx +22 -0
  186. package/src/components/Keywords/Keywords.stories.tsx +19 -0
  187. package/src/components/Keywords/Keywords.test.tsx +57 -0
  188. package/src/components/Keywords/Keywords.tsx +35 -0
  189. package/src/components/Keywords/index.ts +1 -0
  190. package/src/components/Link/Link.test.tsx +25 -0
  191. package/src/components/Link/Link.tsx +4 -18
  192. package/src/components/Link/index.ts +1 -1
  193. package/src/components/LinkExternal/LinkExternal.test.tsx +18 -0
  194. package/src/components/LinkExternal/LinkExternal.tsx +22 -0
  195. package/src/components/LinkExternal/index.ts +1 -0
  196. package/src/components/Loading/Loading.test.tsx +8 -5
  197. package/src/components/Loading/styles.ts +1 -0
  198. package/src/components/LoginDialog/LoginDialog.test.tsx +1 -1
  199. package/src/components/LoginDialog/LoginDialog.tsx +10 -1
  200. package/src/components/LoginDialog/LoginDialogCloseButton.tsx +1 -0
  201. package/src/components/LoginDialog/LoginDialogForm.tsx +0 -2
  202. package/src/components/LoginDialog/LoginDialogFormError.tsx +1 -1
  203. package/src/components/Logo/Logo.stories.tsx +16 -0
  204. package/src/components/Logo/Logo.test.tsx +8 -1
  205. package/src/components/Logo/Logo.tsx +19 -3
  206. package/src/components/Package/Package.test.tsx +47 -14
  207. package/src/components/Package/Package.tsx +41 -44
  208. package/src/components/Package/styles.ts +7 -17
  209. package/src/components/PackageList/Packagelist.test.tsx +1 -0
  210. package/src/components/Person/Person.test.tsx +50 -0
  211. package/src/components/Person/Person.tsx +45 -0
  212. package/src/components/Person/PersonTooltip.tsx +26 -0
  213. package/src/components/Person/index.ts +1 -0
  214. package/src/components/Person/utils.ts +20 -0
  215. package/src/components/RawViewer/RawViewer.tsx +8 -4
  216. package/src/components/Readme/Readme.spec.tsx +17 -0
  217. package/src/components/Readme/Readme.tsx +10 -5
  218. package/src/components/Readme/utils.ts +2 -5
  219. package/src/components/RegistryInfoDialog/styles.ts +5 -4
  220. package/src/components/Repository/Repository.tsx +9 -14
  221. package/src/components/Search/AutoComplete/styles.ts +7 -0
  222. package/src/components/Search/Search.test.tsx +36 -9
  223. package/src/components/Search/Search.tsx +4 -2
  224. package/src/components/Search/SearchItem.tsx +19 -8
  225. package/src/components/Search/utils.ts +17 -0
  226. package/src/components/SettingsMenu/SettingsMenu.test.tsx +41 -0
  227. package/src/components/SettingsMenu/SettingsMenu.tsx +48 -10
  228. package/src/components/SideBarTitle/SideBarTitle.tsx +19 -3
  229. package/src/components/UpLinks/UpLinks.test.tsx +7 -0
  230. package/src/components/UpLinks/UpLinks.tsx +38 -15
  231. package/src/components/UpLinks/UplinkLink.tsx +20 -0
  232. package/src/components/UpLinks/styles.ts +1 -0
  233. package/src/components/Versions/HistoryList.tsx +9 -4
  234. package/src/components/Versions/TagList.tsx +4 -3
  235. package/src/components/Versions/Versions.test.tsx +2 -0
  236. package/src/components/Versions/Versions.tsx +57 -32
  237. package/src/index.ts +4 -1
  238. package/src/providers/AppConfigurationProvider/AppConfigurationProvider.tsx +1 -0
  239. package/src/providers/PersistenceSettingProvider/PersistenceSettingProvider.tsx +2 -0
  240. package/src/providers/VersionProvider/VersionProvider.test.tsx +3 -3
  241. package/src/sections/Detail/Detail.test.tsx +8 -1
  242. package/src/sections/Detail/Detail.tsx +11 -4
  243. package/src/sections/Detail/Tabs.tsx +5 -2
  244. package/src/sections/Footer/Footer.tsx +15 -4
  245. package/src/sections/Footer/styles.ts +4 -0
  246. package/src/sections/Header/Header.test.tsx +12 -10
  247. package/src/sections/Header/HeaderLeft.tsx +19 -11
  248. package/src/sections/Header/HeaderMenu.tsx +1 -1
  249. package/src/sections/Header/HeaderRight.tsx +14 -3
  250. package/src/sections/Header/HeaderSettingsDialog.tsx +1 -1
  251. package/src/sections/Header/RegistryInfoContent/RegistryInfoContent.test.tsx +1 -1
  252. package/src/sections/Header/styles.ts +4 -16
  253. package/src/sections/Home/Home.test.tsx +12 -4
  254. package/src/sections/SideBar/Sidebar.test.tsx +20 -13
  255. package/src/sections/SideBar/Sidebar.tsx +5 -9
  256. package/src/store/api.test.ts +16 -0
  257. package/src/store/models/configuration.ts +2 -1
  258. package/src/store/models/login.ts +10 -12
  259. package/src/store/models/manifest.ts +6 -5
  260. package/src/store/models/packages.ts +4 -5
  261. package/src/store/models/routes.ts +10 -0
  262. package/src/store/models/search.ts +4 -2
  263. package/src/store/models/utils.ts +3 -0
  264. package/src/types/packageMeta.ts +7 -5
  265. package/src/utils/routes.ts +1 -0
  266. package/src/utils/utils.test.ts +34 -0
  267. package/src/utils/utils.ts +20 -5
  268. package/tsconfig.json +1 -1
  269. package/build/components/Developers/styles.js +0 -65
  270. package/build/components/Distribution/utils.js +0 -25
  271. package/build/components/Distribution/utilts.spec.js +0 -18
  272. package/build/components/Package/Tag/Tag.js +0 -14
  273. package/build/components/Package/Tag/styles.js +0 -24
  274. package/build/sections/Header/RegistryInfoDialog/RegistryInfoDialog.js +0 -36
  275. package/build/sections/Header/RegistryInfoDialog/styles.js +0 -46
  276. package/build/sections/Header/RegistryInfoDialog/types.js +0 -6
  277. package/build/src/components/Developers/styles.d.ts +0 -11
  278. package/build/src/components/Distribution/utils.d.ts +0 -7
  279. package/build/src/components/Package/Tag/Tag.d.ts +0 -6
  280. package/build/src/components/Package/Tag/index.d.ts +0 -1
  281. package/build/src/components/Package/Tag/styles.d.ts +0 -5
  282. package/build/src/sections/Header/RegistryInfoDialog/RegistryInfoDialog.d.ts +0 -4
  283. package/build/src/sections/Header/RegistryInfoDialog/index.d.ts +0 -1
  284. package/build/src/sections/Header/RegistryInfoDialog/styles.d.ts +0 -13
  285. package/build/src/sections/Header/RegistryInfoDialog/types.d.ts +0 -7
  286. package/src/components/Developers/styles.ts +0 -31
  287. package/src/components/Distribution/utils.ts +0 -32
  288. package/src/components/Distribution/utilts.spec.ts +0 -17
  289. package/src/components/Package/Tag/Tag.test.tsx +0 -15
  290. package/src/components/Package/Tag/Tag.tsx +0 -11
  291. package/src/components/Package/Tag/index.ts +0 -1
  292. package/src/components/Package/Tag/styles.ts +0 -11
  293. package/src/components/Search/AutoComplete/styles.tsx +0 -42
  294. package/src/sections/Header/RegistryInfoDialog/RegistryInfoDialog.tsx +0 -31
  295. package/src/sections/Header/RegistryInfoDialog/index.ts +0 -1
  296. package/src/sections/Header/RegistryInfoDialog/styles.ts +0 -21
  297. package/src/sections/Header/RegistryInfoDialog/types.ts +0 -8
  298. /package/build/components/Icons/DevsIcons/{es6modules.svg → es6module.svg} +0 -0
  299. /package/build/src/{components/Package/Tag/Tag.test.d.ts → AppTest/AppRoute.test.d.ts} +0 -0
  300. /package/src/components/Icons/DevsIcons/{es6modules.svg → es6module.svg} +0 -0
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.Route = void 0;
7
7
  let Route = exports.Route = /*#__PURE__*/function (Route) {
8
8
  Route["ROOT"] = "/";
9
+ Route["DETAIL"] = "/-/web/detail/";
9
10
  Route["SCOPE_PACKAGE"] = "/-/web/detail/@:scope/:package";
10
11
  Route["SCOPE_PACKAGE_VERSION"] = "/-/web/detail/@:scope/:package/v/:version";
11
12
  Route["PACKAGE"] = "/-/web/detail/:package";
@@ -12,6 +12,7 @@ exports.formatRepository = formatRepository;
12
12
  exports.getAuthorName = getAuthorName;
13
13
  exports.getLastUpdatedPackageTime = getLastUpdatedPackageTime;
14
14
  exports.getRecentReleases = getRecentReleases;
15
+ exports.getUplink = getUplink;
15
16
  var _dayjs = _interopRequireDefault(require("dayjs"));
16
17
  var _localizedFormat = _interopRequireDefault(require("dayjs/plugin/localizedFormat"));
17
18
  var _relativeTime = _interopRequireDefault(require("dayjs/plugin/relativeTime"));
@@ -96,7 +97,25 @@ function getAuthorName(authorName) {
96
97
  }
97
98
  return authorName;
98
99
  }
100
+ function getUplink(upLinkName, packageName) {
101
+ // TODO: make this a config like "uplinks: npmjs: web: https://www.npmjs.com/package/"
102
+ switch (upLinkName) {
103
+ case 'npmjs':
104
+ return `https://www.npmjs.com/package/${packageName}`;
105
+ }
106
+ return null;
107
+ }
99
108
  function fileSizeSI(a, b, c, d, e) {
100
- return (b = Math, c = b.log, d = 1e3, e = c(a) / c(d) | 0, a / b.pow(d, e)).toFixed(2) + ' ' + (e ? 'kMGTPEZY'[--e] + 'B' : 'Bytes');
109
+ b = Math;
110
+ c = b.log;
111
+ d = 1e3;
112
+ e = c(a) / c(d) | 0;
113
+ let size = a / b.pow(d, e);
114
+ // no decimals for Bytes
115
+ if (e === 0) {
116
+ return Math.floor(size) + ' Bytes';
117
+ } else {
118
+ return size.toFixed(1) + ' ' + 'kMGTPEZY'[--e] + 'B';
119
+ }
101
120
  }
102
121
  //# sourceMappingURL=utils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdaccio/ui-components",
3
- "version": "3.0.0-next-7.7",
3
+ "version": "3.0.0-next-7.8",
4
4
  "description": "theme ui component",
5
5
  "author": "Juan Picado <juanpicado19@gmail.com>",
6
6
  "license": "MIT",
@@ -63,7 +63,7 @@
63
63
  "@types/hast": "^2.0.0",
64
64
  "@types/react-router": "^5.1.20",
65
65
  "@types/unist": "^2.0.0",
66
- "@verdaccio/types": "12.0.0-next-7.4",
66
+ "@verdaccio/types": "12.0.0-next-7.5",
67
67
  "babel-loader": "^8.3.0",
68
68
  "mockdate": "3.0.5",
69
69
  "msw": "0.49.3",
@@ -0,0 +1,65 @@
1
+ import React from 'react';
2
+ import { MemoryRouter } from 'react-router';
3
+
4
+ import { store } from '../';
5
+ import { act, renderWithStore, screen, waitFor } from '../test/test-react-testing-library';
6
+ import AppRoute from './AppRoute';
7
+
8
+ // force the windows to expand to display items
9
+ // https://github.com/bvaughn/react-virtualized/issues/493#issuecomment-640084107
10
+ jest.spyOn(HTMLElement.prototype, 'offsetHeight', 'get').mockReturnValue(600);
11
+ jest.spyOn(HTMLElement.prototype, 'offsetWidth', 'get').mockReturnValue(600);
12
+
13
+ function appTest(path: string) {
14
+ renderWithStore(
15
+ <MemoryRouter initialEntries={[path]}>
16
+ <AppRoute />
17
+ </MemoryRouter>,
18
+ store
19
+ );
20
+ }
21
+
22
+ // See jest/server-handlers.ts for test routes
23
+ describe('AppRoute', () => {
24
+ afterEach(() => {
25
+ jest.clearAllMocks();
26
+ });
27
+
28
+ test('renders Front component for ROOT path', async () => {
29
+ act(() => appTest('/'));
30
+ await waitFor(() => expect(screen.getByTestId('loading')).toBeInTheDocument());
31
+ await waitFor(() => expect(screen.getAllByTestId('package-item-list')).toHaveLength(5));
32
+ });
33
+
34
+ test('renders VersionPage component for PACKAGE path', async () => {
35
+ act(() => appTest('/-/web/detail/jquery'));
36
+ await waitFor(() => screen.getByTestId('readme-tab'));
37
+ expect(screen.getByTestId('sidebar')).toBeInTheDocument();
38
+ });
39
+
40
+ test('renders VersionPage component for PACKAGE VERSION path', async () => {
41
+ act(() => appTest('/-/web/detail/jquery/v/3.6.3'));
42
+ await waitFor(() => screen.getByTestId('readme-tab'));
43
+ expect(screen.getByTestId('sidebar')).toBeInTheDocument();
44
+ });
45
+
46
+ test('renders Forbidden component for not allowed PACKAGE', async () => {
47
+ act(() => appTest('/-/web/detail/JSONstream'));
48
+ await waitFor(() => screen.getByTestId('not-found-go-to-home-button'));
49
+ });
50
+
51
+ test('renders NotFound component for missing PACKAGE', async () => {
52
+ act(() => appTest('/-/web/detail/kleur'));
53
+ await waitFor(() => screen.getByTestId('not-found-go-to-home-button'));
54
+ });
55
+
56
+ test('renders NotFound component for non-existing PACKAGE VERSION', async () => {
57
+ act(() => appTest('/-/web/detail/jquery/v/0.9.9'));
58
+ await waitFor(() => screen.getByTestId('not-found-go-to-home-button'));
59
+ });
60
+
61
+ test('renders NotFound component for non-matching path', async () => {
62
+ act(() => appTest('/oiccadrev'));
63
+ await waitFor(() => screen.getByTestId('not-found-go-to-home-button'));
64
+ });
65
+ });
@@ -0,0 +1,27 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+
4
+ import {
5
+ AppConfigurationProvider,
6
+ PersistenceSettingProvider,
7
+ StyleBaseline,
8
+ ThemeProvider,
9
+ } from '../';
10
+
11
+ const AppContainer = () => (
12
+ <AppConfigurationProvider>
13
+ <ThemeProvider>
14
+ <StyleBaseline />
15
+ <PersistenceSettingProvider>
16
+ <div>{'Theme'}</div>
17
+ </PersistenceSettingProvider>
18
+ </ThemeProvider>
19
+ </AppConfigurationProvider>
20
+ );
21
+
22
+ describe('ThemeProvider', () => {
23
+ test('should render with theme', async () => {
24
+ render(<AppContainer />);
25
+ await screen.findByText('Theme');
26
+ });
27
+ });
@@ -6,11 +6,11 @@ const colors = {
6
6
  black: '#000',
7
7
  white: '#fff',
8
8
  red: '#d32f2f',
9
- orange: '#CD4000',
9
+ orange: '#cd4000',
10
10
  greySuperLight: '#f5f5f5',
11
11
  greyLight: '#d3d3d3',
12
12
  greyLight2: '#908ba1',
13
- greyLight3: '#f3f4f240',
13
+ greyLight3: '#f3f4f2',
14
14
  greyDark: '#a9a9a9',
15
15
  greyDark2: '#586069',
16
16
  greyChateau: '#95989a',
@@ -38,7 +38,7 @@ const themeModes = {
38
38
  ...colors,
39
39
  primary: '#ffffff',
40
40
  secondary: '#424242',
41
- background: '#1A202C',
41
+ background: '#1a202c',
42
42
  },
43
43
  };
44
44
 
@@ -1,28 +1,22 @@
1
1
  import React from 'react';
2
2
 
3
3
  import { store } from '../../store/store';
4
- import {
5
- cleanup,
6
- fireEvent,
7
- renderWithStore,
8
- screen,
9
- waitFor,
10
- } from '../../test/test-react-testing-library';
4
+ import { cleanup, fireEvent, renderWithStore, screen } from '../../test/test-react-testing-library';
11
5
  import ActionBar from './ActionBar';
12
6
 
13
7
  const defaultPackageMeta = {
14
8
  _uplinks: {},
15
9
  latest: {
16
- name: 'verdaccio-ui/local-storage',
17
- version: '8.0.1-next.1',
10
+ name: 'verdaccio',
11
+ version: '1.0.0',
18
12
  dist: {
19
- fileCount: 0,
20
- unpackedSize: 0,
21
- tarball: 'http://localhost:8080/bootstrap/-/bootstrap-4.3.1.tgz',
13
+ fileCount: 1,
14
+ unpackedSize: 171,
15
+ tarball: 'http://localhost:9000/verdaccio/-/verdaccio-1.0.0.tgz',
22
16
  },
23
17
  homepage: 'https://verdaccio.org',
24
18
  bugs: {
25
- url: 'https://github.com/verdaccio/monorepo/issues',
19
+ url: 'https://github.com/verdaccio/verdaccio/issues',
26
20
  },
27
21
  },
28
22
  };
@@ -39,6 +33,12 @@ describe('<ActionBar /> component', () => {
39
33
  expect(screen.getByTestId('HomeIcon')).toBeInTheDocument();
40
34
  });
41
35
 
36
+ test('should not render if data is missing', () => {
37
+ // @ts-ignore - testing with missing data
38
+ renderWithStore(<ActionBar packageMeta={undefined} />, store);
39
+ expect(screen.queryByTestId('HomeIcon')).toBeNull();
40
+ });
41
+
42
42
  test('when there is no action bar data', () => {
43
43
  const packageMeta = {
44
44
  ...defaultPackageMeta,
@@ -64,6 +64,14 @@ describe('<ActionBar /> component', () => {
64
64
  expect(screen.getByLabelText('action-bar-action.download-tarball')).toBeTruthy();
65
65
  });
66
66
 
67
+ test('when button to download is disabled', () => {
68
+ renderWithStore(
69
+ <ActionBar packageMeta={defaultPackageMeta} showDownloadTarball={false} />,
70
+ store
71
+ );
72
+ expect(screen.queryByTestId('download-tarball-btn')).not.toBeInTheDocument();
73
+ });
74
+
67
75
  test('when there is a button to raw manifest', () => {
68
76
  renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={true} />, store);
69
77
  expect(screen.getByLabelText('action-bar-action.raw')).toBeTruthy();
@@ -71,15 +79,28 @@ describe('<ActionBar /> component', () => {
71
79
 
72
80
  test('when click button to raw manifest open a dialog with viewer', async () => {
73
81
  renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={true} />, store);
82
+ expect(screen.queryByTestId('rawViewer--dialog')).toBeFalsy();
83
+
74
84
  fireEvent.click(screen.getByLabelText('action-bar-action.raw'));
75
- await waitFor(() => expect(screen.getByTestId('rawViewer--dialog')).toBeInTheDocument());
85
+ await screen.findByTestId('rawViewer--dialog');
86
+
87
+ fireEvent.click(screen.getByTestId('close-raw-viewer'));
88
+ await screen.getByLabelText('action-bar-action.raw');
89
+
90
+ expect(screen.queryByTestId('rawViewer--dialog')).toBeFalsy();
76
91
  });
77
92
 
78
93
  test('should not display download tarball button', () => {
79
- renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={true} />, store);
94
+ renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={false} />, store);
80
95
  expect(screen.queryByLabelText('Download tarball')).toBeFalsy();
81
96
  });
82
97
 
98
+ test('when click button to download ', async () => {
99
+ renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={false} />, store);
100
+ fireEvent.click(screen.getByTestId('download-tarball-btn'));
101
+ await store.getState().loading.models.download;
102
+ });
103
+
83
104
  test('should not display show raw button', () => {
84
105
  renderWithStore(<ActionBar packageMeta={defaultPackageMeta} showRaw={false} />, store);
85
106
  expect(screen.queryByLabelText('action-bar-action.raw')).toBeFalsy();
@@ -41,7 +41,7 @@ const ActionBar: React.FC<Props> = ({ showRaw, showDownloadTarball = true, packa
41
41
  }
42
42
 
43
43
  return (
44
- <Box alignItems="center" display="flex" marginBottom="14px">
44
+ <Box alignItems="center" display="flex" sx={{ my: 2 }}>
45
45
  <Stack direction="row" spacing={1}>
46
46
  {actions.map((action) => (
47
47
  <ActionBarAction key={action.type} {...action} />
@@ -12,11 +12,14 @@ import { useDispatch, useSelector } from 'react-redux';
12
12
 
13
13
  import { Theme } from '../../Theme';
14
14
  import { Dispatch, RootState } from '../../store/store';
15
- import { Link } from '../Link';
15
+ import LinkExternal from '../LinkExternal';
16
16
 
17
17
  export const Fab = styled(FabMUI)<{ theme?: Theme }>(({ theme }) => ({
18
18
  backgroundColor:
19
19
  theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.cyanBlue,
20
+ '&:hover': {
21
+ color: theme?.palette.mode === 'light' ? theme?.palette.primary.main : theme?.palette.cyanBlue,
22
+ },
20
23
  color: theme?.palette.white,
21
24
  }));
22
25
 
@@ -42,21 +45,21 @@ const ActionBarAction: React.FC<ActionBarActionProps> = ({ type, link, action })
42
45
  case 'VISIT_HOMEPAGE':
43
46
  return (
44
47
  <Tooltip title={t('action-bar-action.visit-home-page') as string}>
45
- <Link external={true} to={link} variant="button">
48
+ <LinkExternal to={link} variant="button">
46
49
  <Fab size="small">
47
50
  <HomeIcon />
48
51
  </Fab>
49
- </Link>
52
+ </LinkExternal>
50
53
  </Tooltip>
51
54
  );
52
55
  case 'OPEN_AN_ISSUE':
53
56
  return (
54
57
  <Tooltip title={t('action-bar-action.open-an-issue') as string}>
55
- <Link external={true} to={link} variant="button">
58
+ <LinkExternal to={link} variant="button">
56
59
  <Fab size="small">
57
60
  <BugReportIcon />
58
61
  </Fab>
59
- </Link>
62
+ </LinkExternal>
60
63
  </Tooltip>
61
64
  );
62
65
  case 'DOWNLOAD_TARBALL':
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
 
3
- import { cleanup, render } from '../../test/test-react-testing-library';
3
+ import { cleanup, render, screen } from '../../test/test-react-testing-library';
4
4
  import { PackageMetaInterface } from '../../types/packageMeta';
5
5
  import Authors from './Author';
6
6
 
@@ -66,4 +66,10 @@ describe('<Author /> component', () => {
66
66
  const wrapper = render(withAuthorComponent(packageMeta));
67
67
  expect(wrapper).toMatchSnapshot();
68
68
  });
69
+
70
+ test('should not render if data is missing', () => {
71
+ // @ts-ignore - testing with missing data
72
+ render(withAuthorComponent(undefined));
73
+ expect(screen.queryByText('sidebar.author.title')).toBeNull();
74
+ });
69
75
  });
@@ -1,35 +1,13 @@
1
- import { Typography } from '@mui/material';
2
- import Avatar from '@mui/material/Avatar';
3
1
  import List from '@mui/material/List';
4
- import { useTheme } from '@mui/styles';
5
- import i18next from 'i18next';
6
2
  import React, { FC } from 'react';
7
3
  import { useTranslation } from 'react-i18next';
8
4
 
9
- import { url } from '../../utils';
5
+ import Person from '../Person';
10
6
  import { AuthorListItem, StyledText } from './styles';
11
7
 
12
- export function getAuthorName(authorName?: string): string {
13
- if (!authorName) {
14
- return i18next.t('author-unknown');
15
- }
16
-
17
- if (authorName.toLowerCase() === 'anonymous') {
18
- return i18next.t('author-anonymous');
19
- }
20
-
21
- return authorName;
22
- }
23
-
24
- /**
25
- * @param param0
26
- * @returns
27
- */
28
8
  const Author: FC<{ packageMeta }> = ({ packageMeta }) => {
29
9
  const { t } = useTranslation();
30
10
 
31
- const theme = useTheme();
32
-
33
11
  if (!packageMeta) {
34
12
  return null;
35
13
  }
@@ -40,26 +18,10 @@ const Author: FC<{ packageMeta }> = ({ packageMeta }) => {
40
18
  return null;
41
19
  }
42
20
 
43
- const { email, name } = author;
44
- const avatarComponent = (
45
- <Avatar
46
- alt={author.name}
47
- src={author.avatar}
48
- sx={{ width: 40, height: 40, marginRight: theme.spacing(1) }}
49
- />
50
- );
51
-
52
21
  return (
53
22
  <List subheader={<StyledText variant={'subtitle1'}>{t('sidebar.author.title')}</StyledText>}>
54
- <AuthorListItem>
55
- {!email || !url.isEmail(email) ? (
56
- avatarComponent
57
- ) : (
58
- <a href={`mailto:${email}?subject=${packageName}@${version}`} target={'_top'}>
59
- {avatarComponent}
60
- </a>
61
- )}
62
- {name && <Typography variant="subtitle2">{getAuthorName(name)}</Typography>}
23
+ <AuthorListItem sx={{ my: 1 }}>
24
+ <Person packageName={packageName} person={author} version={version} withText={true} />
63
25
  </AuthorListItem>
64
26
  </List>
65
27
  );
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+
3
+ import { fireEvent, render, screen } from '../../test/test-react-testing-library';
4
+ import CopyToClipBoard from './CopyToClipBoard';
5
+
6
+ Object.assign(navigator, {
7
+ clipboard: { writeText: jest.fn().mockImplementation(() => Promise.resolve()) },
8
+ });
9
+
10
+ describe('CopyToClipBoard component', () => {
11
+ test('should copy text to clipboard', async () => {
12
+ const copyThis = 'copy this';
13
+ render(
14
+ <CopyToClipBoard dataTestId={'copy-component'} text={copyThis} title={`npm i verdaccio`} />
15
+ );
16
+ expect(screen.getByTestId('copy-component')).toBeInTheDocument();
17
+
18
+ const copyComponent = await screen.findByTestId('copy-component');
19
+ await fireEvent.click(copyComponent);
20
+
21
+ expect(navigator.clipboard.writeText).toHaveBeenCalledWith(copyThis);
22
+ });
23
+ });
@@ -5,17 +5,6 @@ export const copyToClipBoardUtility =
5
5
  (event: SyntheticEvent<HTMLElement>): void => {
6
6
  event.preventDefault();
7
7
 
8
- const node = document.createElement('div');
9
- node.innerText = str;
10
- if (document.body) {
11
- document.body.appendChild(node);
12
-
13
- const range = document.createRange();
14
- const selection = window.getSelection() as Selection;
15
- range.selectNodeContents(node);
16
- selection.removeAllRanges();
17
- selection.addRange(range);
18
- document.execCommand('copy');
19
- document.body.removeChild(node);
20
- }
8
+ // document.execCommand is deprecated
9
+ navigator.clipboard.writeText(str);
21
10
  };
@@ -1,19 +1,13 @@
1
- import styled from '@emotion/styled';
2
1
  import Box from '@mui/material/Box';
3
2
  import Card from '@mui/material/Card';
4
3
  import CardContent from '@mui/material/CardContent';
5
4
  import React, { Fragment } from 'react';
6
5
  import { useTranslation } from 'react-i18next';
7
6
 
8
- import { Theme } from '../../Theme';
9
7
  import NoItems from '../NoItems';
10
8
  import { DependencyBlock } from './DependencyBlock';
11
9
  import { hasKeys } from './utits';
12
10
 
13
- export const CardWrap = styled(Card)<{ theme?: Theme }>((props) => ({
14
- marginBottom: props.theme.spacing(2),
15
- }));
16
-
17
11
  const Dependencies: React.FC<{ packageMeta: any }> = ({ packageMeta }) => {
18
12
  const { t } = useTranslation();
19
13
 
@@ -43,7 +37,7 @@ const Dependencies: React.FC<{ packageMeta: any }> = ({ packageMeta }) => {
43
37
  hasKeys(peerDependencies);
44
38
  if (hasDependencies) {
45
39
  return (
46
- <CardWrap>
40
+ <Card sx={{ mb: 2 }}>
47
41
  <CardContent>
48
42
  <Box data-testid="dependencies-box" sx={{ m: 2 }}>
49
43
  {Object.entries(dependencyMap).map(([dependencyType, dependencies]) => {
@@ -62,11 +56,17 @@ const Dependencies: React.FC<{ packageMeta: any }> = ({ packageMeta }) => {
62
56
  })}
63
57
  </Box>
64
58
  </CardContent>
65
- </CardWrap>
59
+ </Card>
66
60
  );
67
61
  }
68
62
 
69
- return <NoItems text={t('dependencies.has-no-dependencies', { package: name })} />;
63
+ return (
64
+ <Card sx={{ mb: 2 }}>
65
+ <CardContent>
66
+ <NoItems text={t('dependencies.has-no-dependencies', { package: name })} />
67
+ </CardContent>
68
+ </Card>
69
+ );
70
70
  };
71
71
 
72
72
  export default Dependencies;
@@ -9,6 +9,7 @@ import { useHistory } from 'react-router-dom';
9
9
 
10
10
  import { Theme } from '../../Theme';
11
11
  import { PackageDependencies } from '../../types/packageMeta';
12
+ import { Route } from '../../utils';
12
13
 
13
14
  interface DependencyBlockProps {
14
15
  title: string;
@@ -41,7 +42,7 @@ export const DependencyBlock: React.FC<DependencyBlockProps> = ({ title, depende
41
42
  const deps = Object.entries(dependencies);
42
43
 
43
44
  function handleClick(name: string): void {
44
- history.push(`/-/web/detail/${name}`);
45
+ history.push(`${Route.DETAIL}${name}`);
45
46
  }
46
47
 
47
48
  function labelText(title: string, name: string, version: string): string {
@@ -0,0 +1,4 @@
1
+ export enum DeveloperType {
2
+ CONTRIBUTORS = 'contributors',
3
+ MAINTAINERS = 'maintainers',
4
+ }
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
 
3
- import { cleanup, fireEvent, render } from '../../test/test-react-testing-library';
3
+ import { cleanup, fireEvent, render, screen } from '../../test/test-react-testing-library';
4
+ import { DeveloperType } from './DeveloperType';
4
5
  import Developers from './Developers';
5
- import { DeveloperType } from './Title';
6
6
 
7
7
  describe('test Developers', () => {
8
8
  afterEach(() => {
@@ -63,7 +63,7 @@ describe('test Developers', () => {
63
63
  expect(wrapper).toMatchSnapshot();
64
64
  });
65
65
 
66
- test('should test onClick the component avatar', () => {
66
+ test('should show only up to max items', () => {
67
67
  const packageMeta = {
68
68
  latest: {
69
69
  packageName: 'foo',
@@ -72,6 +72,7 @@ describe('test Developers', () => {
72
72
  {
73
73
  name: 'dmethvin',
74
74
  email: 'test@gmail.com',
75
+ url: 'https://example.com/',
75
76
  },
76
77
  {
77
78
  name: 'dmethvin2',
@@ -89,14 +90,40 @@ describe('test Developers', () => {
89
90
  <Developers packageMeta={packageMeta} type={DeveloperType.CONTRIBUTORS} visibleMax={1} />
90
91
  );
91
92
 
92
- // const item2 = wrapper.find(Fab);
93
- // // TODO: I am not sure here how to verify the method inside the component was called.
94
- // item2.simulate('click');
95
-
96
93
  expect(wrapper.getByText('sidebar.contributors.title')).toBeInTheDocument();
97
- fireEvent.click(wrapper.getByRole('button'));
94
+ expect(wrapper.getByTestId(packageMeta.latest.contributors[0].name)).toBeInTheDocument();
95
+ expect(wrapper.queryByTestId(packageMeta.latest.contributors[1].name)).not.toBeInTheDocument();
96
+ expect(wrapper.queryByTestId(packageMeta.latest.contributors[2].name)).not.toBeInTheDocument();
97
+ });
98
+
99
+ test('renders only the first six contributors when there are more than six', () => {
100
+ const packageMeta = {
101
+ latest: {
102
+ contributors: [
103
+ { name: 'contributor1', email: 'c1@test.com' },
104
+ { name: 'contributor2', email: 'c2@test.com' },
105
+ { name: 'contributor3', email: 'c3@test.com' },
106
+ { name: 'contributor4', email: 'c4@test.com' },
107
+ { name: 'contributor5', email: 'c5@test.com' },
108
+ { name: 'contributor6', email: 'c6@test.com' },
109
+ { name: 'contributor7', email: 'c7@test.com' },
110
+ ],
111
+ },
112
+ };
113
+
114
+ render(<Developers packageMeta={packageMeta} type={DeveloperType.CONTRIBUTORS} />);
115
+
116
+ expect(screen.getByTestId('contributor1')).toBeInTheDocument();
117
+ expect(screen.getByTestId('contributor2')).toBeInTheDocument();
118
+ expect(screen.getByTestId('contributor3')).toBeInTheDocument();
119
+ expect(screen.getByTestId('contributor4')).toBeInTheDocument();
120
+ expect(screen.getByTestId('contributor5')).toBeInTheDocument();
121
+ expect(screen.getByTestId('contributor6')).toBeInTheDocument();
122
+ expect(screen.queryByTestId('contributor7')).not.toBeInTheDocument();
123
+ expect(screen.getByTestId('fab-add')).toBeInTheDocument();
98
124
 
99
- expect(wrapper.getByLabelText(packageMeta.latest.contributors[0].name)).toBeInTheDocument();
100
- expect(wrapper.getByLabelText(packageMeta.latest.contributors[1].name)).toBeInTheDocument();
125
+ // click on "more"
126
+ fireEvent.click(screen.getByTestId('fab-add'));
127
+ expect(screen.getByTestId('contributor7')).toBeInTheDocument();
101
128
  });
102
129
  });
@@ -1,20 +1,15 @@
1
1
  import styled from '@emotion/styled';
2
2
  import Add from '@mui/icons-material/Add';
3
- import Avatar from '@mui/material/Avatar';
4
3
  import Box from '@mui/material/Box';
5
4
  import FabMUI from '@mui/material/Fab';
6
- import Tooltip from '@mui/material/Tooltip';
7
5
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
8
6
 
9
7
  import { Theme } from '../../Theme';
8
+ import Person from '../Person';
9
+ import { DeveloperType } from './DeveloperType';
10
10
  import Title from './Title';
11
11
  import getUniqueDeveloperValues from './get-unique-developer-values';
12
12
 
13
- export enum DeveloperType {
14
- CONTRIBUTORS = 'contributors',
15
- MAINTAINERS = 'maintainers',
16
- }
17
-
18
13
  export const Fab = styled(FabMUI)<{ theme?: Theme }>((props) => ({
19
14
  backgroundColor: props.theme?.palette.primary.main,
20
15
  color: props.theme?.palette.white,
@@ -28,7 +23,7 @@ interface Props {
28
23
 
29
24
  const StyledBox = styled(Box)({
30
25
  '> *': {
31
- margin: 5,
26
+ marginRight: 5,
32
27
  },
33
28
  });
34
29
 
@@ -58,19 +53,24 @@ const Developers: React.FC<Props> = ({ type, visibleMax = VISIBLE_MAX, packageMe
58
53
  return null;
59
54
  }
60
55
 
56
+ const { name: packageName, version } = packageMeta.latest;
57
+
61
58
  return (
62
59
  <>
63
60
  <Title type={type} />
64
61
  <StyledBox display="flex" flexWrap="wrap" margin="10px 0 10px 0">
65
- {visibleDevelopers.map((visibleDeveloper) => {
62
+ {visibleDevelopers.map((visibleDeveloper, index) => {
66
63
  return (
67
- <Tooltip key={visibleDeveloper.email} title={visibleDeveloper.name}>
68
- <Avatar alt={visibleDeveloper.name} src={visibleDeveloper.avatar} />
69
- </Tooltip>
64
+ <Person
65
+ key={index}
66
+ packageName={packageName}
67
+ person={visibleDeveloper}
68
+ version={version}
69
+ />
70
70
  );
71
71
  })}
72
72
  {visibleDevelopersMax < developers.length && (
73
- <Fab onClick={handleSetVisibleDevelopersMax} size="small">
73
+ <Fab data-testid={'fab-add'} onClick={handleSetVisibleDevelopersMax} size="small">
74
74
  <Add />
75
75
  </Fab>
76
76
  )}