@strapi/admin 4.5.0-beta.0 → 4.5.1

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 (264) hide show
  1. package/admin/src/StrapiApp.js +17 -6
  2. package/admin/src/assets/images/hot-air-balloon.png +0 -0
  3. package/admin/src/assets/images/icon_offline-cloud.svg +3 -3
  4. package/admin/src/assets/images/logo-strapi-2022.svg +7 -0
  5. package/admin/src/assets/images/upgrade-details.png +0 -0
  6. package/admin/src/content-manager/components/DynamicTable/CellContent/CellValue.js +1 -1
  7. package/admin/src/content-manager/components/DynamicTable/CellContent/RelationMultiple/index.js +5 -4
  8. package/admin/src/content-manager/components/DynamicTable/CellContent/index.js +10 -0
  9. package/admin/src/content-manager/components/DynamicTable/index.js +21 -4
  10. package/admin/src/content-manager/components/DynamicZone/components/{AddComponentButton/index.js → AddComponentButton.js} +12 -6
  11. package/admin/src/content-manager/components/DynamicZone/components/{ComponentPicker/Category/ComponentCard/index.js → ComponentCard.js} +8 -19
  12. package/admin/src/content-manager/components/DynamicZone/components/{ComponentPicker/Category/index.js → ComponentCategory.js} +19 -18
  13. package/admin/src/content-manager/components/DynamicZone/components/{ComponentPicker/index.js → ComponentPicker.js} +36 -38
  14. package/admin/src/content-manager/components/DynamicZone/components/DynamicComponent.js +195 -0
  15. package/admin/src/content-manager/components/DynamicZone/components/{DzLabel/index.js → DynamicZoneLabel.js} +13 -5
  16. package/admin/src/content-manager/components/DynamicZone/index.js +35 -116
  17. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +103 -60
  18. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +169 -162
  19. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +70 -16
  20. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findLeafByPathAndReplace.js +52 -0
  21. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/index.js +2 -0
  22. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/recursivelyFindPathsBasedOnCondition.js +72 -0
  23. package/admin/src/content-manager/components/FieldComponent/index.js +9 -2
  24. package/admin/src/content-manager/components/PreviewWysiwyg/index.js +1 -1
  25. package/admin/src/content-manager/components/RelationInput/RelationInput.js +80 -76
  26. package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js +95 -63
  27. package/admin/src/content-manager/components/RelationInputDataManager/utils/diffRelations.js +24 -0
  28. package/admin/src/content-manager/components/RelationInputDataManager/utils/index.js +2 -1
  29. package/admin/src/content-manager/components/RelationInputDataManager/utils/normalizeRelations.js +8 -29
  30. package/admin/src/content-manager/components/RelationInputDataManager/utils/normalizeSearchResults.js +8 -4
  31. package/admin/src/content-manager/components/RelationInputDataManager/utils/select.js +1 -0
  32. package/admin/src/content-manager/components/RepeatableComponent/index.js +4 -3
  33. package/admin/src/content-manager/hooks/__test__/usePrev.test.js +26 -0
  34. package/admin/src/content-manager/hooks/index.js +1 -0
  35. package/admin/src/content-manager/hooks/useFetchContentTypeLayout/utils/formatLayouts.js +19 -48
  36. package/admin/src/content-manager/hooks/usePrev.js +14 -0
  37. package/admin/src/content-manager/hooks/useRelation/useRelation.js +100 -7
  38. package/admin/src/content-manager/pages/App/reducer.js +3 -0
  39. package/admin/src/content-manager/pages/ListSettingsView/components/DraggableCard.js +3 -3
  40. package/admin/src/content-manager/pages/ListSettingsView/components/Settings.js +2 -2
  41. package/admin/src/content-manager/pages/ListSettingsView/components/SortDisplayedFields.js +1 -1
  42. package/admin/src/core/apis/CustomFields.js +0 -1
  43. package/admin/src/core/store/configureStore.js +17 -2
  44. package/admin/src/favicon.png +0 -0
  45. package/admin/src/hooks/useFetchMarketplacePlugins/index.js +2 -2
  46. package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +4 -2
  47. package/admin/src/hooks/useFetchMarketplaceProviders/index.js +3 -3
  48. package/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js +5 -3
  49. package/admin/src/index.js +1 -0
  50. package/admin/src/pages/App/index.js +1 -1
  51. package/admin/src/pages/HomePage/assets/corner-ornament.svg +48 -0
  52. package/admin/src/pages/HomePage/index.js +4 -3
  53. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/CardButton.js +110 -0
  54. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/InstallPluginButton.js +32 -21
  55. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/PackageStats.js +79 -0
  56. package/admin/src/pages/MarketplacePage/components/NpmPackageCard/index.js +28 -11
  57. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FilterSelect.js +42 -0
  58. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/FiltersPopover.js +96 -0
  59. package/admin/src/pages/MarketplacePage/components/NpmPackagesFilters/index.js +107 -0
  60. package/admin/src/pages/MarketplacePage/components/NpmPackagesGrid/index.js +4 -0
  61. package/admin/src/pages/MarketplacePage/components/SortSelect/index.js +70 -0
  62. package/admin/src/pages/MarketplacePage/index.js +68 -8
  63. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormApiTokenContainer/index.js +5 -4
  64. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormBody/index.js +4 -3
  65. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormHead/index.js +6 -2
  66. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Regenerate/index.js +1 -1
  67. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +5 -4
  68. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/schema.js +1 -1
  69. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/index.js +7 -38
  70. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/utils/options.js +31 -0
  71. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/index.js +32 -43
  72. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/index.js +1 -1
  73. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/components/RoleRow/index.js +3 -1
  74. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +2 -1
  75. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js +2 -2
  76. package/admin/src/translations/ca.json +1 -1
  77. package/admin/src/translations/de.json +1 -1
  78. package/admin/src/translations/dk.json +1 -1
  79. package/admin/src/translations/en.json +21 -7
  80. package/admin/src/translations/es.json +1 -1
  81. package/admin/src/translations/fr.json +1 -1
  82. package/admin/src/translations/gu.json +1 -1
  83. package/admin/src/translations/he.json +1 -1
  84. package/admin/src/translations/hi.json +1 -1
  85. package/admin/src/translations/hu.json +1 -1
  86. package/admin/src/translations/id.json +1 -1
  87. package/admin/src/translations/it.json +1 -1
  88. package/admin/src/translations/ja.json +1 -1
  89. package/admin/src/translations/ko.json +1 -1
  90. package/admin/src/translations/ml.json +1 -1
  91. package/admin/src/translations/nl.json +1 -1
  92. package/admin/src/translations/no.json +1 -1
  93. package/admin/src/translations/pl.json +1 -1
  94. package/admin/src/translations/pt-BR.json +15 -15
  95. package/admin/src/translations/ru.json +1 -1
  96. package/admin/src/translations/sa.json +1 -1
  97. package/admin/src/translations/sk.json +1 -1
  98. package/admin/src/translations/sv.json +118 -86
  99. package/admin/src/translations/th.json +1 -1
  100. package/admin/src/translations/zh-Hans.json +1 -1
  101. package/admin/src/translations/zh.json +1 -1
  102. package/build/1856.db9f5782.chunk.js +174 -0
  103. package/build/2077.fed8c9c3.chunk.js +206 -0
  104. package/build/2912.fccb2c43.chunk.js +259 -0
  105. package/build/4318.5e670740.chunk.js +30 -0
  106. package/build/{9166.8fcb3019.chunk.js → 4610.7614b003.chunk.js} +22 -21
  107. package/build/4715.8e33d630.chunk.js +387 -0
  108. package/build/{4800.d09f1225.chunk.js → 4800.a6935af6.chunk.js} +1 -1
  109. package/build/4982.9e58ea3f.chunk.js +325 -0
  110. package/build/617f9c948fa79e6d73bd.png +0 -0
  111. package/build/6925.bb6dd64d.chunk.js +762 -0
  112. package/build/6d21938306785f176538.png +0 -0
  113. package/build/70674f63fc3904c20de0.svg +7 -0
  114. package/build/{7379.d246dd38.chunk.js → 7379.e972985f.chunk.js} +1 -1
  115. package/build/7692.31e83caa.chunk.js +470 -0
  116. package/build/7841.4804bd98.chunk.js +259 -0
  117. package/build/7866.6db2248d.chunk.js +505 -0
  118. package/build/7e9af4fb7e723fcebf1f.svg +48 -0
  119. package/build/8380.37126e0d.chunk.js +299 -0
  120. package/build/8549.5e5fb6b6.chunk.js +159 -0
  121. package/build/8738.5a02bffb.chunk.js +463 -0
  122. package/build/{9066.26faf397.chunk.js → 9066.5d980488.chunk.js} +5 -5
  123. package/build/9420.7addc099.chunk.js +505 -0
  124. package/build/9649.b6afc945.chunk.js +199 -0
  125. package/build/9d5d788027e86620c234.svg +5 -0
  126. package/build/Admin-authenticatedApp.c07d2a86.chunk.js +80 -0
  127. package/build/{Admin_homePage.4b2be829.chunk.js → Admin_homePage.26d32e30.chunk.js} +5 -4
  128. package/build/Admin_marketplace.444ff7b8.chunk.js +22 -0
  129. package/build/Admin_settingsPage.bf2234e1.chunk.js +178 -0
  130. package/build/admin-app.b157c10a.chunk.js +112 -0
  131. package/build/{admin-edit-roles-page.4dd6bcb9.chunk.js → admin-edit-roles-page.69d9fcb2.chunk.js} +1 -1
  132. package/build/ca-json.07ae0f2c.chunk.js +1 -0
  133. package/build/content-manager.f38edbb6.chunk.js +1202 -0
  134. package/build/content-type-builder-translation-pt-BR-json.6fe3b8d1.chunk.js +1 -0
  135. package/build/content-type-builder-translation-sv-json.6deff030.chunk.js +1 -0
  136. package/build/{content-type-builder.a6e29716.chunk.js → content-type-builder.16af63a6.chunk.js} +13 -13
  137. package/build/de-json.6b3e1894.chunk.js +1 -0
  138. package/build/dk-json.144c6a8e.chunk.js +1 -0
  139. package/build/{email-settings-page.bfe6227f.chunk.js → email-settings-page.91c925a5.chunk.js} +6 -6
  140. package/build/email-translation-en-json.ebad8943.chunk.js +1 -0
  141. package/build/en-json.4a269f6b.chunk.js +1 -0
  142. package/build/es-json.6d123a82.chunk.js +1 -0
  143. package/build/fr-json.28ab54cb.chunk.js +1 -0
  144. package/build/gu-json.9a50ea64.chunk.js +1 -0
  145. package/build/he-json.72f18790.chunk.js +1 -0
  146. package/build/hi-json.0301b7ba.chunk.js +1 -0
  147. package/build/hu-json.c4b641bb.chunk.js +1 -0
  148. package/build/{i18n-settings-page.18166125.chunk.js → i18n-settings-page.4ef64441.chunk.js} +5 -5
  149. package/build/id-json.86035797.chunk.js +1 -0
  150. package/build/index.html +1 -1
  151. package/build/it-json.bbdc8993.chunk.js +1 -0
  152. package/build/ja-json.1c9eeeec.chunk.js +1 -0
  153. package/build/ko-json.e1f66398.chunk.js +1 -0
  154. package/build/main.ca8b0ee3.js +9465 -0
  155. package/build/ml-json.963c889f.chunk.js +1 -0
  156. package/build/nl-json.2b8cc3a0.chunk.js +1 -0
  157. package/build/no-json.a58c28bd.chunk.js +1 -0
  158. package/build/pl-json.249626b3.chunk.js +1 -0
  159. package/build/pt-BR-json.2b72b1d6.chunk.js +1 -0
  160. package/build/ru-json.d7cfc2ff.chunk.js +1 -0
  161. package/build/runtime~main.ede9da1e.js +2 -0
  162. package/build/sa-json.44e95991.chunk.js +1 -0
  163. package/build/sk-json.7ba4b330.chunk.js +1 -0
  164. package/build/sv-json.fb1081ff.chunk.js +1 -0
  165. package/build/th-json.a67309b1.chunk.js +1 -0
  166. package/build/{upload-settings.3d613216.chunk.js → upload-settings.3f7ad973.chunk.js} +5 -5
  167. package/build/{users-advanced-settings-page.f4051d92.chunk.js → users-advanced-settings-page.6a838320.chunk.js} +5 -5
  168. package/build/users-permissions-translation-sv-json.d5d11648.chunk.js +1 -0
  169. package/build/{webhook-edit-page.9e46fc3f.chunk.js → webhook-edit-page.dc9442ce.chunk.js} +1 -1
  170. package/build/webhook-list-page.a110c462.chunk.js +134 -0
  171. package/build/zh-Hans-json.21617c24.chunk.js +1 -0
  172. package/build/zh-json.608aaf24.chunk.js +1 -0
  173. package/ee/admin/pages/SettingsPage/pages/Roles/ListPage/index.js +3 -2
  174. package/env.js +1 -0
  175. package/package.json +18 -17
  176. package/scripts/build.js +11 -0
  177. package/server/content-types/api-token.js +1 -1
  178. package/utils/create-plugins-exclude-path.js +40 -0
  179. package/webpack.alias.js +0 -13
  180. package/webpack.config.js +4 -1
  181. package/admin/src/assets/images/banner_strapi-rocket.png +0 -0
  182. package/admin/src/assets/images/big-logo-home.png +0 -0
  183. package/admin/src/assets/images/homepage-logo.png +0 -0
  184. package/admin/src/assets/images/icon_made-by-strapi.svg +0 -5
  185. package/admin/src/assets/images/logo_strapi_auth.png +0 -0
  186. package/admin/src/assets/images/logo_strapi_auth_v4.png +0 -0
  187. package/admin/src/assets/images/logo_strapi_menu.png +0 -0
  188. package/admin/src/assets/images/oops.png +0 -0
  189. package/admin/src/content-manager/components/DynamicZone/components/Component/Rectangle.js +0 -19
  190. package/admin/src/content-manager/components/DynamicZone/components/Component/index.js +0 -191
  191. package/admin/src/content-manager/components/State/index.js +0 -37
  192. package/admin/src/content-manager/icons/Bold/index.js +0 -22
  193. package/admin/src/content-manager/icons/Code/index.js +0 -13
  194. package/admin/src/content-manager/icons/Cross/index.js +0 -28
  195. package/admin/src/content-manager/icons/Italic/index.js +0 -23
  196. package/admin/src/content-manager/icons/Link/index.js +0 -21
  197. package/admin/src/content-manager/icons/Media/index.js +0 -14
  198. package/admin/src/content-manager/icons/Na/index.js +0 -39
  199. package/admin/src/content-manager/icons/Ol/index.js +0 -13
  200. package/admin/src/content-manager/icons/Quote/index.js +0 -13
  201. package/admin/src/content-manager/icons/Striked/index.js +0 -24
  202. package/admin/src/content-manager/icons/Ul/index.js +0 -15
  203. package/admin/src/content-manager/icons/Underline/index.js +0 -22
  204. package/admin/src/favicon.ico +0 -0
  205. package/build/15026a3d58aeb2828134.png +0 -0
  206. package/build/1856.d8f13391.chunk.js +0 -173
  207. package/build/1939.e3c87653.chunk.js +0 -325
  208. package/build/2077.31a2d91e.chunk.js +0 -205
  209. package/build/2912.ab68a736.chunk.js +0 -258
  210. package/build/4318.7d167b58.chunk.js +0 -30
  211. package/build/4715.44b1ef9b.chunk.js +0 -386
  212. package/build/4982.c2a311b7.chunk.js +0 -324
  213. package/build/6925.f5c8b6fc.chunk.js +0 -761
  214. package/build/7841.4b67af3f.chunk.js +0 -258
  215. package/build/7866.5fbeb7e5.chunk.js +0 -504
  216. package/build/8380.9b53a31d.chunk.js +0 -284
  217. package/build/8549.cf10b5d1.chunk.js +0 -158
  218. package/build/8738.a30a2160.chunk.js +0 -461
  219. package/build/90f49a385afb000fb1d4.svg +0 -5
  220. package/build/9420.0fe11290.chunk.js +0 -504
  221. package/build/962.8651ba3f.chunk.js +0 -184
  222. package/build/Admin-authenticatedApp.883449a5.chunk.js +0 -80
  223. package/build/Admin_marketplace.82c0570b.chunk.js +0 -11
  224. package/build/Admin_settingsPage.98e2a62b.chunk.js +0 -178
  225. package/build/a6b842e0b6d2b61135d1.svg +0 -5
  226. package/build/admin-app.a61d5c2e.chunk.js +0 -112
  227. package/build/b997a22a2e0b87ef1fa2.ico +0 -0
  228. package/build/bd81ba6c07827282255d.png +0 -0
  229. package/build/c3de6118ef47086ad05c.png +0 -0
  230. package/build/ca-json.82df6eab.chunk.js +0 -1
  231. package/build/content-manager.933dc286.chunk.js +0 -1201
  232. package/build/content-type-builder-translation-pt-BR-json.d6c7fcc1.chunk.js +0 -1
  233. package/build/de-json.0ad554eb.chunk.js +0 -1
  234. package/build/dk-json.e195ea1a.chunk.js +0 -1
  235. package/build/email-translation-en-json.3d74ff95.chunk.js +0 -1
  236. package/build/en-json.1889403c.chunk.js +0 -1
  237. package/build/es-json.09f80f6e.chunk.js +0 -1
  238. package/build/fb376b132d18bf4522ca.png +0 -0
  239. package/build/fde9b1ad0670d29a2516.png +0 -0
  240. package/build/fr-json.606d056b.chunk.js +0 -1
  241. package/build/gu-json.9881264f.chunk.js +0 -1
  242. package/build/he-json.3b825d80.chunk.js +0 -1
  243. package/build/hi-json.83dcf48f.chunk.js +0 -1
  244. package/build/hu-json.6f328bce.chunk.js +0 -1
  245. package/build/id-json.1f3c4303.chunk.js +0 -1
  246. package/build/it-json.494ac432.chunk.js +0 -1
  247. package/build/ja-json.6f262117.chunk.js +0 -1
  248. package/build/ko-json.36dc3b9a.chunk.js +0 -1
  249. package/build/main.63e7ea0a.js +0 -9338
  250. package/build/ml-json.9566bf9a.chunk.js +0 -1
  251. package/build/nl-json.94c3a289.chunk.js +0 -1
  252. package/build/no-json.40386397.chunk.js +0 -1
  253. package/build/pl-json.ccc6ef23.chunk.js +0 -1
  254. package/build/pt-BR-json.744f024d.chunk.js +0 -1
  255. package/build/ru-json.d22ea13c.chunk.js +0 -1
  256. package/build/runtime~main.3a5e1b07.js +0 -2
  257. package/build/sa-json.8fb1c04d.chunk.js +0 -1
  258. package/build/sk-json.6c7335d4.chunk.js +0 -1
  259. package/build/sv-json.2e589a7d.chunk.js +0 -1
  260. package/build/th-json.72e8de3d.chunk.js +0 -1
  261. package/build/users-permissions-translation-sv-json.83c60841.chunk.js +0 -1
  262. package/build/webhook-list-page.a712ae40.chunk.js +0 -134
  263. package/build/zh-Hans-json.a4d7dc69.chunk.js +0 -1
  264. package/build/zh-json.66aa2ae1.chunk.js +0 -1
