Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Migrate orgUploadToken to ts #3602

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import Icon from 'ui/Icon'

import useGenerateOrgUploadToken from './useGenerateOrgUploadToken'

interface URLParams {
owner: string
}

function GenerateOrgUploadToken() {
const { owner } = useParams()
const { owner } = useParams<URLParams>()
const { regenerateToken, isLoading } = useGenerateOrgUploadToken()
const isAdmin = useIsCurrentUserAnAdmin({ owner })

Expand All @@ -33,11 +37,12 @@ function GenerateOrgUploadToken() {
</div>
{!isAdmin && (
<div className="flex gap-1">
<Icon name="information-circle" size="sm" />
<Icon name="informationCircle" size="sm" />
Only organization admins can regenerate this token.
</div>
)}
<div className="flex gap-1">
{/* @ts-expect-error error until convert A to ts */}
<A to={{ pageName: 'orgUploadTokenDoc' }}>Learn more</A>
<p>how to generate and use the global upload token.</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
})

const wrapper = ({ children }) => (
const wrapper: React.FC<React.PropsWithChildren> = ({ children }) => (
<MemoryRouter initialEntries={['/account/gh/codecov/orgUploadToken']}>
<QueryClientProvider client={queryClient}>
<Route path="/account/:provider/:owner/orgUploadToken">
Expand All @@ -52,20 +52,24 @@
server.close()
})

type SetupOptions = {
orgUploadToken?: string | null
error?: string | null
isAdmin?: boolean
}

