From beed978437bec07be4d53fb205a0d60afc22eb26 Mon Sep 17 00:00:00 2001 From: Joshua Jones Date: Fri, 7 Oct 2022 17:34:12 -0700 Subject: [PATCH 1/2] Add fixes for deleting application optimistically and preventing saves in controls dialog --- src/mocks/handlers.js | 7 ++ src/mocks/resolvers/applications.js | 74 +++++++++++++++++++ .../access-request-dialog.tsx | 10 +-- .../components/access-request/edit-dialog.tsx | 22 +++++- .../pages/devportal/applications/index.tsx | 72 +++++++++++------- 5 files changed, 150 insertions(+), 35 deletions(-) create mode 100644 src/mocks/resolvers/applications.js diff --git a/src/mocks/handlers.js b/src/mocks/handlers.js index d82348bf2..fe42c8629 100644 --- a/src/mocks/handlers.js +++ b/src/mocks/handlers.js @@ -1,6 +1,10 @@ import { graphql, rest } from 'msw'; import { harley, mark } from './resolvers/personas'; +import { + allApplicationsHandler, + removeApplicationHandler, +} from './resolvers/applications'; import { allProductsByNamespaceHandler, accessRequestAuthHandler, @@ -116,6 +120,9 @@ export const handlers = [ 'GetConsumerProductsAndEnvironments', allProductsByNamespaceHandler ), + // Applications + keystone.query('MyApplications', allApplicationsHandler), + keystone.mutation('Remove', removeApplicationHandler), // Service accounts keystone.query('GetAllServiceAccounts', getAllServiceAccountsHandler), keystone.mutation('CreateServiceAccount', createServiceAccountHandler), diff --git a/src/mocks/resolvers/applications.js b/src/mocks/resolvers/applications.js new file mode 100644 index 000000000..11703976b --- /dev/null +++ b/src/mocks/resolvers/applications.js @@ -0,0 +1,74 @@ +const applications = new Map([ + [ + 'app1', + { + id: 'app1', + appId: 'ABC123', + description: '', + name: 'Demo App', + owner: { + name: 'Mark Smith', + }, + }, + ], + [ + 'app2', + { + id: 'app2', + appId: 'ABC123', + description: '', + name: 'Shoppers Drug Mart 112', + owner: { + name: 'Mark Smith', + }, + }, + ], + [ + 'app3error', + { + id: 'app3error', + appId: 'ABC123', + description: '', + name: 'Easy Mart Store 123', + owner: { + name: 'Carter Schleifer', + }, + }, + ], +]); + +export const allApplicationsHandler = (req, res, ctx) => { + return res( + ctx.data({ + myApplications: Array.from(applications.values()), + allTemporaryIdentities: [ + { + id: 'u1', + userId: '1', + }, + ], + }) + ); +}; + +export const removeApplicationHandler = (req, res, ctx) => { + const { id } = req.variables; + + if (id === 'app3error') { + return res( + ctx.data({ + errors: [ + { message: 'You do not have permission to delete this application' }, + ], + }) + ); + } + + const application = applications.get(id); + applications.delete(id); + return res( + ctx.data({ + deleteApplication: application, + }) + ); +}; diff --git a/src/nextapp/components/access-request-form/access-request-dialog.tsx b/src/nextapp/components/access-request-form/access-request-dialog.tsx index 362441f83..6fc8430da 100644 --- a/src/nextapp/components/access-request-form/access-request-dialog.tsx +++ b/src/nextapp/components/access-request-form/access-request-dialog.tsx @@ -71,11 +71,11 @@ const AccessRequestDialog: React.FC = ({ const buttonProps = !isInline ? {} : { - fontWeight: 'normal', - fontSize: 'inherit', - color: 'bc-link', - textDecor: 'underline', - }; + fontWeight: 'normal', + fontSize: 'inherit', + color: 'bc-link', + textDecor: 'underline', + }; // Events const handleAccessSubmit = React.useCallback( diff --git a/src/nextapp/components/access-request/edit-dialog.tsx b/src/nextapp/components/access-request/edit-dialog.tsx index fe2774b03..d4fbd9a1b 100644 --- a/src/nextapp/components/access-request/edit-dialog.tsx +++ b/src/nextapp/components/access-request/edit-dialog.tsx @@ -19,11 +19,12 @@ import { Grid, useToast, Flex, + Alert, + AlertDescription, + AlertIcon, } from '@chakra-ui/react'; import { ConsumerPlugin, - GatewayPlugin, - GatewayPluginCreateInput, } from '@/shared/types/query.types'; import EnvironmentTag from '@/components/environment-tag'; import format from 'date-fns/format'; @@ -56,6 +57,7 @@ const ConsumerEditDialog: React.FC = ({ { suspense: false, enabled: isOpen } ); const [tabIndex, setTabIndex] = React.useState(0); + const [hasUnsavedChanges, setHasUnsavedChanges] = React.useState(false); const restrictions = React.useState(() => { return ( data?.getConsumerProdEnvAccess.plugins @@ -93,6 +95,7 @@ const ConsumerEditDialog: React.FC = ({ const handleClose = () => { const [, setRestrictions] = restrictions; const [, setRateLimits] = rateLimits; + setHasUnsavedChanges(false); setRestrictions( data?.getConsumerProdEnvAccess.plugins .filter((p) => p.name === 'ip-restriction') @@ -124,10 +127,16 @@ const ConsumerEditDialog: React.FC = ({ const data = { plugins: [...restrictsionsData, ...rateLimitsData], }; - const authorizationForm = ref?.current.querySelector( 'form[name="authorizationForm"]' ); + const ipRestrictionForm = new FormData(ref?.current.querySelector('form[name="ipRestrictionsForm"]')); + + if (ipRestrictionForm.get('allow') !== '[]') { + setHasUnsavedChanges(true); + return false; + } + if (authorizationForm) { const authorizationFormData = new FormData(authorizationForm); const defaultClientScopes = authorizationFormData.getAll( @@ -153,6 +162,7 @@ const ConsumerEditDialog: React.FC = ({ client.invalidateQueries(['consumerEdit', prodEnvId, consumerId]); onClose(); setTabIndex(0); + setHasUnsavedChanges(false); } catch (err) { toast({ title: 'Request save failed', @@ -249,6 +259,12 @@ const ConsumerEditDialog: React.FC = ({ {isSuccess && ( + {hasUnsavedChanges && ( + + + You have an unapplied IP Restrictions control. + + )}