@@ -0,0 +1,70 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import { Select, Option } from '@strapi/design-system/Select';
4
+ import { Box } from '@strapi/design-system/Box';
5
+ import { useIntl } from 'react-intl';
6
+ import PropTypes from 'prop-types';
7
+
8
+ const SelectWrapper = styled(Box)`
9
+ font-weight: ${({ theme }) => theme.fontWeights.semiBold};
10
+
11
+ span {
12
+ font-size: ${({ theme }) => theme.fontSizes[1]};
13
+ }
14
+ `;
15
+
16
+ const SortSelect = ({ sortQuery, handleSelectChange }) => {
17
+ const { formatMessage } = useIntl();
18
+
19
+ const sortTypes = {
20
+ 'name:asc': {
21
+ selected: {
22
+ id: 'admin.pages.MarketPlacePage.sort.alphabetical.selected',
23
+ defaultMessage: 'Sort by alphabetical order',
24
+ },
25
+ option: {
26
+ id: 'admin.pages.MarketPlacePage.sort.alphabetical',
27
+ defaultMessage: 'Alphabetical order',
28
+ },
29
+ },
30
+ 'submissionDate:desc': {
31
+ selected: {
32
+ id: 'admin.pages.MarketPlacePage.sort.newest.selected',
33
+ defaultMessage: 'Sort by newest',
34
+ },
35
+ option: {
36
+ id: 'admin.pages.MarketPlacePage.sort.newest',
37
+ defaultMessage: 'Newest',
38
+ },
39
+ },
40
+ };
41
+
42
+ return (
43
+ <SelectWrapper>
44
+ <Select
45
+ size="S"
46
+ id="sort-by-select"
47
+ value={sortQuery}
48
+ customizeContent={() => formatMessage(sortTypes[sortQuery].selected)}
49
+ onChange={(sortName) => {
50
+ handleSelectChange({ sort: sortName });
51
+ }}
52
+ >
53
+ {Object.entries(sortTypes).map(([sortName, messages]) => {
54
+ return (
55
+ <Option key={sortName} value={sortName}>
56
+ {formatMessage(messages.option)}
57
+ </Option>
58
+ );
59
+ })}
60
+ </Select>
61
+ </SelectWrapper>
62
+ );
63
+ };
64
+
65
+ SortSelect.propTypes = {
66
+ sortQuery: PropTypes.string.isRequired,
67
+ handleSelectChange: PropTypes.func.isRequired,
68
+ };
69
+
70
+ export default SortSelect;
@@ -10,6 +10,7 @@ import {
10
10
  LoadingIndicatorPage,
11
11
  useNotification,
12
12
  useAppInfos,
13
+ useQueryParams,
13
14
  } from '@strapi/helper-plugin';