describe('OrgUploadToken', () => {
function setup(
{ orgUploadToken = null, error = null, isAdmin = true } = {
orgUploadToken: null,
error: null,
isAdmin: true,
}
) {
function setup({
orgUploadToken = null,
error = null,
isAdmin = true,
}: SetupOptions = {}) {
const user = userEvent.setup()
const mutate = vi.fn()
const addNotification = vi.fn()
useFlags.mockReturnValue({ tokenlessSection: true })
vi.mocked(useFlags).mockReturnValue({ tokenlessSection: true })

useAddNotification.mockReturnValue(addNotification)
vi.mocked(useAddNotification).mockReturnValue(addNotification)

server.use(
graphql.query('DetailOwner', () => {
Expand Down Expand Up @@ -203,10 +207,10 @@

await user.click(genBtn)

rerender()
rerender(<OrgUploadToken />)

await waitFor(() =>
expect(addNotification).toHaveBeenCalledWith({

Check failure on line 213 in src/pages/AccountSettings/tabs/OrgUploadToken/OrgUploadToken.test.tsx

View workflow job for this annotation

GitHub Actions / Test Runner #0 - Vitest

src/pages/AccountSettings/tabs/OrgUploadToken/OrgUploadToken.test.tsx > OrgUploadToken > when user clicks on Generate button > when mutation is not successful > adds an error notification

AssertionError: expected "spy" to be called with arguments: [ { type: 'error', …(1) } ] Received: 1st spy call: Array [ Object { - "text": "Authentication Error", - "type": "error", + "text": "Global upload token generated.", + "type": "success", }, ] Number of calls: 1 Ignored nodes: comments, script, style <html> <head /> <body> <div> <div class="flex flex-col gap-4 lg:w-3/4" > <div class="flex gap-1" > <h1 class="text-lg font-semibold" > Global upload token </h1> <div class="mt-2 text-xs" > <a class=" font-sans cursor-pointer hover:underline focus:ring-2 text-ds-blue-default inline-flex items-center gap-1" data-cy="orgUploadTokenDoc" data-marketing="orgUploadTokenDoc" href="https://docs.codecov.com/docs/codecov-uploader#organization-upload-token" target="_blank" > learn more <span class="text-ds-gray-quinary" > <svg class="w-4 h-4" data-icon="" data-testid="" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" > <path d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" /> </svg> </span> </a> </div> </div> <hr /> <div class="flex flex-col gap-6" > TokenlessSection <div class="bg-ds-blue-nonary text-ds-gray-octonary p-4 dark:bg-opacity-20 border-l-4 border-ds-blue-quinary" > <h2 class="font-semibold" > Sensitive credential </h2> <p> This token allows for valid upload of coverage reports to Codecov for any repository in your organization. You should treat it as a sensitive credential and not commit it to source control. </p> </div> <div class="border-2 border-ds-gray-primary p-4" > <div class="flex flex-col gap-6" > <div class="flex flex-row" > <p> Generating a global token allows you to apply the same upload token to all of your repos. This can make configuration easier and more streamlined. </p> <div> <button class=" flex items-center gap-1 rounded py-1 px-4 transition-colors duration-150 motion-reduce:transition-none focus:outline-none focus:ring disabled:cursor-not-allowed disabled:text-ds-gray-quaternary disabled:border-ds-gray-tertiary disabled:bg-ds-gray-primary justify-center font-semibold text-white bg-ds-blue-darker dark:bg-ds-blue-nonary border-ds-blue-quinary border-solid border shadow hover:bg-ds-blue-quinary " data-cy="generate-org-upload-token" data-marketing="generate-org-upload-token" data-testid="generate-org-upload-token" > Generate </button> </div> </div> <div class="flex gap-1" > <a class=" font-sans cursor-pointer hover:underline focus:ring-2 text-ds-blue-default inline-flex items-center gap-1" data-cy="orgUploadTokenDoc" data-marketing="orgUploadTokenDoc" href="https://docs.codecov.com/docs/codecov
type: 'error',
text: 'Authentication Error',
})
Expand Down Expand Up @@ -299,7 +303,7 @@

const show = await screen.findAllByText('Show')
expect(show[1]).toBeInTheDocument()
await user.click(show[1])
await user.click(show[1]!)

const token1 = await screen.findByText('CODECOV_TOKEN=token')
expect(token1).toBeInTheDocument()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ import RegenerateOrgUploadToken from './RegenerateOrgUploadToken'

const TokenlessSection = lazy(() => import('./TokenlessSection'))

interface URLParams {
provider: string
owner: string
}

function OrgUploadToken() {
const { provider, owner } = useParams()
const { provider, owner } = useParams<URLParams>()
const { data: orgUploadToken } = useOrgUploadToken({ provider, owner })
const { tokenlessSection: tokenlessSectionFlag } = useFlags({
tokenlessSection: false,
Expand All @@ -23,6 +28,7 @@ function OrgUploadToken() {
<div className="flex gap-1">
<h1 className="text-lg font-semibold">Global upload token</h1>
<div className="mt-2 text-xs">
{/* @ts-expect-error error until we can convert A component to ts */}
<A to={{ pageName: 'orgUploadTokenDoc' }}>learn more</A>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import PropTypes from 'prop-types'
import { useState } from 'react'
import { useParams } from 'react-router-dom'

Expand All @@ -15,9 +14,11 @@ const TokenFormatEnum = Object.freeze({
SECOND_FORMAT: 'CODECOV_TOKEN=',
})

const UploadToken = ({ token, format }) => {
const UploadToken = ({ token, format }: { token: string; format: string }) => {
const [hideClipboard, setHideClipboard] = useState(true)
const encodedToken = hideClipboard && format + token.replace(/[^w-]|/g, 'x')
const encodedToken = hideClipboard
? format + token.replace(/[^w-]|/g, 'x')
: undefined

return (
<div className="flex items-center gap-2">
Expand All @@ -28,7 +29,7 @@ const UploadToken = ({ token, format }) => {
data-testid="hide-token"
>
<Icon
name={hideClipboard ? 'eye' : 'eye-off'}
name={hideClipboard ? 'eye' : 'eyeOff'}
size="sm"
variant="solid"
/>
Expand All @@ -40,13 +41,17 @@ const UploadToken = ({ token, format }) => {
)
}

UploadToken.propTypes = {
token: PropTypes.string.isRequired,
format: PropTypes.string.isRequired,
interface URLParams {
provider: string
owner: string
}

function RegenerateOrgUploadToken({ orgUploadToken }) {
const { owner } = useParams()
function RegenerateOrgUploadToken({
orgUploadToken,
}: {
orgUploadToken: string
}) {
const { owner } = useParams<URLParams>()
const { regenerateToken, isLoading } = useGenerateOrgUploadToken()
const [showModal, setShowModal] = useState(false)
const isAdmin = useIsCurrentUserAnAdmin({ owner })
Expand All @@ -66,7 +71,7 @@ function RegenerateOrgUploadToken({ orgUploadToken }) {
/>
{!isAdmin && (
<div className="flex gap-1">
<Icon name="information-circle" size="sm" />
<Icon name="informationCircle" size="sm" />
Only organization admins can regenerate this token.
</div>
)}
Expand All @@ -82,7 +87,7 @@ function RegenerateOrgUploadToken({ orgUploadToken }) {
{showModal && (
<RegenerateTokenModal
closeModal={() => setShowModal(false)}
regenerateToken={regenerateToken}
regenerateToken={() => Promise.resolve(regenerateToken())}
isLoading={isLoading}
/>
)}
Expand All @@ -91,8 +96,4 @@ function RegenerateOrgUploadToken({ orgUploadToken }) {
)
}

RegenerateOrgUploadToken.propTypes = {
orgUploadToken: PropTypes.string.isRequired,
}

export default RegenerateOrgUploadToken
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import PropTypes from 'prop-types'

import Button from 'ui/Button'
import Modal from 'ui/Modal'

const RegenerateTokenModal = ({ closeModal, regenerateToken, isLoading }) => (
const RegenerateTokenModal = ({
closeModal,
regenerateToken,
isLoading,
}: {
closeModal: () => void
regenerateToken: () => Promise<void>
isLoading: boolean
}) => (
<Modal
isOpen={true}
onClose={closeModal}
Expand Down Expand Up @@ -45,10 +51,4 @@ const RegenerateTokenModal = ({ closeModal, regenerateToken, isLoading }) => (
/>
)

RegenerateTokenModal.propTypes = {
closeModal: PropTypes.func.isRequired,
regenerateToken: PropTypes.func.isRequired,
isLoading: PropTypes.bool.isRequired,
}

export default RegenerateTokenModal
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export default function useGenerateOrgUploadToken() {
data: res,
...rest
} = useRegenerateOrgUploadToken({
onSuccess: (data) => {
const errString = data?.regenerateOrgUploadToken?.error?.__typename
onSuccess: () => {
const errString = res?.regenerateOrgUploadToken?.error?.__typename

if (errString) {
addToast({
Expand Down
Loading