From c4c60277406f210c741a05fa8bd683ff11b0484f Mon Sep 17 00:00:00 2001 From: Jake Laderman Date: Fri, 23 Aug 2024 18:39:50 -0400 Subject: [PATCH] add actions menu with delete option to scm webhooks (#1330) --- assets/package.json | 2 +- .../components/pr/scm/ScmWebhooksColumns.tsx | 145 +++++++++++++++--- assets/src/components/utils/Confirm.tsx | 99 ++++++------ assets/src/generated/graphql.ts | 41 +++++ assets/src/graph/automation.graphql | 6 + assets/yarn.lock | 10 +- 6 files changed, 226 insertions(+), 77 deletions(-) diff --git a/assets/package.json b/assets/package.json index eae8a3d601..dbda857c67 100644 --- a/assets/package.json +++ b/assets/package.json @@ -46,7 +46,7 @@ "@nivo/pie": "0.83.0", "@nivo/radial-bar": "0.83.0", "@nivo/tooltip": "0.83.0", - "@pluralsh/design-system": "3.67", + "@pluralsh/design-system": "3.67.1", "@react-hooks-library/core": "0.6.0", "@saas-ui/use-hotkeys": "1.1.3", "@tanstack/react-virtual": "3.0.1", diff --git a/assets/src/components/pr/scm/ScmWebhooksColumns.tsx b/assets/src/components/pr/scm/ScmWebhooksColumns.tsx index 16b386bf66..98659475da 100644 --- a/assets/src/components/pr/scm/ScmWebhooksColumns.tsx +++ b/assets/src/components/pr/scm/ScmWebhooksColumns.tsx @@ -1,16 +1,32 @@ -import { ArrowTopRightIcon, Button } from '@pluralsh/design-system' +import { + ArrowTopRightIcon, + CopyIcon, + ListBoxItem, + TrashCanIcon, +} from '@pluralsh/design-system' import { createColumnHelper } from '@tanstack/react-table' import styled, { useTheme } from 'styled-components' -import { ScmType, ScmWebhookFragment } from 'generated/graphql' -import { Edge } from 'utils/graphql' +import { + ScmType, + ScmWebhookFragment, + ScmWebhooksDocument, + useDeleteScmWebhookMutation, +} from 'generated/graphql' +import { Edge, removeConnection, updateCache } from 'utils/graphql' -import { StopPropagation } from 'components/utils/StopPropagation' -import { TruncateStart } from 'components/utils/table/TruncateStart' -import { DateTimeCol } from 'components/utils/table/DateTimeCol' import CopyButton from 'components/utils/CopyButton' +import { DateTimeCol } from 'components/utils/table/DateTimeCol' +import { TruncateStart } from 'components/utils/table/TruncateStart' + +import { MoreMenu } from 'components/utils/MoreMenu' + +import { useState } from 'react' + +import { Confirm } from 'components/utils/Confirm' import { ScmTypeCell, scmTypeToLabel } from './PrScmConnectionsColumns' +import { SCM_WEBHOOKS_Q_VARS } from './ScmWebhooks' export const columnHelper = createColumnHelper>() @@ -84,31 +100,120 @@ function getWebhookUrl(scmWebhook: Nullable) { return undefined } +function DeleteScmWebhookModal({ + scmWebhook, + open, + onClose, +}: { + scmWebhook: ScmWebhookFragment + open: boolean + onClose: Nullable<() => void> +}) { + const theme = useTheme() + const [mutation, { loading, error }] = useDeleteScmWebhookMutation({ + variables: { id: scmWebhook.id }, + update: (cache, { data }) => + updateCache(cache, { + variables: SCM_WEBHOOKS_Q_VARS, + query: ScmWebhooksDocument, + update: (prev) => + removeConnection(prev, data?.deleteScmWebhook, 'scmWebhooks'), + }), + onCompleted: () => { + onClose?.() + }, + }) + + return ( + onClose?.()} + destructive + label="Delete" + loading={loading} + error={error} + open={open} + submit={() => mutation()} + title="Delete SCM connection" + text={ + <> + Are you sure you want to delete the{' '} + + “{scmWebhook.name}” + {' '} + webhook? + + } + /> + ) +} + +enum MenuItemKey { + Manage = 'manage', + Copy = 'copy', + Delete = 'delete', +} + export const ColActions = columnHelper.display({ id: 'actions', header: '', cell: function Cell({ row }) { + const theme = useTheme() + const [menuKey, setMenuKey] = useState() const scmWebhook = row.original.node - const url = getWebhookUrl(scmWebhook) + const url = scmWebhook?.url const scmName = scmWebhook?.type ? scmTypeToLabel[scmWebhook?.type] : '' - if (!url) { + if (!scmWebhook) { return null } + if (menuKey === MenuItemKey.Manage) { + window.open(getWebhookUrl(scmWebhook), '_blank', 'noopener,noreferrer') + setMenuKey('') + } + + if (menuKey === MenuItemKey.Copy) { + if (url) { + navigator.clipboard.writeText(url) + } + setMenuKey('') + } + return ( - - - + <> + setMenuKey(newKey)}> + } + label={ + + {`Manage${scmName ? ` on ${scmName}` : ''}`} + + } + textValue="Manage" + /> + } + label="Copy webhook URL" + textValue="Copy webhook URL" + /> + + } + label="Delete webhook" + textValue="Delete webhook" + /> + + {/* Modals */} + setMenuKey('')} + /> + ) }, }) diff --git a/assets/src/components/utils/Confirm.tsx b/assets/src/components/utils/Confirm.tsx index 72c72b6f16..4a687d55ba 100644 --- a/assets/src/components/utils/Confirm.tsx +++ b/assets/src/components/utils/Confirm.tsx @@ -6,7 +6,6 @@ import { GraphQLError } from 'graphql' import { GraphQLErrors } from '@apollo/client/errors' import { GqlError } from './Alert' -import { ModalMountTransition } from './ModalMountTransition' type ConfirmProps = { open: boolean @@ -40,57 +39,55 @@ export function Confirm({ const theme = useTheme() return ( - - - - - - } - > - {error && ( -
+
- )} -
- {text} + Cancel + + + + } + > + {error && ( +
+
- {extraContent} - - + )} +
+ {text} +
+ {extraContent} + ) } diff --git a/assets/src/generated/graphql.ts b/assets/src/generated/graphql.ts index 7f0dfd8bfa..016cf5b81a 100644 --- a/assets/src/generated/graphql.ts +++ b/assets/src/generated/graphql.ts @@ -8137,6 +8137,13 @@ export type CreateScmWebhookMutationVariables = Exact<{ export type CreateScmWebhookMutation = { __typename?: 'RootMutationType', createScmWebhook?: { __typename?: 'ScmWebhook', id: string, name: string, owner: string, type: ScmType, url: string, insertedAt?: string | null, updatedAt?: string | null } | null }; +export type DeleteScmWebhookMutationVariables = Exact<{ + id: Scalars['ID']['input']; +}>; + + +export type DeleteScmWebhookMutation = { __typename?: 'RootMutationType', deleteScmWebhook?: { __typename?: 'ScmWebhook', id: string, name: string, owner: string, type: ScmType, url: string, insertedAt?: string | null, updatedAt?: string | null } | null }; + export type CreateScmWebhookPointerMutationVariables = Exact<{ attributes: ScmWebhookAttributes; }>; @@ -13046,6 +13053,39 @@ export function useCreateScmWebhookMutation(baseOptions?: Apollo.MutationHookOpt export type CreateScmWebhookMutationHookResult = ReturnType; export type CreateScmWebhookMutationResult = Apollo.MutationResult; export type CreateScmWebhookMutationOptions = Apollo.BaseMutationOptions; +export const DeleteScmWebhookDocument = gql` + mutation DeleteScmWebhook($id: ID!) { + deleteScmWebhook(id: $id) { + ...ScmWebhook + } +} + ${ScmWebhookFragmentDoc}`; +export type DeleteScmWebhookMutationFn = Apollo.MutationFunction; + +/** + * __useDeleteScmWebhookMutation__ + * + * To run a mutation, you first call `useDeleteScmWebhookMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useDeleteScmWebhookMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [deleteScmWebhookMutation, { data, loading, error }] = useDeleteScmWebhookMutation({ + * variables: { + * id: // value for 'id' + * }, + * }); + */ +export function useDeleteScmWebhookMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(DeleteScmWebhookDocument, options); + } +export type DeleteScmWebhookMutationHookResult = ReturnType; +export type DeleteScmWebhookMutationResult = Apollo.MutationResult; +export type DeleteScmWebhookMutationOptions = Apollo.BaseMutationOptions; export const CreateScmWebhookPointerDocument = gql` mutation CreateScmWebhookPointer($attributes: ScmWebhookAttributes!) { createScmWebhookPointer(attributes: $attributes) { @@ -21081,6 +21121,7 @@ export const namedOperations = { DeleteScmConnection: 'DeleteScmConnection', SetupRenovate: 'SetupRenovate', CreateScmWebhook: 'CreateScmWebhook', + DeleteScmWebhook: 'DeleteScmWebhook', CreateScmWebhookPointer: 'CreateScmWebhookPointer', CreateObjectStore: 'CreateObjectStore', UpdateObjectStore: 'UpdateObjectStore', diff --git a/assets/src/graph/automation.graphql b/assets/src/graph/automation.graphql index a359fef471..8cf15203a7 100644 --- a/assets/src/graph/automation.graphql +++ b/assets/src/graph/automation.graphql @@ -165,6 +165,12 @@ mutation CreateScmWebhook($connectionId: ID!, $owner: String!) { } } +mutation DeleteScmWebhook($id: ID!) { + deleteScmWebhook(id: $id) { + ...ScmWebhook + } +} + mutation CreateScmWebhookPointer($attributes: ScmWebhookAttributes!) { createScmWebhookPointer(attributes: $attributes) { ...ScmWebhook diff --git a/assets/yarn.lock b/assets/yarn.lock index e0c1b8a8f6..c0771fca2a 100644 --- a/assets/yarn.lock +++ b/assets/yarn.lock @@ -4281,9 +4281,9 @@ __metadata: languageName: node linkType: hard -"@pluralsh/design-system@npm:3.67": - version: 3.67.0 - resolution: "@pluralsh/design-system@npm:3.67.0" +"@pluralsh/design-system@npm:3.67.1": + version: 3.67.1 + resolution: "@pluralsh/design-system@npm:3.67.1" dependencies: "@floating-ui/react-dom-interactions": 0.13.3 "@loomhq/loom-embed": 1.5.0 @@ -4331,7 +4331,7 @@ __metadata: react-dom: ">=18.3.1" react-transition-group: ">=4.4.5" styled-components: ">=5.3.11" - checksum: 763fdca1903a5d4802c0a092605c3ca2c52deaabd9c2220664730b2521e5439656ed224e9329dd27b6bfa178162eb7b89439f9ec6965f454dbcb31a9d445d318 + checksum: 077c1a7cdde3a6b3425540c872f82194edc9cd51fe05de0986a88da048c0327482234c98ee8a736322b0f3f3a5ccd397d4757073701daef7089af4285a94f107 languageName: node linkType: hard @@ -10168,7 +10168,7 @@ __metadata: "@nivo/pie": 0.83.0 "@nivo/radial-bar": 0.83.0 "@nivo/tooltip": 0.83.0 - "@pluralsh/design-system": 3.67 + "@pluralsh/design-system": 3.67.1 "@pluralsh/eslint-config-typescript": 2.5.150 "@pluralsh/stylelint-config": 2.0.10 "@react-hooks-library/core": 0.6.0