From 573518e48d1f4208476f269d9e8f00a4b510b4f8 Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Tue, 22 Aug 2023 14:40:38 +0200 Subject: [PATCH] Integrations - frontend adjustments (#4527) ## About the changes - [x] Create a feature flag - [x] Rename page title - [x] Rename menu item - [x] Update frontend URL (add redirect from old one) https://linear.app/unleash/issue/1-1263/integrations-frontend-adjustments --- .../component/addons/AddonList/AddonList.tsx | 19 -------- .../AddonRedirect/AddonRedirect.tsx | 19 ++++++++ .../CreateIntegration/CreateIntegration.tsx} | 6 +-- .../EditIntegration/EditIntegration.tsx} | 8 ++-- .../IntegrationForm.styles.tsx} | 0 .../IntegrationForm/IntegrationForm.tsx} | 20 ++++----- .../IntegrationInstall.tsx} | 4 +- .../IntegrationMultiSelector.test.tsx} | 25 +++++++---- .../IntegrationMultiSelector.tsx} | 12 +++--- .../IntegrationParameter.tsx} | 8 ++-- .../IntegrationParameters.tsx} | 22 +++++----- .../AvailableAddons/AvailableAddons.tsx | 18 +++++--- .../ConfigureAddonsButton.tsx} | 9 ++-- .../AvailableIntegrations.tsx | 8 ++++ .../ConfiguredAddons/ConfiguredAddons.tsx | 13 ++++-- .../ConfiguredAddonsActionsCell.tsx | 3 ++ .../IntegrationIcon/IntegrationIcon.tsx} | 4 +- .../IntegrationList/IntegrationList.tsx | 28 ++++++++++++ .../IntegrationNameCell.tsx} | 9 +++- .../__snapshots__/routes.test.tsx.snap | 28 ++++++++++++ frontend/src/component/menu/routes.ts | 43 ++++++++++++++++--- frontend/src/interfaces/uiConfig.ts | 1 + .../__snapshots__/create-config.test.ts.snap | 2 + src/lib/types/experimental.ts | 7 ++- website/README.md | 3 +- 25 files changed, 225 insertions(+), 94 deletions(-) delete mode 100644 frontend/src/component/addons/AddonList/AddonList.tsx create mode 100644 frontend/src/component/integrations/AddonRedirect/AddonRedirect.tsx rename frontend/src/component/{addons/CreateAddon/CreateAddon.tsx => integrations/CreateIntegration/CreateIntegration.tsx} (87%) rename frontend/src/component/{addons/EditAddon/EditAddon.tsx => integrations/EditIntegration/EditIntegration.tsx} (78%) rename frontend/src/component/{addons/AddonForm/AddonForm.styles.tsx => integrations/IntegrationForm/IntegrationForm.styles.tsx} (100%) rename frontend/src/component/{addons/AddonForm/AddonForm.tsx => integrations/IntegrationForm/IntegrationForm.tsx} (95%) rename frontend/src/component/{addons/AddonForm/AddonInstall/AddonInstall.tsx => integrations/IntegrationForm/IntegrationInstall/IntegrationInstall.tsx} (93%) rename frontend/src/component/{addons/AddonForm/AddonMultiSelector/AddonMultiSelector.test.tsx => integrations/IntegrationForm/IntegrationMultiSelector/IntegrationMultiSelector.test.tsx} (88%) rename frontend/src/component/{addons/AddonForm/AddonMultiSelector/AddonMultiSelector.tsx => integrations/IntegrationForm/IntegrationMultiSelector/IntegrationMultiSelector.tsx} (95%) rename frontend/src/component/{addons/AddonForm/AddonParameters/AddonParameter/AddonParameter.tsx => integrations/IntegrationForm/IntegrationParameters/IntegrationParameter/IntegrationParameter.tsx} (90%) rename frontend/src/component/{addons/AddonForm/AddonParameters/AddonParameters.tsx => integrations/IntegrationForm/IntegrationParameters/IntegrationParameters.tsx} (65%) rename frontend/src/component/{addons/AddonList => integrations/IntegrationList}/AvailableAddons/AvailableAddons.tsx (88%) rename frontend/src/component/{addons/AddonList/AvailableAddons/ConfigureAddonButton/ConfigureAddonButton.tsx => integrations/IntegrationList/AvailableAddons/ConfigureAddonButton/ConfigureAddonsButton.tsx} (77%) create mode 100644 frontend/src/component/integrations/IntegrationList/AvailableIntegrations/AvailableIntegrations.tsx rename frontend/src/component/{addons/AddonList => integrations/IntegrationList}/ConfiguredAddons/ConfiguredAddons.tsx (95%) rename frontend/src/component/{addons/AddonList => integrations/IntegrationList}/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx (97%) rename frontend/src/component/{addons/AddonList/AddonIcon/AddonIcon.tsx => integrations/IntegrationList/IntegrationIcon/IntegrationIcon.tsx} (94%) create mode 100644 frontend/src/component/integrations/IntegrationList/IntegrationList.tsx rename frontend/src/component/{addons/AddonList/AddonNameCell/AddonNameCell.tsx => integrations/IntegrationList/IntegrationNameCell/IntegrationNameCell.tsx} (84%) diff --git a/frontend/src/component/addons/AddonList/AddonList.tsx b/frontend/src/component/addons/AddonList/AddonList.tsx deleted file mode 100644 index 5d4de0e8c8a8..000000000000 --- a/frontend/src/component/addons/AddonList/AddonList.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -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'; - -export const AddonList = () => { - const { providers, addons, loading } = useAddons(); - - return ( - <> - 0} - show={} - /> - - - ); -}; diff --git a/frontend/src/component/integrations/AddonRedirect/AddonRedirect.tsx b/frontend/src/component/integrations/AddonRedirect/AddonRedirect.tsx new file mode 100644 index 000000000000..acb916333faf --- /dev/null +++ b/frontend/src/component/integrations/AddonRedirect/AddonRedirect.tsx @@ -0,0 +1,19 @@ +import { Link, useLocation, useNavigate } from 'react-router-dom'; +import { useEffect } from 'react'; +import { PageContent } from 'component/common/PageContent/PageContent'; + +export const AddonRedirect = () => { + const location = useLocation(); + const navigate = useNavigate(); + + useEffect(() => { + navigate(`/integrations${location.pathname.replace('/addons', '')}`); + }, [location.pathname, navigate]); + + return ( + + Addons where renamed to{' '} + /integrations + + ); +}; diff --git a/frontend/src/component/addons/CreateAddon/CreateAddon.tsx b/frontend/src/component/integrations/CreateIntegration/CreateIntegration.tsx similarity index 87% rename from frontend/src/component/addons/CreateAddon/CreateAddon.tsx rename to frontend/src/component/integrations/CreateIntegration/CreateIntegration.tsx index 30548882f179..0158ab9957fe 100644 --- a/frontend/src/component/addons/CreateAddon/CreateAddon.tsx +++ b/frontend/src/component/integrations/CreateIntegration/CreateIntegration.tsx @@ -1,5 +1,5 @@ import useAddons from 'hooks/api/getters/useAddons/useAddons'; -import { AddonForm } from '../AddonForm/AddonForm'; +import { IntegrationForm } from '../IntegrationForm/IntegrationForm'; import cloneDeep from 'lodash.clonedeep'; import { IAddon } from 'interfaces/addons'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; @@ -14,7 +14,7 @@ export const DEFAULT_DATA = { environments: [], } as unknown as IAddon; // TODO: improve type -export const CreateAddon = () => { +export const CreateIntegration = () => { const providerId = useRequiredPathParam('providerId'); const { providers, refetchAddons } = useAddons(); @@ -29,7 +29,7 @@ export const CreateAddon = () => { }; return ( - { +export const EditIntegration = () => { const addonId = useRequiredPathParam('addonId'); const { providers, addons, refetchAddons } = useAddons(); @@ -18,7 +18,7 @@ export const EditAddon = () => { : undefined; return ( - = ({ +export const IntegrationForm: VFC = ({ editMode, provider, addon: initialValues, @@ -272,7 +272,7 @@ export const AddonForm: VFC = ({ ( - = ({ - = ({ /> - = ({ /> - = ({ /> - { }); it('renders with default state', () => { - render(); + render( + + ); const checkbox = screen.getByLabelText( /all current and future projects/i @@ -49,7 +51,9 @@ describe('AddonMultiSelector', () => { it('can toggle "ALL" checkbox', async () => { const user = userEvent.setup(); - render(); + render( + + ); await user.click(screen.getByTestId('select-all-projects')); @@ -70,7 +74,10 @@ describe('AddonMultiSelector', () => { it('renders with autocomplete enabled if default value is not a wildcard', () => { render( - + ); const checkbox = screen.getByLabelText( @@ -87,7 +94,7 @@ describe('AddonMultiSelector', () => { it("doesn't show up for less than 3 options", async () => { const user = userEvent.setup(); render( - { it('can filter options', async () => { const user = userEvent.setup(); render( - void; @@ -44,7 +44,7 @@ const StyledCheckbox = styled(Checkbox)(() => ({ const CustomPaper = ({ ...props }) => ; -export const AddonMultiSelector: VFC = ({ +export const IntegrationMultiSelector: VFC = ({ options, selectedItems, onChange, @@ -138,9 +138,9 @@ export const AddonMultiSelector: VFC = ({ const DefaultHelpText = () => ( - Selecting {entityName}(s) here will filter events so that your addon - will only receive events that are tagged with one of your{' '} - {entityName}s. + Selecting {entityName}(s) here will filter events so that your + integration will only receive events that are tagged with one of + your {entityName}s. ); diff --git a/frontend/src/component/addons/AddonForm/AddonParameters/AddonParameter/AddonParameter.tsx b/frontend/src/component/integrations/IntegrationForm/IntegrationParameters/IntegrationParameter/IntegrationParameter.tsx similarity index 90% rename from frontend/src/component/addons/AddonForm/AddonParameters/AddonParameter/AddonParameter.tsx rename to frontend/src/component/integrations/IntegrationForm/IntegrationParameters/IntegrationParameter/IntegrationParameter.tsx index d4f15ec80bf0..8983a5b9e5c6 100644 --- a/frontend/src/component/addons/AddonForm/AddonParameters/AddonParameter/AddonParameter.tsx +++ b/frontend/src/component/integrations/IntegrationForm/IntegrationParameters/IntegrationParameter/IntegrationParameter.tsx @@ -1,7 +1,7 @@ import { TextField, Typography } from '@mui/material'; import { IAddonConfig, IAddonProviderParams } from 'interfaces/addons'; import { ChangeEventHandler } from 'react'; -import { StyledAddonParameterContainer } from '../../AddonForm.styles'; +import { StyledAddonParameterContainer } from '../../IntegrationForm.styles'; const resolveType = ({ type = 'text', sensitive = false }, value: string) => { if (sensitive && value === MASKED_VALUE) { @@ -15,19 +15,19 @@ const resolveType = ({ type = 'text', sensitive = false }, value: string) => { const MASKED_VALUE = '*****'; -export interface IAddonParameterProps { +export interface IIntegrationParameterProps { parametersErrors: Record; definition: IAddonProviderParams; setParameterValue: (param: string) => ChangeEventHandler; config: IAddonConfig; } -export const AddonParameter = ({ +export const IntegrationParameter = ({ definition, config, parametersErrors, setParameterValue, -}: IAddonParameterProps) => { +}: IIntegrationParameterProps) => { const value = config.parameters[definition.name] || ''; const type = resolveType(definition, value); const error = parametersErrors[definition.name]; diff --git a/frontend/src/component/addons/AddonForm/AddonParameters/AddonParameters.tsx b/frontend/src/component/integrations/IntegrationForm/IntegrationParameters/IntegrationParameters.tsx similarity index 65% rename from frontend/src/component/addons/AddonForm/AddonParameters/AddonParameters.tsx rename to frontend/src/component/integrations/IntegrationForm/IntegrationParameters/IntegrationParameters.tsx index fb62c6894fde..646b45ab8453 100644 --- a/frontend/src/component/addons/AddonForm/AddonParameters/AddonParameters.tsx +++ b/frontend/src/component/integrations/IntegrationForm/IntegrationParameters/IntegrationParameters.tsx @@ -1,26 +1,26 @@ import React from 'react'; import { IAddonProvider } from 'interfaces/addons'; import { - AddonParameter, - IAddonParameterProps, -} from './AddonParameter/AddonParameter'; -import { StyledTitle } from '../AddonForm.styles'; + IntegrationParameter, + IIntegrationParameterProps, +} from './IntegrationParameter/IntegrationParameter'; +import { StyledTitle } from '../IntegrationForm.styles'; -interface IAddonParametersProps { +interface IIntegrationParametersProps { provider?: IAddonProvider; - parametersErrors: IAddonParameterProps['parametersErrors']; + parametersErrors: IIntegrationParameterProps['parametersErrors']; editMode: boolean; - setParameterValue: IAddonParameterProps['setParameterValue']; - config: IAddonParameterProps['config']; + setParameterValue: IIntegrationParameterProps['setParameterValue']; + config: IIntegrationParameterProps['config']; } -export const AddonParameters = ({ +export const IntegrationParameters = ({ provider, config, parametersErrors, setParameterValue, editMode, -}: IAddonParametersProps) => { +}: IIntegrationParametersProps) => { if (!provider) return null; return ( @@ -33,7 +33,7 @@ export const AddonParameters = ({

) : null} {provider.parameters.map(parameter => ( - { return ( - } /> + } + /> ); }, }, @@ -79,7 +85,7 @@ export const AvailableAddons = ({ accessor: 'name', width: '90%', Cell: ({ row: { original } }: any) => ( - + ), sortType: 'alphanumeric', }, @@ -88,7 +94,7 @@ export const AvailableAddons = ({ align: 'center', Cell: ({ row: { original } }: any) => ( - + ), width: 150, diff --git a/frontend/src/component/addons/AddonList/AvailableAddons/ConfigureAddonButton/ConfigureAddonButton.tsx b/frontend/src/component/integrations/IntegrationList/AvailableAddons/ConfigureAddonButton/ConfigureAddonsButton.tsx similarity index 77% rename from frontend/src/component/addons/AddonList/AvailableAddons/ConfigureAddonButton/ConfigureAddonButton.tsx rename to frontend/src/component/integrations/IntegrationList/AvailableAddons/ConfigureAddonButton/ConfigureAddonsButton.tsx index dfe10193c3b9..bc165e9059f3 100644 --- a/frontend/src/component/addons/AddonList/AvailableAddons/ConfigureAddonButton/ConfigureAddonButton.tsx +++ b/frontend/src/component/integrations/IntegrationList/AvailableAddons/ConfigureAddonButton/ConfigureAddonsButton.tsx @@ -3,13 +3,16 @@ import { CREATE_ADDON } from 'component/providers/AccessProvider/permissions'; import { IAddonProvider } from 'interfaces/addons'; import { useNavigate } from 'react-router-dom'; -interface IConfigureAddonButtonProps { +interface IConfigureAddonsButtonProps { provider: IAddonProvider; } -export const ConfigureAddonButton = ({ +/** + * @deprecated Remove when integrationsRework flag is removed + */ +export const ConfigureAddonsButton = ({ provider, -}: IConfigureAddonButtonProps) => { +}: IConfigureAddonsButtonProps) => { const navigate = useNavigate(); return ( diff --git a/frontend/src/component/integrations/IntegrationList/AvailableIntegrations/AvailableIntegrations.tsx b/frontend/src/component/integrations/IntegrationList/AvailableIntegrations/AvailableIntegrations.tsx new file mode 100644 index 000000000000..970f5991c48b --- /dev/null +++ b/frontend/src/component/integrations/IntegrationList/AvailableIntegrations/AvailableIntegrations.tsx @@ -0,0 +1,8 @@ +import { PageContent } from 'component/common/PageContent/PageContent'; +import { VFC } from 'react'; + +interface IAvailableIntegrationsProps {} + +export const AvailableIntegrations: VFC = () => { + return Available integrations; +}; diff --git a/frontend/src/component/addons/AddonList/ConfiguredAddons/ConfiguredAddons.tsx b/frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddons.tsx similarity index 95% rename from frontend/src/component/addons/AddonList/ConfiguredAddons/ConfiguredAddons.tsx rename to frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddons.tsx index edfff5c0d903..54198c7b4c90 100644 --- a/frontend/src/component/addons/AddonList/ConfiguredAddons/ConfiguredAddons.tsx +++ b/frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddons.tsx @@ -13,10 +13,13 @@ 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 { AddonIcon } from '../AddonIcon/AddonIcon'; +import { IntegrationIcon } from '../IntegrationIcon/IntegrationIcon'; import { ConfiguredAddonsActionsCell } from './ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell'; -import { AddonNameCell } from '../AddonNameCell/AddonNameCell'; +import { IntegrationNameCell } from '../IntegrationNameCell/IntegrationNameCell'; +/** + * @deprecated Remove when integrationsRework flag is removed + */ export const ConfiguredAddons = () => { const { refetchAddons, addons, providers, loading } = useAddons(); const { updateAddon, removeAddon } = useAddonsApi(); @@ -73,7 +76,9 @@ export const ConfiguredAddons = () => { original: { provider }, }, }: any) => ( - } /> + } + /> ), disableSortBy: true, }, @@ -86,7 +91,7 @@ export const ConfiguredAddons = () => { original: { provider, description }, }, }: any) => ( - name === provider diff --git a/frontend/src/component/addons/AddonList/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx b/frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx similarity index 97% rename from frontend/src/component/addons/AddonList/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx rename to frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx index f2a9e21136c1..2d3374818b1a 100644 --- a/frontend/src/component/addons/AddonList/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx +++ b/frontend/src/component/integrations/IntegrationList/ConfiguredAddons/ConfiguredAddonsActionCell/ConfiguredAddonsActionsCell.tsx @@ -18,6 +18,9 @@ interface IConfiguredAddonsActionsCellProps { setDeletedAddon: React.Dispatch>; } +/** + * @deprecated Remove when integrationsRework flag is removed + */ export const ConfiguredAddonsActionsCell = ({ toggleAddon, setShowDelete, diff --git a/frontend/src/component/addons/AddonList/AddonIcon/AddonIcon.tsx b/frontend/src/component/integrations/IntegrationList/IntegrationIcon/IntegrationIcon.tsx similarity index 94% rename from frontend/src/component/addons/AddonList/AddonIcon/AddonIcon.tsx rename to frontend/src/component/integrations/IntegrationList/IntegrationIcon/IntegrationIcon.tsx index 427a6ca7ba76..ee2e6f1e2c3d 100644 --- a/frontend/src/component/addons/AddonList/AddonIcon/AddonIcon.tsx +++ b/frontend/src/component/integrations/IntegrationList/IntegrationIcon/IntegrationIcon.tsx @@ -14,11 +14,11 @@ const style: React.CSSProperties = { marginRight: '16px', }; -interface IAddonIconProps { +interface IIntegrationIconProps { name: string; } -export const AddonIcon = ({ name }: IAddonIconProps) => { +export const IntegrationIcon = ({ name }: IIntegrationIconProps) => { switch (name) { case 'slack': case 'slack-app': diff --git a/frontend/src/component/integrations/IntegrationList/IntegrationList.tsx b/frontend/src/component/integrations/IntegrationList/IntegrationList.tsx new file mode 100644 index 000000000000..addbad3734e4 --- /dev/null +++ b/frontend/src/component/integrations/IntegrationList/IntegrationList.tsx @@ -0,0 +1,28 @@ +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'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; +import { AvailableIntegrations } from './AvailableIntegrations/AvailableIntegrations'; + +export const IntegrationList = () => { + const { providers, addons, loading } = useAddons(); + const { uiConfig } = useUiConfig(); + const integrationsRework = uiConfig?.flags?.integrationsRework || false; + + return ( + <> + 0} + show={} + /> + } + elseShow={ + + } + /> + + ); +}; diff --git a/frontend/src/component/addons/AddonList/AddonNameCell/AddonNameCell.tsx b/frontend/src/component/integrations/IntegrationList/IntegrationNameCell/IntegrationNameCell.tsx similarity index 84% rename from frontend/src/component/addons/AddonList/AddonNameCell/AddonNameCell.tsx rename to frontend/src/component/integrations/IntegrationList/IntegrationNameCell/IntegrationNameCell.tsx index 74ab375c0f16..4d2bb0aeacb5 100644 --- a/frontend/src/component/addons/AddonList/AddonNameCell/AddonNameCell.tsx +++ b/frontend/src/component/integrations/IntegrationList/IntegrationNameCell/IntegrationNameCell.tsx @@ -10,14 +10,19 @@ const StyledBadge = styled(Badge)(({ theme }) => ({ marginLeft: theme.spacing(1), })); -interface IAddonNameCellProps { +interface IIntegrationNameCellProps { provider: Pick< IAddonProvider, 'displayName' | 'description' | 'deprecated' >; } -export const AddonNameCell = ({ provider }: IAddonNameCellProps) => ( +/** + * @deprecated Remove when integrationsRework flag is removed + */ +export const IntegrationNameCell = ({ + provider, +}: IIntegrationNameCellProps) => ( ; @@ -133,6 +134,10 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_CUSTOM_ROOT_ROLES_KILL_SWITCH, false, ), + integrationsRework: parseEnvVarBoolean( + process.env.UNLEASH_INTEGRATIONS, + false, + ), }; export const defaultExperimentalOptions: IExperimentalOptions = { diff --git a/website/README.md b/website/README.md index 7c71f1eeb00f..7eee45919dbc 100644 --- a/website/README.md +++ b/website/README.md @@ -13,6 +13,7 @@ yarn install ```console yarn generate ``` + Generate the Open API docs that live at Reference documentation > APIs > OpenAPI ## Local Development @@ -21,7 +22,7 @@ Generate the Open API docs that live at Reference documentation > APIs > OpenAPI yarn start ``` - Start a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. +Start a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. ## Build