14
15
  import { Layout, ContentLayout } from '@strapi/design-system/Layout';
15
16
  import { Main } from '@strapi/design-system/Main';
@@ -29,6 +30,8 @@ import offlineCloud from '../../assets/images/icon_offline-cloud.svg';
29
30
  import useNavigatorOnLine from '../../hooks/useNavigatorOnLine';
30
31
  import MissingPluginBanner from './components/MissingPluginBanner';
31
32
  import NpmPackagesGrid from './components/NpmPackagesGrid';
33
+ import SortSelect from './components/SortSelect';
34
+ import NpmPackagesFilters from './components/NpmPackagesFilters';
32
35
 
33
36
  const matchSearch = (npmPackages, search) => {
34
37
  return matchSorter(npmPackages, search, {
@@ -39,6 +42,7 @@ const matchSearch = (npmPackages, search) => {
39
42
  },
40
43
  { threshold: matchSorter.rankings.WORD_STARTS_WITH, key: 'attributes.description' },
41
44
  ],
45
+ baseSort: (a, b) => (a.index < b.index ? -1 : 1),
42
46
  });
43
47
  };
44
48
 
@@ -49,10 +53,18 @@ const MarketPlacePage = () => {
49
53
  const trackUsageRef = useRef(trackUsage);
50
54
  const toggleNotification = useNotification();
51
55
  const [searchQuery, setSearchQuery] = useState('');
52
- const [npmPackageType, setNpmPackageType] = useState('plugin');
53
- const { autoReload: isInDevelopmentMode, dependencies, useYarn } = useAppInfos();
56
+ const [{ query }, setQuery] = useQueryParams();
57
+
58
+ const { autoReload: isInDevelopmentMode, dependencies, useYarn, strapiVersion } = useAppInfos();
54
59
  const isOnline = useNavigatorOnLine();
55
60
 
61
+ const npmPackageType = query?.npmPackageType || 'plugin';
62
+
63
+ const [tabQuery, setTabQuery] = useState({
64
+ plugin: npmPackageType === 'plugin' ? { ...query } : {},
65
+ provider: npmPackageType === 'provider' ? { ...query } : {},
66
+ });
67
+
56
68
  useFocusWhenNavigate();
57
69
 
58
70
  const marketplaceTitle = formatMessage({
@@ -72,11 +84,11 @@ const MarketPlacePage = () => {
72
84
  );
73
85
  };
74
86
 
75
- const { status: marketplacePluginsStatus, data: marketplacePluginsResponse } =
76
- useFetchMarketplacePlugins(notifyMarketplaceLoad);
77
-
78
87
  const { status: marketplaceProvidersStatus, data: marketplaceProvidersResponse } =
79
- useFetchMarketplaceProviders(notifyMarketplaceLoad);
88
+ useFetchMarketplaceProviders(notifyMarketplaceLoad, tabQuery.provider);
89
+
90
+ const { status: marketplacePluginsStatus, data: marketplacePluginsResponse } =
91
+ useFetchMarketplacePlugins(notifyMarketplaceLoad, tabQuery.plugin);
80
92
 
81
93
  const isLoading = [marketplacePluginsStatus, marketplaceProvidersStatus].includes('loading');
82
94
 
@@ -169,13 +181,44 @@ const MarketPlacePage = () => {
169
181
  );
170
182
 
171
183
  const handleTabChange = (selected) => {
172
- const packageType = selected === 0 ? 'plugin' : 'provider';
173
- setNpmPackageType(packageType);
184
+ const selectedTab = selected === 0 ? 'plugin' : 'provider';
185
+ const hasTabQuery = tabQuery[selectedTab] && Object.keys(tabQuery[selectedTab]).length;
186
+
187
+ if (hasTabQuery) {
188
+ setQuery({ ...tabQuery[selectedTab], npmPackageType: selectedTab });
189
+ } else {
190
+ setQuery({
191
+ npmPackageType: selectedTab,
192
+ // Clear filters
193
+ collections: [],
194
+ categories: [],
195
+ sort: 'name:asc',
196
+ });
197
+ }
198
+ };
199
+
200
+ const handleSelectChange = (update) => {
201
+ setQuery(update);
202
+ setTabQuery((prev) => ({
203
+ ...prev,
204
+ [npmPackageType]: { ...prev[npmPackageType], ...update },
205
+ }));
206
+ };
207
+
208
+ const handleSelectClear = (filterType) => {
209
+ setQuery({ [filterType]: [] }, 'remove');
210
+ setTabQuery((prev) => ({ ...prev, [npmPackageType]: {} }));
174
211
  };
175
212
 
176
213
  // Check if plugins and providers are installed already
177
214
  const installedPackageNames = Object.keys(dependencies);
178
215
 
216
+ const possibleCollections =
217
+ npmPackageType === 'plugin'
218
+ ? marketplacePluginsResponse.meta.collections
219
+ : marketplaceProvidersResponse.meta.collections;
220
+ const possibleCategories = marketplacePluginsResponse.meta.categories;
221
+
179
222
  return (
180
223
  <Layout>
181
224
  <Main>
@@ -215,6 +258,7 @@ const MarketPlacePage = () => {
215
258
  })}
216
259
  id="tabs"
217
260
  variant="simple"
261
+ initialSelectedTabIndex={['plugin', 'provider'].indexOf(npmPackageType)}
218
262
  onTabChange={handleTabChange}
219
263
  >
220
264
  <Box paddingBottom={4}>
@@ -235,6 +279,21 @@ const MarketPlacePage = () => {
235
279
  </Tab>
236
280
  </Tabs>
237
281
  </Box>
282
+ <Flex paddingBottom={4} gap={2}>
283
+ <SortSelect
284
+ sortQuery={query?.sort || 'name:asc'}
285
+ handleSelectChange={handleSelectChange}
286
+ />
287
+ <NpmPackagesFilters
288
+ npmPackageType={npmPackageType}
289
+ possibleCollections={possibleCollections}
290
+ possibleCategories={possibleCategories}
291
+ query={query || {}}
292
+ handleSelectChange={handleSelectChange}
293
+ handleSelectClear={handleSelectClear}
294
+ />
295
+ </Flex>
296
+
238
297
  <TabPanels>
239
298
  {/* Plugins panel */}
240
299
  <TabPanel>
@@ -247,6 +306,7 @@ const MarketPlacePage = () => {
247
306
  useYarn={useYarn}
248
307
  isInDevelopmentMode={isInDevelopmentMode}
249
308
  npmPackageType="plugin"
309
+ strapiAppVersion={strapiVersion}
250
310
  />
251
311
  )}
252
312
  </TabPanel>
@@ -111,7 +111,7 @@ const FormApiTokenContainer = ({
111
111
  id: 'Settings.apiTokens.form.duration',
112
112
  defaultMessage: 'Token duration',
113
113
  })}
