Skip to content

Commit

Permalink
Add application edit dialog (#678)
Browse files Browse the repository at this point in the history
* Add application edit dialog

* Fix GraphQL ID type
  • Loading branch information
Jonesy committed Jan 6, 2023
1 parent 31cf7f0 commit 15073be
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

query GET_APPLICATION_SERVICES($appId: String!) {
query GetApplicationServices($appId: String!) {
myServiceAccesses(where: { application: { appId: $appId } }) {
id
name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

mutation UpdateApplication($id: ID!, $data: ApplicationUpdateInput) {
updateApplication(id: $id, data: $data) {
id
}
}
7 changes: 5 additions & 2 deletions src/mocks/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import {
import {
allApplicationsHandler,
createApplicationHandler,
getApplicationServicesHandler,
removeApplicationHandler,
updateApplicationHandler,
} from './resolvers/applications';
import {
allProductsByNamespaceHandler,
Expand Down Expand Up @@ -168,8 +170,7 @@ export const handlers = [
return res(
ctx.status(200),
ctx.json({
user: null,
// user: { ...mark, namespace },
user: { ...personas.mark, namespace },
})
);
}),
Expand Down Expand Up @@ -238,7 +239,9 @@ export const handlers = [
keystone.mutation('UpdateEnvironment', updateEnvironmentHandler),
// Applications
keystone.query('MyApplications', allApplicationsHandler),
keystone.query('GetApplicationServices', getApplicationServicesHandler),
keystone.mutation('AddApplication', createApplicationHandler),
keystone.mutation('UpdateApplication', updateApplicationHandler),
keystone.mutation('RemoveApplication', removeApplicationHandler),
// Services
keystone.query('GetServices', allServicesHandler),
Expand Down
49 changes: 49 additions & 0 deletions src/mocks/resolvers/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,37 @@ export const allApplicationsHandler = (req, res, ctx) => {
);
};

export const getApplicationServicesHandler = (req, res, ctx) => {
if (req.variables.appId !== 'ABC123') {
return res(
ctx.data({
myServiceAccesses: [],
})
);
}
return res(
ctx.data({
myServiceAccesses: [
{
id: 'sa1',
name: '123123-123ADSFSD',
active: true,
application: {
name: 'Demo App',
},
productEnvironment: {
id: 'pe1',
name: 'dev',
product: {
name: 'My Pharma API',
},
},
},
],
})
);
};

export const createApplicationHandler = (req, res, ctx) => {
if (req.variables.name === 'error') {
return res(
Expand All @@ -75,6 +106,24 @@ export const createApplicationHandler = (req, res, ctx) => {
);
};

export const updateApplicationHandler = (req, res, ctx) => {
const { id, data } = req.variables;
const cached = applications.get(id);

applications.set(id, {
...cached,
...data,
});

return res(
ctx.data({
updateApplication: {
id,
},
})
);
};

export const removeApplicationHandler = (req, res, ctx) => {
const { id } = req.variables;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const ApplicationServices: React.FC<ApplicationServicesProps> = ({ appId }) => {
export default ApplicationServices;

const query = gql`
query GET_APPLICATION_SERVICES($appId: String!) {
query GetApplicationServices($appId: String!) {
myServiceAccesses(where: { application: { appId: $appId } }) {
id
name
Expand Down
131 changes: 131 additions & 0 deletions src/nextapp/components/edit-application/edit-application.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import * as React from 'react';
import {
Button,
ButtonGroup,
FormControl,
FormHelperText,
FormLabel,
Input,
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Textarea,
useToast,
} from '@chakra-ui/react';
import { useQueryClient } from 'react-query';
import { useApiMutation } from '@/shared/services/api';
import { gql } from 'graphql-request';
import { Application, Mutation } from '@/shared/types/query.types';

interface EditApplicationProps {
data?: Application;
open: boolean;
onClose: () => void;
refreshQueryKey: string;
}

const EditApplication: React.FC<EditApplicationProps> = ({
data,
open,
onClose,
refreshQueryKey,
}) => {
const toast = useToast();
const queryClient = useQueryClient();
const applicationMutation = useApiMutation(mutation);
const form = React.useRef<HTMLFormElement>();
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
createApplication();
};
const createApplication = async () => {
if (form.current) {
try {
const formData = new FormData(form.current);

if (form.current.checkValidity()) {
const name = formData.get('name') as string;
const description = formData.get('description') as string;
await applicationMutation.mutateAsync({
id: data?.id,
data: { name, description },
});
toast({
title: `${name} updated`,
status: 'success',
isClosable: true,
});
queryClient.invalidateQueries(refreshQueryKey);
onClose();
}
} catch (err) {
toast({
title: 'Application update failed',
description: err,
status: 'error',
isClosable: true,
});
}
}
};
const submitForm = React.useCallback(() => form.current?.requestSubmit(), []);

return (
<Modal isOpen={open} onClose={onClose}>
<ModalOverlay />
<ModalContent borderRadius="4px">
<ModalHeader>Edit Application</ModalHeader>
<ModalBody>
<form ref={form} onSubmit={onSubmit}>
<FormControl isRequired mb={8}>
<FormLabel>Application Name</FormLabel>
<Input
defaultValue={data?.name}
name="name"
variant="bc-input"
data-testid="edit-app-name-input"
/>
</FormControl>
<FormControl>
<FormLabel>Description (Optional)</FormLabel>
<FormHelperText>What does your application do?</FormHelperText>
<Textarea
defaultValue={data?.description}
name="description"
variant="bc-input"
data-testid="edit-app-description-input"
/>
</FormControl>
</form>
</ModalBody>
<ModalFooter>
<ButtonGroup>
<Button
onClick={onClose}
variant="secondary"
data-testid="edit-app-cancel-btn"
>
Cancel
</Button>
<Button onClick={submitForm} data-testid="edit-app-submit-btn">
Update
</Button>
</ButtonGroup>
</ModalFooter>
</ModalContent>
</Modal>
);
};

export default EditApplication;

const mutation = gql`
mutation UpdateApplication($id: ID!, $data: ApplicationUpdateInput) {
updateApplication(id: $id, data: $data) {
id
}
}
`;
1 change: 1 addition & 0 deletions src/nextapp/components/edit-application/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './edit-application';
20 changes: 20 additions & 0 deletions src/nextapp/pages/devportal/applications/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
GridItem,
Flex,
} from '@chakra-ui/react';
import EditApplication from '@/components/edit-application';
import get from 'lodash/get';
import Head from 'next/head';
import PageHeader from '@/components/page-header';
Expand Down Expand Up @@ -58,6 +59,7 @@ const ApplicationsPage: React.FC<
InferGetServerSidePropsType<typeof getServerSideProps>
> = ({ queryKey }) => {
const toast = useToast();
const [editing, setEditing] = React.useState<Application | null>(null);
const [openId, setOpenId] = React.useState<string | null>();
const queryClient = useQueryClient();
const { data } = useApi(
Expand Down Expand Up @@ -93,6 +95,12 @@ const ApplicationsPage: React.FC<
queryClient.refetchQueries(queryKey);
},
});
const handleEdit = (data: Application) => () => {
setEditing(data);
};
const handleCloseEditDialog = () => {
setEditing(null);
};
const handleDelete = (id: string) => async () => {
try {
if (openId === id) {
Expand Down Expand Up @@ -133,6 +141,12 @@ const ApplicationsPage: React.FC<
<Head>
<title>API Program Services | Applications</title>
</Head>
<EditApplication
data={editing}
open={Boolean(editing)}
onClose={handleCloseEditDialog}
refreshQueryKey={queryKey}
/>
<Container maxW="6xl">
{data?.allApplications?.length === 0 && (
<Alert status="warning">
Expand Down Expand Up @@ -166,6 +180,12 @@ const ApplicationsPage: React.FC<
aria-label={`${d.name} actions menu button`}
placement="bottom-end"
>
<MenuItem
data-testid="edit-application-btn"
onClick={handleEdit(d)}
>
Edit Application
</MenuItem>
<MenuItem
color="red.500"
data-testid="delete-application-btn"
Expand Down

0 comments on commit 15073be

Please sign in to comment.