From edd7c2288786d20bebf62e6204d66ad8858787ea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 11:47:32 +0000 Subject: [PATCH 1/9] fix(deps): update dependency uuid to v9.0.1 (#4793) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [uuid](https://togithub.com/uuidjs/uuid) | [`9.0.0` -> `9.0.1`](https://renovatebot.com/diffs/npm/uuid/9.0.0/9.0.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/uuid/9.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/uuid/9.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/uuid/9.0.0/9.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/uuid/9.0.0/9.0.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
uuidjs/uuid (uuid) ### [`v9.0.1`](https://togithub.com/uuidjs/uuid/blob/HEAD/CHANGELOG.md#901-2023-09-12) [Compare Source](https://togithub.com/uuidjs/uuid/compare/v9.0.0...v9.0.1) ##### build - Fix CI to work with Node.js 20.x
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/Unleash/unleash). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 16813f23d7..82d5e53d57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7962,9 +7962,9 @@ uuid@^8.3.2: integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== uuid@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" - integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== v8-compile-cache-lib@^3.0.1: version "3.0.1" From eeeedffa8cc84a877f86e68dabaa2e440615bd63 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:32:40 +0000 Subject: [PATCH 2/9] chore(deps): update dependency eslint to v8.49.0 (#4796) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [eslint](https://eslint.org) ([source](https://togithub.com/eslint/eslint)) | [`8.48.0` -> `8.49.0`](https://renovatebot.com/diffs/npm/eslint/8.48.0/8.49.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/eslint/8.49.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/eslint/8.49.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/eslint/8.48.0/8.49.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/eslint/8.48.0/8.49.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
eslint/eslint (eslint) ### [`v8.49.0`](https://togithub.com/eslint/eslint/releases/tag/v8.49.0) [Compare Source](https://togithub.com/eslint/eslint/compare/v8.48.0...v8.49.0) #### Features - [`da09f4e`](https://togithub.com/eslint/eslint/commit/da09f4e641141f585ef611c6e9d63d4331054706) feat: Implement onUnreachableCodePathStart/End ([#​17511](https://togithub.com/eslint/eslint/issues/17511)) (Nicholas C. Zakas) - [`32b2327`](https://togithub.com/eslint/eslint/commit/32b2327aafdd3b911fabab69ed75c9ff97658c60) feat: Emit deprecation warnings in RuleTester ([#​17527](https://togithub.com/eslint/eslint/issues/17527)) (Nicholas C. Zakas) - [`acb7df3`](https://togithub.com/eslint/eslint/commit/acb7df35b9a7485f26bc6b3e1f9083d1c585dce9) feat: add new `enforce` option to `lines-between-class-members` ([#​17462](https://togithub.com/eslint/eslint/issues/17462)) (Nitin Kumar) #### Documentation - [`ecfb54f`](https://togithub.com/eslint/eslint/commit/ecfb54ff4cdd18f28b4f9b78f0a78fb4cf80f1b8) docs: Update README (GitHub Actions Bot) - [`de86b3b`](https://togithub.com/eslint/eslint/commit/de86b3b2e58edd5826200c23255d8325abe375e1) docs: update `no-promise-executor-return` examples ([#​17529](https://togithub.com/eslint/eslint/issues/17529)) (Nitin Kumar) - [`032c4b1`](https://togithub.com/eslint/eslint/commit/032c4b1476a7b8cfd917a66772d2221950ea87eb) docs: add typescript template ([#​17500](https://togithub.com/eslint/eslint/issues/17500)) (James) - [`cd7da5c`](https://togithub.com/eslint/eslint/commit/cd7da5cc3154f86f7ca45fb58929d27a7af359ed) docs: Update README (GitHub Actions Bot) #### Chores - [`b7621c3`](https://togithub.com/eslint/eslint/commit/b7621c3b16cf7d5539f05336a827e1b32d95e6ac) chore: remove browser test from `npm test` ([#​17550](https://togithub.com/eslint/eslint/issues/17550)) (Milos Djermanovic) - [`cac45d0`](https://togithub.com/eslint/eslint/commit/cac45d04b890b0700dd8908927300608adad05fe) chore: upgrade [@​eslint/js](https://togithub.com/eslint/js)[@​8](https://togithub.com/8).49.0 ([#​17549](https://togithub.com/eslint/eslint/issues/17549)) (Milos Djermanovic) - [`cd39508`](https://togithub.com/eslint/eslint/commit/cd395082bffcb4b68efa09226d7c682cef56179e) chore: package.json update for [@​eslint/js](https://togithub.com/eslint/js) release (ESLint Jenkins) - [`203a971`](https://togithub.com/eslint/eslint/commit/203a971c0abc3a95ae02ff74104a01e569707060) ci: bump actions/checkout from 3 to 4 ([#​17530](https://togithub.com/eslint/eslint/issues/17530)) (dependabot\[bot]) - [`a40fa50`](https://togithub.com/eslint/eslint/commit/a40fa509922b36bb986eb1be9394591f84f62d9e) chore: use eslint-plugin-jsdoc's flat config ([#​17516](https://togithub.com/eslint/eslint/issues/17516)) (Milos Djermanovic) - [`926a286`](https://togithub.com/eslint/eslint/commit/926a28684282aeec37680bbc52a66973b8055f54) test: replace Karma with Webdriver.IO ([#​17126](https://togithub.com/eslint/eslint/issues/17126)) (Christian Bromann) - [`f591d2c`](https://togithub.com/eslint/eslint/commit/f591d2c88bf15af72e3a207b34fa872b4b90464b) chore: Upgrade config-array ([#​17512](https://togithub.com/eslint/eslint/issues/17512)) (Nicholas C. Zakas)
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/Unleash/unleash). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package.json | 2 +- frontend/yarn.lock | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 86f894c894..ca899e6b9d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -75,7 +75,7 @@ "debounce": "1.2.1", "deep-diff": "1.0.2", "dequal": "2.0.3", - "eslint": "8.48.0", + "eslint": "8.49.0", "eslint-config-react-app": "7.0.1", "fast-json-patch": "3.1.1", "http-proxy-middleware": "2.0.6", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index f9e8246db1..d4cdd1b39b 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1845,10 +1845,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.48.0": - version "8.48.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.48.0.tgz#642633964e217905436033a2bd08bf322849b7fb" - integrity sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw== +"@eslint/js@8.49.0": + version "8.49.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333" + integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== "@exodus/schemasafe@^1.0.0-rc.2": version "1.0.1" @@ -1860,10 +1860,10 @@ resolved "https://registry.yarnpkg.com/@gilbarbara/deep-equal/-/deep-equal-0.1.2.tgz#1a106721368dba5e7e9fb7e9a3a6f9efbd8df36d" integrity sha512-jk+qzItoEb0D0xSSmrKDDzf9sheQj/BAPxlgNxgmOaA3mxpUa6ndJLYGZKsJnIVEQSD8zcTbyILz7I0HcnBCRA== -"@humanwhocodes/config-array@^0.11.10": - version "0.11.10" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" - integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== +"@humanwhocodes/config-array@^0.11.11": + version "0.11.11" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" + integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" @@ -5357,16 +5357,16 @@ eslint-visitor-keys@^3.4.3: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@8.48.0: - version "8.48.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.48.0.tgz#bf9998ba520063907ba7bfe4c480dc8be03c2155" - integrity sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg== +eslint@8.49.0: + version "8.49.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42" + integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.48.0" - "@humanwhocodes/config-array" "^0.11.10" + "@eslint/js" "8.49.0" + "@humanwhocodes/config-array" "^0.11.11" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" ajv "^6.12.4" From 18f7d0f9e1bb2495c3959c6ce0b23877266e5dde Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:27:40 +0200 Subject: [PATCH 3/9] Remove integrationsRework flag (#4770) https://linear.app/unleash/issue/1-1359/remove-integrationsrework-flag --- .../IntegrationForm/IntegrationForm.tsx | 25 +- .../AddonNameCell/AddonNameCell.tsx | 38 --- .../IntegrationList/AddonsList.tsx | 21 -- .../AvailableAddons/AvailableAddons.tsx | 172 ------------- .../ConfigureAddonsButton.tsx | 29 --- .../ConfiguredAddons/ConfiguredAddons.tsx | 241 ------------------ .../ConfiguredAddonsActionsCell.tsx | 76 ------ .../__snapshots__/routes.test.tsx.snap | 7 +- frontend/src/component/menu/routes.ts | 16 +- frontend/src/interfaces/uiConfig.ts | 1 - .../__snapshots__/create-config.test.ts.snap | 2 - src/lib/types/experimental.ts | 5 - src/server-dev.ts | 1 - 13 files changed, 14 insertions(+), 620 deletions(-) delete mode 100644 frontend/src/component/integrations/IntegrationList/AddonNameCell/AddonNameCell.tsx delete mode 100644 frontend/src/component/integrations/IntegrationList/AddonsList.tsx delete mode 100644 frontend/src/component/integrations/IntegrationList/AvailableAddons/AvailableAddons.tsx delete mode 100644 frontend/src/component/integrations/IntegrationList/AvailableAddons/ConfigureAddonButton/ConfigureAddonsButton.tsx delete mode 100644 frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddons.tsx delete mode 100644 frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx diff --git a/frontend/src/component/integrations/IntegrationForm/IntegrationForm.tsx b/frontend/src/component/integrations/IntegrationForm/IntegrationForm.tsx index ff44a87a20..88e72044c4 100644 --- a/frontend/src/component/integrations/IntegrationForm/IntegrationForm.tsx +++ b/frontend/src/component/integrations/IntegrationForm/IntegrationForm.tsx @@ -43,7 +43,6 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit import { IntegrationDelete } from './IntegrationDelete/IntegrationDelete'; import { IntegrationStateSwitch } from './IntegrationStateSwitch/IntegrationStateSwitch'; import { capitalizeFirst } from 'utils/capitalizeFirst'; -import { useUiFlag } from 'hooks/useUiFlag'; import { IntegrationHowToSection } from '../IntegrationHowToSection/IntegrationHowToSection'; type IntegrationFormProps = { @@ -77,7 +76,6 @@ export const IntegrationForm: VFC = ({ label: event, })); const { uiConfig } = useUiConfig(); - const integrationsRework = useUiFlag('integrationsRework'); const [formValues, setFormValues] = useState(initialValues); const [errors, setErrors] = useState<{ containsErrors: boolean; @@ -221,14 +219,14 @@ export const IntegrationForm: VFC = ({ try { if (editMode) { await updateAddon(formValues as AddonSchema); - navigate(integrationsRework ? '/integrations' : '/addons'); + navigate('/integrations'); setToastData({ type: 'success', title: 'Integration updated successfully', }); } else { await createAddon(formValues as Omit); - navigate(integrationsRework ? '/integrations' : '/addons'); + navigate('/integrations'); setToastData({ type: 'success', confetti: true, @@ -393,19 +391,12 @@ export const IntegrationForm: VFC = ({ /> - ( - <> - -
- -
- - )} - /> + +
+ +
diff --git a/frontend/src/component/integrations/IntegrationList/AddonNameCell/AddonNameCell.tsx b/frontend/src/component/integrations/IntegrationList/AddonNameCell/AddonNameCell.tsx deleted file mode 100644 index 6862a096ee..0000000000 --- a/frontend/src/component/integrations/IntegrationList/AddonNameCell/AddonNameCell.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { styled } from '@mui/material'; -import { Badge } from 'component/common/Badge/Badge'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip'; -import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell'; -import { AddonTypeSchema } from 'openapi'; - -const StyledBadge = styled(Badge)(({ theme }) => ({ - cursor: 'pointer', - marginLeft: theme.spacing(1), -})); - -interface IAddonNameCellProps { - provider: Pick< - AddonTypeSchema, - 'displayName' | 'description' | 'deprecated' - >; -} - -/** - * @deprecated Remove when integrationsRework flag is removed - */ -export const AddonNameCell = ({ provider }: IAddonNameCellProps) => ( - - Deprecated - - } - /> - } - /> -); diff --git a/frontend/src/component/integrations/IntegrationList/AddonsList.tsx b/frontend/src/component/integrations/IntegrationList/AddonsList.tsx deleted file mode 100644 index 4076b9ddc2..0000000000 --- a/frontend/src/component/integrations/IntegrationList/AddonsList.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { ConfiguredAddons } from './ConfiguredAddons/ConfiguredAddons'; -import { AvailableAddons } from './AvailableAddons/AvailableAddons'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import useAddons from 'hooks/api/getters/useAddons/useAddons'; - -/** - * @deprecated remove with `integrationsRework` flag - */ -export const AddonsList = () => { - const { providers, addons, loading } = useAddons(); - - return ( - <> - 0} - show={} - /> - - - ); -}; diff --git a/frontend/src/component/integrations/IntegrationList/AvailableAddons/AvailableAddons.tsx b/frontend/src/component/integrations/IntegrationList/AvailableAddons/AvailableAddons.tsx deleted file mode 100644 index ab4ef87734..0000000000 --- a/frontend/src/component/integrations/IntegrationList/AvailableAddons/AvailableAddons.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import { useMemo } from 'react'; -import { PageContent } from 'component/common/PageContent/PageContent'; - -import { - Table, - SortableTableHeader, - TableBody, - TableCell, - TableRow, - TablePlaceholder, -} from 'component/common/Table'; - -import { useTable, useSortBy } from 'react-table'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { PageHeader } from 'component/common/PageHeader/PageHeader'; -import { sortTypes } from 'utils/sortTypes'; -import { IconCell } from 'component/common/Table/cells/IconCell/IconCell'; -import { ActionCell } from 'component/common/Table/cells/ActionCell/ActionCell'; -import { ConfigureAddonsButton } from './ConfigureAddonButton/ConfigureAddonsButton'; -import { IntegrationIcon } from '../IntegrationIcon/IntegrationIcon'; -import { AddonNameCell } from '../AddonNameCell/AddonNameCell'; -import type { AddonTypeSchema } from 'openapi'; - -interface IAvailableAddonsProps { - providers: AddonTypeSchema[]; - loading: boolean; -} - -/** - * @deprecated Remove when integrationsRework flag is removed - */ -export const AvailableAddons = ({ - providers, - loading, -}: IAvailableAddonsProps) => { - const data = useMemo(() => { - if (loading) { - return Array(5).fill({ - name: 'Provider name', - description: 'Provider description when loading', - }); - } - - return providers.map( - ({ name, displayName, description, deprecated, installation }) => ({ - name, - displayName, - description, - deprecated, - installation, - }) - ); - }, [providers, loading]); - - const columns = useMemo( - () => [ - { - id: 'Icon', - Cell: ({ - row: { - original: { name }, - }, - }: any) => { - return ( - } - /> - ); - }, - }, - { - Header: 'Name', - accessor: 'name', - width: '90%', - Cell: ({ row: { original } }: any) => ( - - ), - sortType: 'alphanumeric', - }, - { - id: 'Actions', - align: 'center', - Cell: ({ row: { original } }: any) => ( - - - - ), - width: 150, - disableSortBy: true, - }, - { - accessor: 'description', - disableSortBy: true, - }, - ], - [] - ); - - const initialState = useMemo( - () => ({ - sortBy: [{ id: 'name', desc: false }], - hiddenColumns: ['description'], - }), - [] - ); - - const { - getTableProps, - getTableBodyProps, - headerGroups, - rows, - prepareRow, - state: { globalFilter }, - } = useTable( - { - columns: columns as any[], // TODO: fix after `react-table` v8 update - data, - initialState, - sortTypes, - autoResetGlobalFilter: false, - autoResetSortBy: false, - disableSortRemove: true, - }, - useSortBy - ); - - return ( - } - > - - - - {rows.map(row => { - prepareRow(row); - return ( - - {row.cells.map(cell => ( - - {cell.render('Cell')} - - ))} - - ); - })} - -
- - 0} - show={ - - No providers found matching “ - {globalFilter} - ” - - } - elseShow={ - - No providers available. - - } - /> - } - /> -
- ); -}; diff --git a/frontend/src/component/integrations/IntegrationList/AvailableAddons/ConfigureAddonButton/ConfigureAddonsButton.tsx b/frontend/src/component/integrations/IntegrationList/AvailableAddons/ConfigureAddonButton/ConfigureAddonsButton.tsx deleted file mode 100644 index 74074ad8c0..0000000000 --- a/frontend/src/component/integrations/IntegrationList/AvailableAddons/ConfigureAddonButton/ConfigureAddonsButton.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import PermissionButton from 'component/common/PermissionButton/PermissionButton'; -import { CREATE_ADDON } from 'component/providers/AccessProvider/permissions'; -import type { AddonTypeSchema } from 'openapi'; -import { useNavigate } from 'react-router-dom'; - -interface IConfigureAddonsButtonProps { - provider: AddonTypeSchema; -} - -/** - * @deprecated Remove when integrationsRework flag is removed - */ -export const ConfigureAddonsButton = ({ - provider, -}: IConfigureAddonsButtonProps) => { - const navigate = useNavigate(); - - return ( - { - navigate(`/addons/create/${provider.name}`); - }} - > - Configure - - ); -}; diff --git a/frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddons.tsx b/frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddons.tsx deleted file mode 100644 index ce64f96c97..0000000000 --- a/frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddons.tsx +++ /dev/null @@ -1,241 +0,0 @@ -import { Table, TableBody, TableCell, TableRow } from 'component/common/Table'; -import { useMemo, useState, useCallback } from 'react'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { PageContent } from 'component/common/PageContent/PageContent'; -import useAddons from 'hooks/api/getters/useAddons/useAddons'; -import useToast from 'hooks/useToast'; -import useAddonsApi from 'hooks/api/actions/useAddonsApi/useAddonsApi'; -import { Dialogue } from 'component/common/Dialogue/Dialogue'; -import { formatUnknownError } from 'utils/formatUnknownError'; -import { sortTypes } from 'utils/sortTypes'; -import { useTable, useSortBy } from 'react-table'; -import { PageHeader } from 'component/common/PageHeader/PageHeader'; -import { SortableTableHeader, TablePlaceholder } from 'component/common/Table'; -import { IconCell } from 'component/common/Table/cells/IconCell/IconCell'; -import { IntegrationIcon } from '../IntegrationIcon/IntegrationIcon'; -import { ConfiguredAddonsActionsCell } from './ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell'; -import { AddonNameCell } from '../AddonNameCell/AddonNameCell'; -import { AddonSchema } from 'openapi'; - -/** - * @deprecated Remove when integrationsRework flag is removed - */ -export const ConfiguredAddons = () => { - const { refetchAddons, addons, providers, loading } = useAddons(); - const { updateAddon, removeAddon } = useAddonsApi(); - const { setToastData, setToastApiError } = useToast(); - const [showDelete, setShowDelete] = useState(false); - const [deletedAddon, setDeletedAddon] = useState({ - id: 0, - provider: '', - description: '', - enabled: false, - events: [], - parameters: {}, - }); - - const data = useMemo(() => { - if (loading) { - return Array(5).fill({ - name: 'Addon name', - description: 'Addon description when loading', - }); - } - - return addons.map(addon => ({ - ...addon, - })); - }, [addons, loading]); - - const toggleAddon = useCallback( - async (addon: AddonSchema) => { - try { - await updateAddon({ ...addon, enabled: !addon.enabled }); - refetchAddons(); - setToastData({ - type: 'success', - title: 'Success', - text: !addon.enabled - ? 'Addon is now enabled' - : 'Addon is now disabled', - }); - } catch (error: unknown) { - setToastApiError(formatUnknownError(error)); - throw error; // caught by optimistic update - } - }, - [setToastApiError, refetchAddons, setToastData, updateAddon] - ); - - const columns = useMemo( - () => [ - { - accessor: 'id', - Cell: ({ - row: { - original: { provider }, - }, - }: any) => ( - } - /> - ), - disableSortBy: true, - }, - { - Header: 'Name', - accessor: 'provider', - width: '90%', - Cell: ({ - row: { - original: { provider, description }, - }, - }: any) => ( - name === provider - ) || { - displayName: provider, - }), - description, - }} - /> - ), - sortType: 'alphanumeric', - }, - { - Header: 'Actions', - id: 'Actions', - align: 'center', - Cell: ({ - row: { original }, - }: { - row: { original: AddonSchema }; - }) => ( - - ), - width: 150, - disableSortBy: true, - }, - { - accessor: 'description', - disableSortBy: true, - }, - ], - [toggleAddon] - ); - - const initialState = useMemo( - () => ({ - sortBy: [ - { id: 'provider', desc: false }, - { id: 'id', desc: false }, - ], - hiddenColumns: ['description'], - }), - [] - ); - - const { - getTableProps, - getTableBodyProps, - headerGroups, - rows, - prepareRow, - state: { globalFilter }, - } = useTable( - { - columns: columns as any[], // TODO: fix after `react-table` v8 update - data, - initialState, - sortTypes, - autoResetGlobalFilter: false, - autoResetSortBy: false, - disableSortRemove: true, - }, - useSortBy - ); - - const onRemoveAddon = async (addon: AddonSchema) => { - try { - await removeAddon(addon.id); - refetchAddons(); - setToastData({ - type: 'success', - title: 'Success', - text: 'Deleted addon successfully', - }); - } catch (error: unknown) { - setToastApiError(formatUnknownError(error)); - } - }; - - return ( - } - sx={theme => ({ marginBottom: theme.spacing(2) })} - > - - - - {rows.map(row => { - prepareRow(row); - return ( - - {row.cells.map(cell => ( - - {cell.render('Cell')} - - ))} - - ); - })} - -
- 0} - show={ - - No addons found matching “ - {globalFilter} - ” - - } - elseShow={ - - No addons configured - - } - /> - } - /> - { - onRemoveAddon(deletedAddon); - setShowDelete(false); - }} - onClose={() => { - setShowDelete(false); - }} - title="Confirm deletion" - > -
Are you sure you want to delete this Addon?
-
-
- ); -}; diff --git a/frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx b/frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx deleted file mode 100644 index fa1af5fc52..0000000000 --- a/frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { Edit, Delete } from '@mui/icons-material'; -import { Tooltip } from '@mui/material'; -import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton'; -import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch'; -import { ActionCell } from 'component/common/Table/cells/ActionCell/ActionCell'; -import { useOptimisticUpdate } from 'component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/hooks/useOptimisticUpdate'; -import { - UPDATE_ADDON, - DELETE_ADDON, -} from 'component/providers/AccessProvider/permissions'; -import { AddonSchema } from 'openapi'; -import { useNavigate } from 'react-router-dom'; - -interface IConfiguredAddonsActionsCellProps { - toggleAddon: (addon: AddonSchema) => Promise; - original: AddonSchema; - setShowDelete: React.Dispatch>; - setDeletedAddon: React.Dispatch>; -} - -/** - * @deprecated Remove when integrationsRework flag is removed - */ -export const ConfiguredAddonsActionsCell = ({ - toggleAddon, - setShowDelete, - setDeletedAddon, - original, -}: IConfiguredAddonsActionsCellProps) => { - const navigate = useNavigate(); - const [isEnabled, setIsEnabled, rollbackIsChecked] = - useOptimisticUpdate(original.enabled); - - const onClick = () => { - setIsEnabled(!isEnabled); - toggleAddon(original).catch(rollbackIsChecked); - }; - - return ( - - - - - - navigate(`/addons/edit/${original.id}`)} - > - - - { - setDeletedAddon(original); - setShowDelete(true); - }} - > - - - - ); -}; diff --git a/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap b/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap index eba6d685c4..6d2589ba0f 100644 --- a/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap +++ b/frontend/src/component/menu/__tests__/__snapshots__/routes.test.tsx.snap @@ -308,11 +308,7 @@ exports[`returns all baseRoutes 1`] = ` { "component": [Function], "hidden": false, - "menu": { - "advanced": true, - "mobile": true, - }, - "notFlag": "integrationsRework", + "menu": {}, "path": "/addons", "title": "Addons", "type": "protected", @@ -343,7 +339,6 @@ exports[`returns all baseRoutes 1`] = ` }, { "component": [Function], - "flag": "integrationsRework", "hidden": false, "menu": { "advanced": true, diff --git a/frontend/src/component/menu/routes.ts b/frontend/src/component/menu/routes.ts index 421c081a3d..8e649fc3c2 100644 --- a/frontend/src/component/menu/routes.ts +++ b/frontend/src/component/menu/routes.ts @@ -43,9 +43,9 @@ import { LazyAdmin } from 'component/admin/LazyAdmin'; import { LazyProject } from 'component/project/Project/LazyProject'; import { LoginHistory } from 'component/loginHistory/LoginHistory'; import { FeatureTypesList } from 'component/featureTypes/FeatureTypesList'; -import { AddonsList } from 'component/integrations/IntegrationList/AddonsList'; import { ViewIntegration } from 'component/integrations/ViewIntegration/ViewIntegration'; import { ApplicationList } from '../application/ApplicationList/ApplicationList'; +import { AddonRedirect } from 'component/integrations/AddonRedirect/AddonRedirect'; export const routes: IRoute[] = [ // Splash @@ -306,8 +306,7 @@ export const routes: IRoute[] = [ path: '/addons/create/:providerId', parent: '/addons', title: 'Create', - component: CreateIntegration, - // TODO: use AddonRedirect after removing `integrationsRework` menu flag + component: AddonRedirect, type: 'protected', menu: {}, }, @@ -315,21 +314,17 @@ export const routes: IRoute[] = [ path: '/addons/edit/:addonId', parent: '/addons', title: 'Edit', - component: EditIntegration, - // TODO: use AddonRedirect after removing `integrationsRework` menu flag + component: AddonRedirect, type: 'protected', menu: {}, }, { path: '/addons', title: 'Addons', - component: AddonsList, - // TODO: use AddonRedirect after removing `integrationsRework` menu flag + component: AddonRedirect, hidden: false, type: 'protected', - notFlag: 'integrationsRework', - menu: { mobile: true, advanced: true }, - // TODO: remove 'addons' from menu after removing `integrationsRework` menu flag + menu: {}, }, { path: '/integrations/create/:providerId', @@ -362,7 +357,6 @@ export const routes: IRoute[] = [ hidden: false, type: 'protected', menu: { mobile: true, advanced: true }, - flag: 'integrationsRework', }, // Segments diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index e4438d0d4b..290af1e5a6 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -59,7 +59,6 @@ export type UiFlags = { customRootRolesKillSwitch?: boolean; strategyVariant?: boolean; lastSeenByEnvironment?: boolean; - integrationsRework?: boolean; multipleRoles?: boolean; featureNamingPattern?: boolean; doraMetrics?: boolean; diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index aacb6303a1..59a28fd6e8 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -87,7 +87,6 @@ exports[`should create default config 1`] = ` "featuresExportImport": true, "filterInvalidClientMetrics": false, "googleAuthEnabled": false, - "integrationsRework": false, "lastSeenByEnvironment": false, "maintenanceMode": false, "messageBanner": { @@ -127,7 +126,6 @@ exports[`should create default config 1`] = ` "featuresExportImport": true, "filterInvalidClientMetrics": false, "googleAuthEnabled": false, - "integrationsRework": false, "lastSeenByEnvironment": false, "maintenanceMode": false, "messageBanner": { diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 8aed0e0e5e..d7dd19770f 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -24,7 +24,6 @@ export type IFlagKey = | 'filterInvalidClientMetrics' | 'lastSeenByEnvironment' | 'customRootRolesKillSwitch' - | 'integrationsRework' | 'multipleRoles' | 'featureNamingPattern' | 'doraMetrics' @@ -116,10 +115,6 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_CUSTOM_ROOT_ROLES_KILL_SWITCH, false, ), - integrationsRework: parseEnvVarBoolean( - process.env.UNLEASH_INTEGRATIONS, - false, - ), multipleRoles: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_MULTIPLE_ROLES, false, diff --git a/src/server-dev.ts b/src/server-dev.ts index 4853f62166..41e7ed2177 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -39,7 +39,6 @@ process.nextTick(async () => { responseTimeWithAppNameKillSwitch: false, slackAppAddon: true, lastSeenByEnvironment: true, - integrationsRework: true, featureNamingPattern: true, doraMetrics: true, variantTypeNumber: true, From b9a860730c98ba2758eed38127347014894041c6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 14:30:57 +0000 Subject: [PATCH 4/9] chore(deps): update dependency fast-check to v3.13.0 (#4797) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [fast-check](https://togithub.com/dubzzz/fast-check) | [`3.12.1` -> `3.13.0`](https://renovatebot.com/diffs/npm/fast-check/3.12.1/3.13.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/fast-check/3.13.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/fast-check/3.13.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/fast-check/3.12.1/3.13.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/fast-check/3.12.1/3.13.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
dubzzz/fast-check (fast-check) ### [`v3.13.0`](https://togithub.com/dubzzz/fast-check/blob/HEAD/packages/fast-check/CHANGELOG.md#3130) [Compare Source](https://togithub.com/dubzzz/fast-check/compare/v3.12.1...v3.13.0) *New options for `date`, `record` and `dictionary`* \[[Code](https://togithub.com/dubzzz/fast-check/tree/v3.13.0)]\[[Diff](https://togithub.com/dubzzz/fast-check/compare/v3.12.1...v3.13.0)] #### Features - ([PR#4197](https://togithub.com/dubzzz/fast-check/pull/4197)) Add support for "Invalid Date" in `date` - ([PR#4203](https://togithub.com/dubzzz/fast-check/pull/4203)) Deprecate `withDeletedKeys` on `record` - ([PR#4204](https://togithub.com/dubzzz/fast-check/pull/4204)) Support null-proto in `dictionary` - ([PR#4205](https://togithub.com/dubzzz/fast-check/pull/4205)) Support null-proto in `record` #### Fixes - ([PR#4207](https://togithub.com/dubzzz/fast-check/pull/4207)) Bug: Better poisoning resiliency for `dictionary` - ([PR#4194](https://togithub.com/dubzzz/fast-check/pull/4194)) CI: Add some more details onto the PWA - ([PR#4211](https://togithub.com/dubzzz/fast-check/pull/4211)) CI: Rework broken test on `date` - ([PR#4212](https://togithub.com/dubzzz/fast-check/pull/4212)) CI: Rework broken test on `date` (retry) - ([PR#4214](https://togithub.com/dubzzz/fast-check/pull/4214)) CI: Rework another broken test on date - ([PR#4186](https://togithub.com/dubzzz/fast-check/pull/4186)) Doc: Document our approach to dual package - ([PR#4187](https://togithub.com/dubzzz/fast-check/pull/4187)) Doc: Expose website as PWA too - ([PR#4190](https://togithub.com/dubzzz/fast-check/pull/4190)) Move: Move the manifest in /static - ([PR#4206](https://togithub.com/dubzzz/fast-check/pull/4206)) Refactor: Re-use null-proto helpers of `dictionary` on `anything` - ([PR#4189](https://togithub.com/dubzzz/fast-check/pull/4189)) Test: Drop Node 14.x from the test-chain ***
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/Unleash/unleash). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d079c8a22c..693b7e4280 100644 --- a/package.json +++ b/package.json @@ -205,7 +205,7 @@ "eslint-plugin-prettier": "4.2.1", "eslint-plugin-regexp": "^1.14.0", "faker": "5.5.3", - "fast-check": "3.12.1", + "fast-check": "3.13.0", "fetch-mock": "9.11.0", "husky": "8.0.3", "jest": "29.6.4", diff --git a/yarn.lock b/yarn.lock index 82d5e53d57..d6e3ec40ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3603,10 +3603,10 @@ faker@5.5.3: resolved "https://registry.yarnpkg.com/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e" integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g== -fast-check@3.12.1: - version "3.12.1" - resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.12.1.tgz#00c35e83bcbec80fd35e0c204f9996309f004b3d" - integrity sha512-aRN6WrO+q3TZV8CjXnpebx9bTHrpYIOVi6v3ttxciZiWqS739yy8b1oVx+qNEyV1b8RdVjlp/+miTY6yAp90HA== +fast-check@3.13.0: + version "3.13.0" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.13.0.tgz#1099a36fd945fb06f6e68e261c91fa8c70c29802" + integrity sha512-m6+3gZ/yTiCWTuV/1e/UuPPjyyyHdQ5gu0pMd84C6705VTDjAgAE6nqFT5jhgegFllCJ95yOzBpqvJSs2DZAxQ== dependencies: pure-rand "^6.0.0" From 7233143ace148db0e79bc34afa2d6dd61152d55f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:14:36 +0000 Subject: [PATCH 5/9] chore(deps): update dependency jest to v29.7.0 (#4799) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [jest](https://jestjs.io/) ([source](https://togithub.com/jestjs/jest)) | [`29.6.4` -> `29.7.0`](https://renovatebot.com/diffs/npm/jest/29.6.4/29.7.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/jest/29.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/jest/29.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/jest/29.6.4/29.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/jest/29.6.4/29.7.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
jestjs/jest (jest) ### [`v29.7.0`](https://togithub.com/jestjs/jest/blob/HEAD/CHANGELOG.md#2970) [Compare Source](https://togithub.com/jestjs/jest/compare/v29.6.4...v29.7.0) ##### Features - `[create-jest]` Add `npm init` / `yarn create` initialiser for Jest projects ([#​14465](https://togithub.com/jestjs/jest/pull/14453)) - `[jest-validate]` Allow deprecation warnings for unknown options ([#​14499](https://togithub.com/jestjs/jest/pull/14499)) ##### Fixes - `[jest-resolver]` Replace unmatched capture groups in `moduleNameMapper` with empty string instead of `undefined` ([#​14507](https://togithub.com/jestjs/jest/pull/14507)) - `[jest-snapshot]` Allow for strings as well as template literals in inline snapshots ([#​14465](https://togithub.com/jestjs/jest/pull/14465)) - `[@jest/test-sequencer]` Calculate test runtime if `perStats.duration` is missing ([#​14473](https://togithub.com/jestjs/jest/pull/14473)) ##### Performance - `[@jest/create-cache-key-function]` Cache access of `NODE_ENV` and `BABEL_ENV` ([#​14455](https://togithub.com/jestjs/jest/pull/14455)) ##### Chore & Maintenance - `[jest-cli]` Move internal config initialisation logic to the `create-jest` package ([#​14465](https://togithub.com/jestjs/jest/pull/14453))
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/Unleash/unleash). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 693b7e4280..38848e3fc1 100644 --- a/package.json +++ b/package.json @@ -208,7 +208,7 @@ "fast-check": "3.13.0", "fetch-mock": "9.11.0", "husky": "8.0.3", - "jest": "29.6.4", + "jest": "29.7.0", "jest-junit": "^16.0.0", "lint-staged": "13.2.3", "nock": "13.3.3", diff --git a/yarn.lock b/yarn.lock index d6e3ec40ab..7e2f50ea8f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -761,7 +761,7 @@ jest-util "^29.7.0" slash "^3.0.0" -"@jest/core@^29.6.4", "@jest/core@^29.7.0": +"@jest/core@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== @@ -4761,7 +4761,7 @@ jest-circus@^29.7.0: slash "^3.0.0" stack-utils "^2.0.3" -jest-cli@^29.6.4: +jest-cli@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== @@ -5136,15 +5136,15 @@ jest-worker@^29.7.0: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@29.6.4: - version "29.6.4" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.6.4.tgz#7c48e67a445ba264b778253b5d78d4ebc9d0a622" - integrity sha512-tEFhVQFF/bzoYV1YuGyzLPZ6vlPrdfvDmmAxudA1dLEuiztqg2Rkx20vkKY32xiDROcD2KXlgZ7Cu8RPeEHRKw== +jest@29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: - "@jest/core" "^29.6.4" + "@jest/core" "^29.7.0" "@jest/types" "^29.6.3" import-local "^3.0.2" - jest-cli "^29.6.4" + jest-cli "^29.7.0" joi@^17.3.0, joi@^17.7.0: version "17.10.1" From 5e6ed0baac9df0922372ccb153721b5c15632b37 Mon Sep 17 00:00:00 2001 From: Jaanus Sellin Date: Thu, 21 Sep 2023 11:22:29 +0300 Subject: [PATCH 6/9] feat: private projects handle in playground (#4791) --- .../playground/advanced-playground.test.ts | 1 + .../features/playground/playground-service.ts | 40 +++++++++++++++++-- src/lib/features/playground/playground.ts | 5 ++- .../client-metrics/instance-service.ts | 5 ++- src/lib/services/index.ts | 1 + .../e2e/services/playground-service.test.ts | 1 + 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/lib/features/playground/advanced-playground.test.ts b/src/lib/features/playground/advanced-playground.test.ts index bf53d177f9..c2e6c8c52f 100644 --- a/src/lib/features/playground/advanced-playground.test.ts +++ b/src/lib/features/playground/advanced-playground.test.ts @@ -19,6 +19,7 @@ beforeAll(async () => { advancedPlayground: true, strictSchemaValidation: true, strategyVariant: true, + privateProjects: true, }, }, }, diff --git a/src/lib/features/playground/playground-service.ts b/src/lib/features/playground/playground-service.ts index ef4495c1c0..4ffcf8d813 100644 --- a/src/lib/features/playground/playground-service.ts +++ b/src/lib/features/playground/playground-service.ts @@ -4,7 +4,7 @@ import { IUnleashServices } from 'lib/types/services'; import { ALL } from '../../types/models/api-token'; import { PlaygroundFeatureSchema } from 'lib/openapi/spec/playground-feature-schema'; import { Logger } from '../../logger'; -import { ISegment, IUnleashConfig } from 'lib/types'; +import { IFlagResolver, ISegment, IUnleashConfig } from 'lib/types'; import { offlineUnleashClient } from './offline-unleash-client'; import { FeatureInterface } from 'lib/features/playground/feature-evaluator/feature'; import { @@ -16,10 +16,11 @@ import { FeatureConfigurationClient } from '../../types/stores/feature-strategie import { generateObjectCombinations } from './generateObjectCombinations'; import groupBy from 'lodash.groupby'; import { omitKeys } from '../../util'; -import { AdvancedPlaygroundFeatureSchema } from '../../openapi/spec/advanced-playground-feature-schema'; +import { AdvancedPlaygroundFeatureSchema } from '../../openapi'; import { AdvancedPlaygroundEnvironmentFeatureSchema } from '../../openapi/spec/advanced-playground-environment-feature-schema'; import { validateQueryComplexity } from './validateQueryComplexity'; import { playgroundStrategyEvaluation } from 'lib/openapi'; +import { IPrivateProjectChecker } from '../private-project/privateProjectCheckerType'; type EvaluationInput = { features: FeatureConfigurationClient[]; @@ -66,16 +67,28 @@ export class PlaygroundService { private readonly segmentService: ISegmentService; + private flagResolver: IFlagResolver; + + private privateProjectChecker: IPrivateProjectChecker; + constructor( config: IUnleashConfig, { featureToggleServiceV2, segmentService, - }: Pick, + privateProjectChecker, + }: Pick< + IUnleashServices, + | 'featureToggleServiceV2' + | 'segmentService' + | 'privateProjectChecker' + >, ) { this.logger = config.getLogger('services/playground-service.ts'); + this.flagResolver = config.flagResolver; this.featureToggleService = featureToggleServiceV2; this.segmentService = segmentService; + this.privateProjectChecker = privateProjectChecker; } async evaluateAdvancedQuery( @@ -83,10 +96,29 @@ export class PlaygroundService { environments: string[], context: SdkContextSchema, limit: number, + userId: number, ): Promise { const segments = await this.segmentService.getActive(); + + let filteredProjects: typeof projects; + if (this.flagResolver.isEnabled('privateProjects')) { + const accessibleProjects = + await this.privateProjectChecker.getUserAccessibleProjects( + userId, + ); + filteredProjects = + projects === ALL + ? accessibleProjects + : projects.filter((project) => + accessibleProjects.includes(project), + ); + console.log(accessibleProjects); + } + const environmentFeatures = await Promise.all( - environments.map((env) => this.resolveFeatures(projects, env)), + environments.map((env) => + this.resolveFeatures(filteredProjects, env), + ), ); const contexts = generateObjectCombinations(context); diff --git a/src/lib/features/playground/playground.ts b/src/lib/features/playground/playground.ts index ef165a9890..5822f4ea43 100644 --- a/src/lib/features/playground/playground.ts +++ b/src/lib/features/playground/playground.ts @@ -20,6 +20,7 @@ import { advancedPlaygroundViewModel, playgroundViewModel, } from './playground-view-model'; +import { IAuthRequest } from '../../routes/unleash-types'; export default class PlaygroundController extends Controller { private openApiService: OpenApiService; @@ -112,9 +113,10 @@ export default class PlaygroundController extends Controller { } async evaluateAdvancedContext( - req: Request, + req: IAuthRequest, res: Response, ): Promise { + const { user } = req; // used for runtime control, do not remove const { payload } = this.flagResolver.getVariant('advancedPlayground'); const limit = @@ -127,6 +129,7 @@ export default class PlaygroundController extends Controller { req.body.environments, req.body.context, limit, + user.id, ); const response: AdvancedPlaygroundResponseSchema = diff --git a/src/lib/services/client-metrics/instance-service.ts b/src/lib/services/client-metrics/instance-service.ts index 8cb503d5a7..19cca5a26b 100644 --- a/src/lib/services/client-metrics/instance-service.ts +++ b/src/lib/services/client-metrics/instance-service.ts @@ -20,6 +20,7 @@ import { clientMetricsSchema } from './schema'; import { PartialSome } from '../../types/partial'; import { IPrivateProjectChecker } from '../../features/private-project/privateProjectCheckerType'; import { IFlagResolver } from '../../types'; +import { ALL_PROJECTS } from '../../util'; export default class ClientInstanceService { apps = {}; @@ -178,7 +179,7 @@ export default class ClientInstanceService { ): Promise { const applications = await this.clientApplicationsStore.getAppsForStrategy(query); - if (this.flagResolver.isEnabled('privateProjects') && userId) { + if (this.flagResolver.isEnabled('privateProjects')) { const accessibleProjects = await this.privateProjectChecker.getUserAccessibleProjects( userId, @@ -188,7 +189,7 @@ export default class ClientInstanceService { ...application, usage: application.usage?.filter( (usageItem) => - usageItem.project === '*' || + usageItem.project === ALL_PROJECTS || accessibleProjects.includes(usageItem.project), ), }; diff --git a/src/lib/services/index.ts b/src/lib/services/index.ts index 433f008bb9..a3db29e6cf 100644 --- a/src/lib/services/index.ts +++ b/src/lib/services/index.ts @@ -251,6 +251,7 @@ export const createServices = ( const playgroundService = new PlaygroundService(config, { featureToggleServiceV2, segmentService, + privateProjectChecker, }); const configurationRevisionService = new ConfigurationRevisionService( diff --git a/src/test/e2e/services/playground-service.test.ts b/src/test/e2e/services/playground-service.test.ts index 058e713b6f..89b1dc0758 100644 --- a/src/test/e2e/services/playground-service.test.ts +++ b/src/test/e2e/services/playground-service.test.ts @@ -63,6 +63,7 @@ beforeAll(async () => { service = new PlaygroundService(config, { featureToggleServiceV2: featureToggleService, segmentService, + privateProjectChecker, }); }); From b1234fb89c545f6d7b71707ca66a613efa4a49ca Mon Sep 17 00:00:00 2001 From: Simon Hornby Date: Thu, 21 Sep 2023 11:12:20 +0200 Subject: [PATCH 7/9] fix: force permissions export to only be enterprise in ui (#4760) --- frontend/src/component/admin/users/UsersList/UsersList.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/component/admin/users/UsersList/UsersList.tsx b/frontend/src/component/admin/users/UsersList/UsersList.tsx index 027b107e81..74bb5ad1eb 100644 --- a/frontend/src/component/admin/users/UsersList/UsersList.tsx +++ b/frontend/src/component/admin/users/UsersList/UsersList.tsx @@ -34,6 +34,7 @@ import { RoleCell } from 'component/common/Table/cells/RoleCell/RoleCell'; import { useSearch } from 'hooks/useSearch'; import { Download } from '@mui/icons-material'; import { useUiFlag } from 'hooks/useUiFlag'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; const UsersList = () => { const navigate = useNavigate(); @@ -44,6 +45,7 @@ const UsersList = () => { const [pwDialog, setPwDialog] = useState<{ open: boolean; user?: IUser }>({ open: false, }); + const { isEnterprise } = useUiConfig(); const [delDialog, setDelDialog] = useState(false); const [showConfirm, setShowConfirm] = useState(false); const [emailSent, setEmailSent] = useState(false); @@ -271,7 +273,10 @@ const UsersList = () => { ( <> Date: Thu, 21 Sep 2023 11:46:39 +0200 Subject: [PATCH 8/9] docs: add info on how to troubleshoot and better errors (#4803) This PR adds some troubleshooting information to the website readme and also makes it so that we get more readable errors in the build logs when something goes wrong. --- .github/workflows/build_doc_prs.yaml | 7 +++- website/README.md | 58 ++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_doc_prs.yaml b/.github/workflows/build_doc_prs.yaml index 46971c60c6..122eedc5e6 100644 --- a/.github/workflows/build_doc_prs.yaml +++ b/.github/workflows/build_doc_prs.yaml @@ -17,4 +17,9 @@ jobs: UNLEASH_PROXY_URL: ${{ secrets.UNLEASH_PROXY_URL_DEVELOPMENT }} run: | # Build the site - cd website && yarn && yarn build + cd website && yarn + # give better error messages when the build fails (refer to website/readme.md#troubleshooting) + echo "Removing references to chalk in node_modules/@docusaurus/core/lib/client/serverEntry.js" + sed -i 's/chalk\(\w\|\.\)\+//g' node_modules/@docusaurus/core/lib/client/serverEntry.js + echo "Chalk removed" + yarn build diff --git a/website/README.md b/website/README.md index 7eee45919d..7d8ca67f75 100644 --- a/website/README.md +++ b/website/README.md @@ -39,3 +39,61 @@ GIT_USER= USE_SSH=true yarn deploy ``` If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. + +## Troubleshooting + +### `TypeError: source_default(...).bold is not a function` + +If you get an error like this, it's probably due to a formatting issue within one of the markdown files. It could be + +- unescaped angle brackets (markdown will try to parse `` (when it's not quoted) as HTML, which breaks the build) +- incorrectly formatted titles or missing pieces of files +- a lot of other stuff. + +```console +Component Figure was not imported, exported, or provided by MDXProvider as global scope + +TypeError: source_default(...).bold is not a function +[ERROR] Unable to build website for locale en. +``` + +This error is very hard to debug, but there is a trick that appears to work (as shared in [this discussion on docusaurus' repo](https://github.com/facebook/docusaurus/issues/7686#issuecomment-1486771382)): + +In `node_modules/@docusaurus/core/lib/client/serverEntry.js`, remove all references to `chalk`. You can use a regex replace for that, by replacing `chalk(\w|\.)+` with the empty string. + +Depending on your editor, that regex might need more escapes. For instance, here's a command to run with `evil-ex` in Emacs: + +``` +%s/chalk\(\w\|\.\)+//g +``` + +For macOS `sed`, it'd be: + +```shell +sed -i '' 's/chalk\(\w\|\.\)\+//g' node_modules/@docusaurus/core/lib/client/serverEntry.js +``` + +For GNU `sed`: + +```shell +sed -i 's/chalk\(\w\|\.\)\+//g' node_modules/@docusaurus/core/lib/client/serverEntry.js +``` + +That might turn your error into something like this: + +```console +[ERROR] Docusaurus server-side rendering could not render static page with path /reference/api/unleash/change-requests. +[ERROR] Docusaurus server-side rendering could not render static page with path /reference/api/unleash/feature-types. +[ERROR] Docusaurus server-side rendering could not render static page with path /reference/api/unleash/frontend-api. +[ERROR] Docusaurus server-side rendering could not render static page with path /reference/api/unleash/maintenance. +[ERROR] Docusaurus server-side rendering could not render static page with path /reference/api/unleash/notifications. +[ERROR] Docusaurus server-side rendering could not render static page with path /reference/api/unleash/personal-access-tokens. +[ERROR] Docusaurus server-side rendering could not render static page with path /reference/api/unleash/segments. +[ERROR] Docusaurus server-side rendering could not render static page with path /reference/api/unleash/service-accounts. +[ERROR] Docusaurus server-side rendering could not render static page with path /reference/api/unleash/telemetry. +[ERROR] Docusaurus server-side rendering could not render static page with path /reference/api/unleash/unstable. +Component Figure was not imported, exported, or provided by MDXProvider as global scope + +Error: Unexpected: cant find current sidebar in context +[ERROR] Unable to build website for locale en. +``` From 6884f9cdc9048fad87a7b42c82ccb6be87fcf7ab Mon Sep 17 00:00:00 2001 From: Fredrik Strand Oseberg Date: Thu, 21 Sep 2023 14:28:45 +0200 Subject: [PATCH 9/9] feat: strategy variants on strategy overview (#4776) Refactors the breakdown of feature variants per strategy on the environment overview level: --- .../TooltipResolver/TooltipResolver.tsx | 1 - .../StrategyItem/StrategyItem.tsx | 4 + .../SplitPreviewSlider/SplitPreviewSlider.tsx | 198 +++++++++++++++--- .../StrategyTypes/StrategyVariants.tsx | 4 +- 4 files changed, 170 insertions(+), 37 deletions(-) diff --git a/frontend/src/component/common/TooltipResolver/TooltipResolver.tsx b/frontend/src/component/common/TooltipResolver/TooltipResolver.tsx index 8aea828f5c..d4860ac7ff 100644 --- a/frontend/src/component/common/TooltipResolver/TooltipResolver.tsx +++ b/frontend/src/component/common/TooltipResolver/TooltipResolver.tsx @@ -18,7 +18,6 @@ export const TooltipResolver = ({ if (!title && !titleComponent) { return children; } - if (variant === 'custom') { return ( diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.tsx index d71a619f6d..1cfef9da74 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.tsx @@ -12,6 +12,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit import { CopyStrategyIconMenu } from './CopyStrategyIconMenu/CopyStrategyIconMenu'; import { StrategyItemContainer } from 'component/common/StrategyItemContainer/StrategyItemContainer'; import MenuStrategyRemove from './MenuStrategyRemove/MenuStrategyRemove'; +import SplitPreviewSlider from 'component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider'; interface IStrategyItemProps { environmentId: string; @@ -86,6 +87,9 @@ export const StrategyItem: FC = ({ } > + {strategy.variants ? ( + + ) : null} ); }; diff --git a/frontend/src/component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider.tsx b/frontend/src/component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider.tsx index 6ddd8425a0..7d761579e8 100644 --- a/frontend/src/component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider.tsx +++ b/frontend/src/component/feature/StrategyTypes/SplitPreviewSlider/SplitPreviewSlider.tsx @@ -1,10 +1,9 @@ import { Box, Typography, styled } from '@mui/material'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import { TooltipResolver } from 'component/common/TooltipResolver/TooltipResolver'; +import { IFeatureVariant } from 'interfaces/featureToggle'; -type SplitPreviewSliderProps = { - values: number[]; -}; - -const StyledContainer = styled(Box)(({ theme }) => ({ +const StyledContainer = styled(Box)(() => ({ display: 'flex', width: '100%', position: 'relative', @@ -18,55 +17,188 @@ const StyledTrack = styled(Box)(({ theme }) => ({ overflow: 'hidden', })); -const StyledSegment = styled(Box)(({ theme }) => ({ +const StyledSegment = styled(Box)(() => ({ height: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', + width: '100%', })); -const StyledSegmentTrack = styled(Box)(({ theme }) => ({ - height: theme.spacing(3), +const StyledSegmentTrack = styled(Box, { + shouldForwardProp: prop => prop !== 'index', +})<{ index: number }>(({ theme, index }) => ({ + height: theme.spacing(1.8), width: '100%', position: 'relative', + background: theme.palette.variants[index % theme.palette.variants.length], })); -const SplitPreviewSlider = ({ values }: SplitPreviewSliderProps) => { - if (values.length < 2) { +const StyledHeaderContainer = styled(Box)(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + marginBottom: theme.spacing(1), +})); + +const StyledTypography = styled(Typography)(({ theme }) => ({ + marginY: theme.spacing(1), +})); + +const StyledVariantBoxContainer = styled(Box)(() => ({ + display: 'flex', + alignItems: 'center', + marginLeft: 'auto', +})); + +const StyledVariantBox = styled(Box, { + shouldForwardProp: prop => prop !== 'index', +})<{ index: number }>(({ theme, index }) => ({ + display: 'flex', + alignItems: 'center', + marginRight: theme.spacing(2), + '& div': { + width: theme.spacing(1.6), + height: theme.spacing(1.6), + borderRadius: '50%', + marginRight: theme.spacing(1), + background: + theme.palette.variants[index % theme.palette.variants.length], + }, +})); + +const StyledTypographySubtitle = styled(Typography)(({ theme }) => ({ + marginTop: theme.spacing(1), +})); + +interface ISplitPreviewSliderProps { + variants: IFeatureVariant[]; +} + +const SplitPreviewSlider = ({ variants }: ISplitPreviewSliderProps) => { + if (variants.length < 2) { return null; } return ( ({ marginTop: theme.spacing(2) })}> - ({ marginY: theme.spacing(1) })} - > - Split preview - + - {values.map((value, index) => ( - - ({ - background: - theme.palette.variants[ - index % theme.palette.variants.length - ], - })} - /> - ({ marginTop: theme.spacing(1) })} + + {variants.map((variant, index) => { + const value = variant.weight / 10; + return ( + e.preventDefault()} + titleComponent={ + + } > - {value}% - - - ))} + + {' '} + + + + {value}% + + + + + ); + })} ); }; +const SplitPreviewHeader = ({ variants }: ISplitPreviewSliderProps) => { + return ( + + + Feature variants ({variants.length}) + + + {variants.map((variant, index) => ( + + + + {variant.name} + + + ))} + + + ); +}; + +interface ISplitPreviewTooltip { + variant: IFeatureVariant; + index: number; +} + +const StyledTooltipContainer = styled(Box)(() => ({ + display: 'flex', + flexDirection: 'column', +})); + +const StyledVariantContainer = styled(Box)(() => ({ + display: 'flex', + alignItems: 'center', + minWidth: '250px', +})); + +const StyledPayloadContainer = styled(Box)(({ theme }) => ({ + marginTop: theme.spacing(1), + display: 'flex', + flexDirection: 'column', +})); + +const StyledPayloadLabel = styled(Typography)(({ theme }) => ({ + marginBottom: theme.spacing(1), +})); + +const SplitPreviewTooltip = ({ variant, index }: ISplitPreviewTooltip) => { + return ( + + + + + + + + {variant.weight / 10}% - {variant.name} + + + + {variant.payload ? ( + + + Payload + + + {variant.payload.value}} + elseShow={ + + {variant.payload.value} + + } + /> + + ) : null} + + ); +}; + export default SplitPreviewSlider; diff --git a/frontend/src/component/feature/StrategyTypes/StrategyVariants.tsx b/frontend/src/component/feature/StrategyTypes/StrategyVariants.tsx index 7d1cb785a8..30177b6d79 100644 --- a/frontend/src/component/feature/StrategyTypes/StrategyVariants.tsx +++ b/frontend/src/component/feature/StrategyTypes/StrategyVariants.tsx @@ -157,9 +157,7 @@ export const StrategyVariants: FC<{ > Add variant - variant.weight / 10)} - /> + ); };