114
- value={values.lifespan}
114
+ value={values.lifespan !== null ? values.lifespan : '0'}
115
115
  error={
116
116
  errors.lifespan
117
117
  ? formatMessage(
@@ -146,7 +146,7 @@ const FormApiTokenContainer = ({
146
146
  defaultMessage: '90 days',
147
147
  })}
148
148
  </Option>
149
- <Option value={null}>
149
+ <Option value="0">
150
150
  {formatMessage({
151
151
  id: 'Settings.apiTokens.duration.unlimited',
152
152
  defaultMessage: 'Unlimited',
@@ -234,7 +234,7 @@ FormApiTokenContainer.propTypes = {
234
234
  }).isRequired,
235
235
  isCreating: PropTypes.bool.isRequired,
236
236
  apiToken: PropTypes.shape({
237
- id: PropTypes.string,
237
+ id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
238
238
  type: PropTypes.string,
239
239
  lifespan: PropTypes.number,
240
240
  name: PropTypes.string,
@@ -242,13 +242,14 @@ FormApiTokenContainer.propTypes = {
242
242
  permissions: PropTypes.array,
243
243
  description: PropTypes.string,
244
244
  createdAt: PropTypes.string,
245
- }).isRequired,
245
+ }),
246
246
  onDispatch: PropTypes.func.isRequired,
247
247
  setHasChangedPermissions: PropTypes.func.isRequired,
248
248
  };
249
249
 
250
250
  FormApiTokenContainer.defaultProps = {
251
251
  errors: {},
252
+ apiToken: {},
252
253
  };
253
254
 
254
255
  export default FormApiTokenContainer;
@@ -19,7 +19,7 @@ const FormBody = ({
19
19
  return (
20
20
  <ContentLayout>
21
21
  <Stack spacing={6}>
22
- {Boolean(apiToken?.name) && <HeaderContentBox apiToken={apiToken.accessKey} />}
22
+ {Boolean(apiToken?.name) && <HeaderContentBox apiToken={apiToken?.accessKey} />}
23
23
  <FormApiTokenContainer
24
24
  errors={errors}
25
25
  onChange={onChange}
@@ -48,7 +48,7 @@ FormBody.propTypes = {
48
48
  type: PropTypes.string,
49
49
  }),
50
50
  apiToken: PropTypes.shape({
51
- id: PropTypes.string,
51
+ id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
52
52
  type: PropTypes.string,
53
53
  lifespan: PropTypes.number,
54
54
  name: PropTypes.string,
@@ -56,7 +56,7 @@ FormBody.propTypes = {
56
56
  permissions: PropTypes.array,
57
57
  description: PropTypes.string,
58
58
  createdAt: PropTypes.string,
59
- }).isRequired,
59
+ }),
60
60
  onChange: PropTypes.func.isRequired,
61
61
  canEditInputs: PropTypes.bool.isRequired,
62
62
  isCreating: PropTypes.bool.isRequired,
@@ -72,6 +72,7 @@ FormBody.propTypes = {
72
72
 
73
73
  FormBody.defaultProps = {
74
74
  errors: {},
75
+ apiToken: {},
75
76
  };
76
77
 
77
78
  export default FormBody;
@@ -67,7 +67,7 @@ const FormHead = ({ apiToken, setApiToken, canEditInputs, canRegenerate, isSubmi
67
67
 
68
68
  FormHead.propTypes = {
69
69
  apiToken: PropTypes.shape({
70
- id: PropTypes.string,
70
+ id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
71
71
  type: PropTypes.string,
72
72
  lifespan: PropTypes.number,
73
73
  name: PropTypes.string,
@@ -75,11 +75,15 @@ FormHead.propTypes = {
75
75
  permissions: PropTypes.array,
76
76
  description: PropTypes.string,
77
77
  createdAt: PropTypes.string,
78
- }).isRequired,
78
+ }),
79
79
  canEditInputs: PropTypes.bool.isRequired,
80
80
  canRegenerate: PropTypes.bool.isRequired,
81
81
  setApiToken: PropTypes.func.isRequired,
82
82
  isSubmitting: PropTypes.bool.isRequired,
83
83
  };
84
84
 
85
+ FormHead.defaultProps = {
86
+ apiToken: undefined,
87
+ };
88
+
85
89
  export default FormHead;
@@ -62,7 +62,7 @@ Regenerate.defaultProps = { onRegenerate() {} };
62
62
 
63
63
  Regenerate.propTypes = {
64
64
  onRegenerate: PropTypes.func,
65
- idToRegenerate: PropTypes.string.isRequired,
65
+ idToRegenerate: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
66
66
  };
67
67
 
68
68
  export default Regenerate;
@@ -152,6 +152,10 @@ const ApiTokenCreateView = () => {
152
152
  const handleSubmit = async (body, actions) => {
153
153
  trackUsageRef.current(isCreating ? 'willCreateToken' : 'willEditToken');
154
154
  lockApp();
155
+ const lifespanVal =
156
+ body.lifespan && parseInt(body.lifespan, 10) && body.lifespan !== '0'
157
+ ? parseInt(body.lifespan, 10)
158
+ : null;
155
159
 
156
160
  try {
157
161
  const {
@@ -159,10 +163,7 @@ const ApiTokenCreateView = () => {
159
163
  } = isCreating
160
164
  ? await axiosInstance.post(`/admin/api-tokens`, {
161
165
  ...body,
162
- lifespan:
163
- body.lifespan && parseInt(body.lifespan, 10)
164
- ? parseInt(body.lifespan, 10)
165
- : body.lifespan,
166
+ lifespan: lifespanVal,
166
167
  permissions: body.type === 'custom' ? state.selectedActions : null,
167
168
  })
168
169
  : await axiosInstance.put(`/admin/api-tokens/${id}`, {
@@ -8,7 +8,7 @@ const schema = yup.object().shape({
8
8
  .oneOf(['read-only', 'full-access', 'custom'])
9
9
  .required(translatedErrors.required),
10
10
  description: yup.string().nullable(),
11
- lifespan: yup.number().integer().min(1).nullable().defined(translatedErrors.required),
11
+ lifespan: yup.number().integer().min(0).nullable().defined(translatedErrors.required),
12
12
  });
13
13
 
14
14
  export default schema;
@@ -5,14 +5,9 @@ import { Box } from '@strapi/design-system/Box';
5
5
  import { Flex } from '@strapi/design-system/Flex';
6
6
  import { Typography } from '@strapi/design-system/Typography';
7
7
  import { MultiSelectNested } from '@strapi/design-system/Select';
8
- import upperFirst from 'lodash/upperFirst';
9
8
  import { useIntl } from 'react-intl';
10
- import styled from 'styled-components';
11
- import { rowHeight } from '../../Permissions/utils/constants';
12
9
 
13
- const FlexWrapper = styled(Flex)`
14
- height: ${rowHeight};
15
- `;
10
+ import { getNestedOptions, getSelectedValues, getNewStateFromChangedValues } from './utils/options';
16
11
 
17
12
  const ActionRow = ({
18
13
  arrayOfOptionsGroupedByCategory,
@@ -24,40 +19,13 @@ const ActionRow = ({
24
19
  value,
25
20
  }) => {
26
21
  const { formatMessage } = useIntl();
27
- const options = arrayOfOptionsGroupedByCategory.reduce((arr, curr) => {
28
- const [label, children] = curr;
29
- const obj = {
30
- label: upperFirst(label),
31
- children: children.map((child) => ({
32
- label: child.displayName,
33
- value: child.id,
34
- })),
35
- };
36
22
 
37
- return [...arr, obj];
38
- }, []);
39
-
40
- // Output: ['value1', 'value2']
41
- const values = Object.values(value)
42
- .map((x) =>
43
- Object.entries(x)
44
- .filter(([, value]) => value)
45
- .map(([key]) => key)
46
- )
47
- .flat();
48
-
49
- // ! Only expects arrayOfOpt to be [['default', obj]] - might break in future changes
50
23
  const handleChange = (val) => {
51
- const [[, values]] = arrayOfOptionsGroupedByCategory;
52
- const formattedValues = values.reduce(
53
- (acc, curr) => ({ [curr.id]: val.includes(curr.id), ...acc }),
54
- {}
55
- );
56
- onChange(name, formattedValues);
24
+ onChange(name, getNewStateFromChangedValues(arrayOfOptionsGroupedByCategory, val));
57
25
  };
58
26
 
59
27
  return (
60
- <FlexWrapper as="li" background={isGrey ? 'neutral100' : 'neutral0'}>
28
+ <Flex as="li" background={isGrey ? 'neutral100' : 'neutral0'} paddingBottom={3} paddingTop={3}>
61
29
  <Flex paddingLeft={6} style={{ width: 180 }}>
62
30
  <Typography variant="sigma" textColor="neutral600">
63
31
  {formatMessage({
@@ -85,12 +53,12 @@ const ActionRow = ({
85
53
  id={name}
86
54
  customizeContent={(values) => `${values.length} currently selected`}
87
55
  onChange={handleChange}
88
- value={values}
89
- options={options}
56
+ value={getSelectedValues(value)}
57
+ options={getNestedOptions(arrayOfOptionsGroupedByCategory)}
90
58
  disabled={isFormDisabled || IS_DISABLED}
91
59
  />
92
60
  </Box>
93
- </FlexWrapper>
61
+ </Flex>
94
62
  );
95
63
  };
96
64
 
@@ -103,4 +71,5 @@ ActionRow.propTypes = {
103
71
  value: PropTypes.object.isRequired,
104
72
  onChange: PropTypes.func.isRequired,
105
73
  };
74
+
106
75
  export default ActionRow;
@@ -0,0 +1,31 @@
1
+ import upperFirst from 'lodash/upperFirst';
2
+
3
+ const getSelectedValues = (rawValue) =>
4
+ Object.values(rawValue)
5
+ .map((x) =>
6
+ Object.entries(x)
7
+ .filter(([, value]) => value)
8
+ .map(([key]) => key)
9
+ )
10
+ .flat();
11
+
12
+ const getNestedOptions = (options) =>
13
+ options.reduce((acc, [label, children]) => {
14
+ acc.push({
15
+ label: upperFirst(label),
16
+ children: children.map((child) => ({
17
+ label: child.displayName,
18
+ value: child.id,
19
+ })),
20
+ });
21
+
22
+ return acc;
23
+ }, []);
24
+
25
+ const getNewStateFromChangedValues = (options, changedValues) =>
26
+ options
27
+ .map(([, values]) => values)
28
+ .flat()
29
+ .reduce((acc, curr) => ({ [curr.id]: changedValues.includes(curr.id), ...acc }), {});
30
+
31
+ export { getNestedOptions, getSelectedValues, getNewStateFromChangedValues };
@@ -1,10 +1,12 @@
1
1
  import React, { useMemo, useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Box } from '@strapi/design-system/Box';
4
3
  import { Button } from '@strapi/design-system/Button';
5
- import { Divider } from '@strapi/design-system/Divider';
6
- import { Stack } from '@strapi/design-system/Stack';
7
- import { ModalFooter, ModalHeader, ModalLayout } from '@strapi/design-system/ModalLayout';
4
+ import {
5
+ ModalFooter,
6
+ ModalHeader,
7
+ ModalLayout,
8
+ ModalBody,
9
+ } from '@strapi/design-system/ModalLayout';
8
10
  import { Breadcrumbs, Crumb } from '@strapi/design-system/Breadcrumbs';
9
11
  import { Typography } from '@strapi/design-system/Typography';
10
12
  import produce from 'immer';
@@ -88,48 +90,35 @@ const ConditionsModal = ({ actions, headerBreadCrumbs, isFormDisabled, onClosed,
88
90
  ))}
89
91
  </Breadcrumbs>
90
92
  </ModalHeader>
91
- <Box padding={8}>
92
- <Stack spacing={6}>
93
- <Typography variant="beta" as="h2">
93
+ <ModalBody>
94
+ {actionsToDisplay.length === 0 && (
95
+ <Typography>
94
96
  {formatMessage({
95
- id: 'Settings.permissions.conditions.define-conditions',
96
- defaultMessage: 'Define conditions',
97
+ id: 'Settings.permissions.conditions.no-actions',
98
+ defaultMessage:
99
+ 'You first need to select actions (create, read, update, ...) before defining conditions on them.',
97
100
  })}
98
101
  </Typography>
99
- <Box>
100
- <Divider />
101
- </Box>
102
- <Box>
103
- {actionsToDisplay.length === 0 && (
104
- <Typography>
105
- {formatMessage({
106
- id: 'Settings.permissions.conditions.no-actions',
107
- defaultMessage:
108
- 'You first need to select actions (create, read, update, ...) before defining conditions on them.',
109
- })}
110
- </Typography>
111
- )}
112
- <ul>
113
- {actionsToDisplay.map(({ actionId, label, pathToConditionsObject }, index) => {
114
- const name = pathToConditionsObject.join('..');
115
-
116
- return (
117
- <ActionRow
118
- key={actionId}
119
- arrayOfOptionsGroupedByCategory={arrayOfOptionsGroupedByCategory}
120
- label={label}
121
- isFormDisabled={isFormDisabled}
122
- isGrey={index % 2 === 0}
123
- name={name}
124
- onChange={handleChange}
125
- value={get(state, name, {})}
126
- />
127
- );
128
- })}
129
- </ul>
130
- </Box>
131
- </Stack>
132
- </Box>
102
+ )}
103
+ <ul>
104
+ {actionsToDisplay.map(({ actionId, label, pathToConditionsObject }, index) => {
105
+ const name = pathToConditionsObject.join('..');
106
+
107
+ return (
108
+ <ActionRow
109
+ key={actionId}
110
+ arrayOfOptionsGroupedByCategory={arrayOfOptionsGroupedByCategory}
111
+ label={label}
112
+ isFormDisabled={isFormDisabled}
113
+ isGrey={index % 2 === 0}
114
+ name={name}
115
+ onChange={handleChange}
116
+ value={get(state, name, {})}
117
+ />
118
+ );
119
+ })}
120
+ </ul>
121
+ </ModalBody>
133
122
  <ModalFooter
134
123
  startActions={
135
124
  <Button variant="tertiary" onClick={onToggle}>
@@ -232,7 +232,7 @@ const Collapse = ({
232
232
  </Flex>
233
233
  {isModalOpen && (
234
234
  <ConditionsModal
235
- headerBreadCrumbs={[label, 'app.components.LeftMenuLinkContainer.settings']}
235
+ headerBreadCrumbs={[label, 'Settings.permissions.conditions.conditions']}
236
236
  actions={checkboxesActions}
237
237
  isFormDisabled={isFormDisabled}
238
238
  onClosed={handleModalClose}
@@ -8,7 +8,7 @@ import { IconButton } from '@strapi/design-system/IconButton';
8
8
  import { stopPropagation, onRowClick, pxToRem } from '@strapi/helper-plugin';
9
9
  import { useIntl } from 'react-intl';
10
10
 
11
- const RoleRow = ({ id, name, description, usersCount, icons }) => {
11
+ const RoleRow = ({ id, name, description, usersCount, icons, rowIndex }) => {
12
12
  const { formatMessage } = useIntl();
13
13
 
14
14
  const usersCountText = formatMessage(
@@ -21,6 +21,7 @@ const RoleRow = ({ id, name, description, usersCount, icons }) => {
21
21
 
22
22
  return (
23
23
  <Tr
24
+ aria-rowindex={rowIndex}
24
25
  key={id}
25
26
  {...onRowClick({
26
27
  fn: icons[1].onClick,
@@ -60,6 +61,7 @@ RoleRow.propTypes = {
60
61
  description: PropTypes.string.isRequired,
61
62
  usersCount: PropTypes.number.isRequired,
62
63
  icons: PropTypes.array.isRequired,
64
+ rowIndex: PropTypes.number.isRequired,
63
65
  };
64
66
 
65
67
  export default RoleRow;
@@ -168,7 +168,7 @@ const RoleListPage = () => {
168
168
  </Tr>
169
169
  </Thead>
170
170
  <Tbody>
171
- {sortedRoles?.map((role) => (
171
+ {sortedRoles?.map((role, rowIndex) => (
172
172
  <RoleRow
173
173
  key={role.id}
174
174
  id={role.id}
@@ -176,6 +176,7 @@ const RoleListPage = () => {
176
176
  description={role.description}
177
177
  usersCount={role.usersCount}
178
178
  icons={getIcons(role)}
179
+ rowIndex={rowIndex + 2}
179
180
  />
180
181
  ))}
181
182
  </Tbody>
@@ -114,7 +114,7 @@ const EventInput = ({ isDraftAndPublish }) => {
114
114
  if (header === 'app.utils.publish' || header === 'app.utils.unpublish') {
115
115
  return (
116
116
  <td
117
- key={header}
117
+ key={header.id}
118
118
  title={formatMessage({
119
119
  id: 'Settings.webhooks.event.publish-tooltip',
120
120
  defaultMessage:
@@ -129,7 +129,7 @@ const EventInput = ({ isDraftAndPublish }) => {
129
129
  }
130
130
 
131
131
  return (
132
- <td key={header}>
132
+ <td key={header.id}>
133
133
  <Typography variant="sigma" textColor="neutral600">
134
134
  {formatMessage(header)}
135
135
  </Typography>
@@ -107,7 +107,7 @@
107
107
  "Settings.permissions.conditions.anytime": "En qualsevol moment",
108
108
  "Settings.permissions.conditions.apply": "Aplicar",
109
109
  "Settings.permissions.conditions.can": "Poder",
110
- "Settings.permissions.conditions.define-conditions": "Definir condicions",
110
+ "Settings.permissions.conditions.conditions": "Definir condicions",
111
111
  "Settings.permissions.conditions.links": "Enllaços",
112
112
  "Settings.permissions.conditions.no-actions": "No hi ha acció",
113
113
  "Settings.permissions.conditions.none-selected": "En qualsevol moment",
@@ -107,7 +107,7 @@
107
107
  "Settings.permissions.conditions.anytime": "Jederzeit",
108
108
  "Settings.permissions.conditions.apply": "Anwenden",
109
109
  "Settings.permissions.conditions.can": "Kann",
110
- "Settings.permissions.conditions.define-conditions": "Bedingungen definieren",
110
+ "Settings.permissions.conditions.conditions": "Bedingungen definieren",
111
111
  "Settings.permissions.conditions.links": "Links",
112
112
  "Settings.permissions.conditions.no-actions": "Keine Aktionen",
113
113
  "Settings.permissions.conditions.none-selected": "Jederzeit",
@@ -105,7 +105,7 @@
105
105
  "Settings.permissions.conditions.anytime": "Altid",
106
106
  "Settings.permissions.conditions.apply": "Godkend",
107
107
  "Settings.permissions.conditions.can": "Kan",
108
- "Settings.permissions.conditions.define-conditions": "Definér betingelser",
108
+ "Settings.permissions.conditions.conditions": "Definér betingelser",
109
109
  "Settings.permissions.conditions.links": "Links",
110
110
  "Settings.permissions.conditions.no-actions": "Der er ingen handling",
111
111
  "Settings.permissions.conditions.none-selected": "Når som helst",