Skip to content

Commit 171eb5d

Browse files
committed
chore: API token UAT modifications
1 parent 666b73f commit 171eb5d

File tree

5 files changed

+82
-152
lines changed

5 files changed

+82
-152
lines changed

src/Pages/GlobalConfigurations/Authorization/APITokens/EditAPIToken.tsx

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ import { useHistory, useParams, useRouteMatch } from 'react-router-dom'
2020
import moment from 'moment'
2121

2222
import {
23+
Button,
2324
ButtonStyleType,
2425
ButtonVariantType,
25-
ButtonWithLoader,
2626
CustomInput,
27+
Icon,
2728
InfoBlock,
2829
noop,
2930
Progressing,
@@ -34,7 +35,6 @@ import {
3435
useMainContext,
3536
} from '@devtron-labs/devtron-fe-common-lib'
3637

37-
import { ReactComponent as Delete } from '../../../../assets/icons/ic-delete-interactive.svg'
3838
import { importComponentFromFELibrary } from '../../../../components/common'
3939
import { MomentDateFormat } from '../../../../config'
4040
import { API_COMPONENTS } from '../../../../config/constantMessaging'
@@ -167,21 +167,13 @@ const EditAPIToken = ({
167167
}
168168

169169
const getExpirationText = () => {
170-
if (isTokenExpired(editData.expireAtInMs)) {
171-
return (
172-
<span className="cr-5 fw-6">
173-
This token expired on&nbsp;
174-
{moment(editData.expireAtInMs).format(MomentDateFormat)}.
175-
</span>
176-
)
177-
}
178170
if (editData.expireAtInMs === 0) {
179-
return <span className="fw-6">This token has no expiration date.</span>
171+
return <span className="fw-6 cn-9">This token has no expiration date.</span>
180172
}
181173

182174
return (
183-
<span className="fw-6">
184-
This token expires on&nbsp;
175+
<span className="fw-6 cn-9">
176+
This token {isTokenExpired(editData.expireAtInMs) ? 'expired' : 'expires'} on&nbsp;
185177
{moment(editData.expireAtInMs).format(MomentDateFormat)}.
186178
</span>
187179
)
@@ -198,6 +190,7 @@ const EditAPIToken = ({
198190
variant: ButtonVariantType.text,
199191
style: ButtonStyleType.negative,
200192
}}
193+
variant={isTokenExpired(editData.expireAtInMs) ? 'error' : 'information'}
201194
/>
202195
)
203196

@@ -219,16 +212,16 @@ const EditAPIToken = ({
219212
{renderQuestionwithTippy()}
220213
</div>
221214
<div className="flex dc__align-end dc__content-end">
222-
<ButtonWithLoader
223-
rootClassName="flex cta override-button delete scr-5 h-32"
215+
<Button
224216
onClick={handleDeleteButton}
225217
disabled={loader}
226218
isLoading={false}
227219
dataTestId="delete-token"
228-
>
229-
<Delete className="icon-dim-16 mr-8" />
230-
<span>Delete</span>
231-
</ButtonWithLoader>
220+
text="Delete"
221+
variant={ButtonVariantType.secondary}
222+
style={ButtonStyleType.negative}
223+
startIcon={<Icon name="ic-delete" color={null} />}
224+
/>
232225
</div>
233226
</div>
234227
<div className="flexbox-col dc__gap-16">

src/Pages/GlobalConfigurations/Authorization/APITokens/GenerateModal.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
ClipboardButton,
2121
copyToClipboard,
2222
GenericModal,
23+
Icon,
2324
InfoBlock,
2425
stopPropagation,
2526
} from '@devtron-labs/devtron-fe-common-lib'
@@ -35,7 +36,7 @@ const GenerateModal = ({
3536
open,
3637
}: GenerateTokenModalType) => {
3738
const [copyToClipboardPromise, setCopyToClipboardPromise] = useState<ReturnType<typeof copyToClipboard>>(null)
38-
const modelType = isRegenerationModal ? 'regenerated' : 'generated'
39+
const modelType = isRegenerationModal ? 'Regenerated' : 'Generated'
3940
const handleCloseButton = () => {
4041
close()
4142
reload()
@@ -59,14 +60,21 @@ const GenerateModal = ({
5960
<GenericModal.Body>
6061
<div className="flexbox-col dc__gap-20 p-20">
6162
<div className="flexbox-col dc__gap-4">
62-
<h4 className="m-0">Copy and store this token safely, you won’t be able to view it again.</h4>
63+
<h5 className="m-0 cn-9 lh-1-5">
64+
Copy and store this token safely, you won’t be able to view it again.
65+
</h5>
6366
<p className="cn-7 fs-12 lh-1-5 m-0">
6467
You can regenerate a token anytime. If you do, remember to update any scripts or
6568
applications using the old token.
6669
</p>
6770
</div>
6871

69-
<InfoBlock description={token} variant="success" />
72+
<InfoBlock
73+
heading="API Token"
74+
description={token}
75+
variant="success"
76+
customIcon={<Icon name="ic-key" color="G500" />}
77+
/>
7078
</div>
7179
</GenericModal.Body>
7280
<GenericModal.Footer

src/components/ciPipeline/Webhook/WebhookDetailsModal.tsx

Lines changed: 58 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ import {
2323
copyToClipboard,
2424
CustomInput,
2525
ClipboardButton,
26-
ButtonWithLoader,
2726
CodeEditor,
28-
SelectPicker,
2927
TabGroup,
3028
ComponentSizeType,
3129
ToastVariantType,
@@ -37,31 +35,23 @@ import {
3735
ActionTypes,
3836
InfoBlock,
3937
DocLink,
38+
stopPropagation,
39+
ButtonStyleType,
40+
Icon,
4041
} from '@devtron-labs/devtron-fe-common-lib'
4142
import { useParams } from 'react-router-dom'
4243
import Tippy from '@tippyjs/react'
4344
import { ReactComponent as Close } from '../../../assets/icons/ic-close.svg'
4445
import { ReactComponent as Help } from '../../../assets/icons/ic-help.svg'
4546
import { ReactComponent as ICHelpOutline } from '../../../assets/icons/ic-help-outline.svg'
4647
import { ReactComponent as Add } from '../../../assets/icons/ic-add.svg'
47-
import { ReactComponent as PlayButton } from '../../../assets/icons/ic-play.svg'
4848
import { ReactComponent as Tag } from '../../../assets/icons/ic-tag.svg'
4949
import './webhookDetails.scss'
50-
import {
51-
getUserRole,
52-
createOrUpdateUser,
53-
} from '@Pages/GlobalConfigurations/Authorization/authorization.service'
50+
import { getUserRole, createOrUpdateUser } from '@Pages/GlobalConfigurations/Authorization/authorization.service'
5451
import { MODES, SERVER_MODE, WEBHOOK_NO_API_TOKEN_ERROR } from '../../../config'
5552
import { createGeneratedAPIToken } from '@Pages/GlobalConfigurations/Authorization/APITokens/service'
56-
import {
57-
CURL_PREFIX,
58-
getWebhookTokenListOptions,
59-
PLAYGROUND_TAB_LIST,
60-
REQUEST_BODY_TAB_LIST,
61-
RESPONSE_TAB_LIST,
62-
TOKEN_TAB_LIST,
63-
} from './webhook.utils'
64-
import { SchemaType, TabDetailsType, TokenListOptionsType, WebhookDetailsType, WebhookDetailType } from './types'
53+
import { CURL_PREFIX, PLAYGROUND_TAB_LIST, REQUEST_BODY_TAB_LIST, RESPONSE_TAB_LIST } from './webhook.utils'
54+
import { SchemaType, TabDetailsType, WebhookDetailsType, WebhookDetailType } from './types'
6555
import { executeWebhookAPI, getExternalCIConfig, getWebhookAPITokenList } from './webhook.service'
6656
import { GENERATE_TOKEN_NAME_VALIDATION } from '../../../config/constantMessaging'
6757
import { createUserPermissionPayload } from '@Pages/GlobalConfigurations/Authorization/utils'
@@ -82,15 +72,12 @@ export const WebhookDetailsModal = ({ close, isTemplateView }: WebhookDetailType
8272
const [loader, setLoader] = useState(false)
8373
const [webhookExecutionLoader, setWebhookExecutionLoader] = useState(false)
8474
const [generateTokenLoader, setGenerateTokenLoader] = useState(false)
85-
const [selectedTokenTab, setSelectedTokenTab] = useState<string>(TOKEN_TAB_LIST[0].key)
8675
const [tokenName, setTokenName] = useState<string>('')
8776
const [showTokenNameError, setTokenNameError] = useState(false)
8877
const [selectedPlaygroundTab, setSelectedPlaygroundTab] = useState<string>(PLAYGROUND_TAB_LIST[0].key)
8978
const [selectedRequestBodyTab, setRequestBodyPlaygroundTab] = useState<string>(REQUEST_BODY_TAB_LIST[0].key)
9079
const [webhookResponse, setWebhookResponse] = useState<Object>(null)
91-
const [selectedToken, setSelectedToken] = useState<TokenListOptionsType>(null)
9280
const [generatedAPIToken, setGeneratedAPIToken] = useState<string>(null)
93-
const [tokenList, setTokenList] = useState<TokenListOptionsType[]>(undefined)
9481
const [showTokenSection, setShowTokenSection] = useState(false)
9582
const [isSuperAdmin, setIsSuperAdmin] = useState(false)
9683
const [samplePayload, setSamplePayload] = useState<any>(null)
@@ -203,7 +190,6 @@ export const WebhookDetailsModal = ({ close, isTemplateView }: WebhookDetailType
203190
.map((tokenData) => {
204191
return { label: tokenData.name, value: tokenData.id, ...tokenData }
205192
}) || []
206-
setTokenList(sortedResult)
207193
}
208194
setLoader(false)
209195
} catch (error) {
@@ -379,41 +365,31 @@ export const WebhookDetailsModal = ({ close, isTemplateView }: WebhookDetailType
379365
)
380366
}
381367

382-
const renderSelectedToken = (titlePrefix: string, token: string): JSX.Element => {
383-
return (
384-
<div>
385-
<div className="cn-7 mt-16 mb-8 fs-13">{titlePrefix} API token</div>
386-
<div className="fs-13 font-roboto flexbox dc__word-break pl-8-imp" data-testid="generated-api-token">
387-
{token}
388-
<div className="flex pl-4">
389-
<ClipboardButton content={token} />
390-
</div>
391-
</div>
392-
</div>
393-
)
368+
const handleCopyToClipboard = async ({ e, token }: { e: React.MouseEvent; token: string }) => {
369+
stopPropagation(e)
370+
setCopyToClipboardPromise(copyToClipboard(token))
394371
}
395372

396-
const renderSelectTokenSection = (): JSX.Element => {
397-
const handleSelectedTokenChange = (selectedToken): void => {
398-
setSelectedToken(selectedToken)
399-
}
400-
373+
const renderSelectedToken = (token: string): JSX.Element => {
401374
return (
402-
<>
403-
<div className="w-400 h-32 mt-16">
404-
<SelectPicker
405-
inputId="select-token"
406-
name="select-token"
407-
classNamePrefix="select-token"
408-
placeholder="Select API token"
409-
isClearable={false}
410-
options={getWebhookTokenListOptions(tokenList)}
411-
value={selectedToken}
412-
onChange={handleSelectedTokenChange}
413-
isSearchable={false}
414-
/>
415-
</div>
416-
</>
375+
<div className="mt-16">
376+
<InfoBlock
377+
heading="Copy and store this token safely, you won’t be able to view it again."
378+
description={
379+
<div className="fs-13 font-roboto flexbox dc__word-break" data-testid="generated-api-token">
380+
{token}
381+
</div>
382+
}
383+
buttonProps={{
384+
text: 'Copy',
385+
startIcon: <ClipboardButton content={token} copyToClipboardPromise={copyToClipboardPromise} />,
386+
dataTestId: 'copy-generated-api-token',
387+
variant: ButtonVariantType.text,
388+
onClick: (e) => handleCopyToClipboard({ e, token }),
389+
}}
390+
variant="success"
391+
/>
392+
</div>
417393
)
418394
}
419395

@@ -427,7 +403,7 @@ export const WebhookDetailsModal = ({ close, isTemplateView }: WebhookDetailType
427403
const renderGenerateTokenSection = (): JSX.Element => {
428404
return (
429405
<div className="flexbox-col dc__gap-16">
430-
<div className="mt-16">
406+
<div className="mt-8">
431407
<CustomInput
432408
placeholder="Enter token name"
433409
name="token-name"
@@ -437,8 +413,9 @@ export const WebhookDetailsModal = ({ close, isTemplateView }: WebhookDetailType
437413
disabled={!!generatedAPIToken}
438414
error={showTokenNameError && GENERATE_TOKEN_NAME_VALIDATION}
439415
helperText="An API token with the required permissions will be auto-generated."
416+
required
440417
/>
441-
{generatedAPIToken && renderSelectedToken('Generated', generatedAPIToken)}
418+
{generatedAPIToken && renderSelectedToken(generatedAPIToken)}
442419
</div>
443420
{!generatedAPIToken && (
444421
<Button
@@ -470,13 +447,12 @@ export const WebhookDetailsModal = ({ close, isTemplateView }: WebhookDetailType
470447
dataTestId="select-or-generate-token"
471448
variant={ButtonVariantType.text}
472449
onClick={toggleTokenSection}
473-
text="Select or auto-generate token with required permissions"
450+
text="Auto-generate token with required permissions"
474451
/>
475452
) : (
476-
<div>
477-
{generateTabHeader(TOKEN_TAB_LIST, selectedTokenTab, setSelectedTokenTab)}
478-
{selectedTokenTab === TOKEN_TAB_LIST[0].key && renderSelectTokenSection()}
479-
{selectedTokenTab === TOKEN_TAB_LIST[1].key && renderGenerateTokenSection()}
453+
<div className="cn-9 fs-13 mb-8">
454+
<span className="fs-13 lh-1-5 fw-6">Generate token with required permissions</span>
455+
{renderGenerateTokenSection()}
480456
</div>
481457
)
482458
}
@@ -820,19 +796,23 @@ export const WebhookDetailsModal = ({ close, isTemplateView }: WebhookDetailType
820796
const renderTryoutActionSection = (): JSX.Element => {
821797
return (
822798
<div className="flex left mt-20">
823-
<ButtonWithLoader
824-
rootClassName="cta h-28 flex mr-8"
799+
<Button
800+
dataTestId="execute-token"
825801
onClick={executeWebhook}
802+
text="Execute"
803+
startIcon={<Icon name="ic-play-outline" color="N0" size={18} />}
826804
isLoading={webhookExecutionLoader}
827-
>
828-
<PlayButton className="icon-dim-18 mr-8" />
829-
Execute
830-
</ButtonWithLoader>
805+
size={ComponentSizeType.small}
806+
/>
831807
{webhookResponse && (
832-
<button className="cta cancel h-28 flex" onClick={clearWebhookResponse}>
833-
<Close className="icon-dim-18 mr-8" />
834-
Clear
835-
</button>
808+
<Button
809+
dataTestId="clear-response"
810+
onClick={clearWebhookResponse}
811+
text="Clear"
812+
startIcon={<Icon name="ic-close-large" color="N0" size={18} />}
813+
size={ComponentSizeType.small}
814+
variant={ButtonVariantType.secondary}
815+
/>
836816
)}
837817
</div>
838818
)
@@ -869,9 +849,15 @@ export const WebhookDetailsModal = ({ close, isTemplateView }: WebhookDetailType
869849
return (
870850
<div className="flex flex-align-center flex-justify dc__border-bottom bg__primary pt-16 pr-20 pb-16 pl-20">
871851
<h2 className="fs-16 fw-6 lh-1-43 m-0">Webhook Details</h2>
872-
<button type="button" className="dc__transparent flex icon-dim-24" onClick={closeWebhook}>
873-
<Close className="icon-dim-24" />
874-
</button>
852+
<Button
853+
dataTestId="close-webhook-details-modal"
854+
icon={<Icon name="ic-close-large" color={null} />}
855+
ariaLabel="Close"
856+
showAriaLabelInTippy={false}
857+
onClick={closeWebhook}
858+
variant={ButtonVariantType.borderLess}
859+
style={ButtonStyleType.negativeGrey}
860+
/>
875861
</div>
876862
)
877863
}

src/components/ciPipeline/Webhook/types.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
import { AppConfigProps, ResponseType } from '@devtron-labs/devtron-fe-common-lib'
1818

19-
import { TokenListType } from '@Pages/GlobalConfigurations/Authorization/APITokens/apiToken.type'
20-
2119
export interface WebhookDetailType extends Required<Pick<AppConfigProps, 'isTemplateView'>> {
2220
close: () => void
2321
}
@@ -27,12 +25,6 @@ export interface TabDetailsType {
2725
value: string
2826
}
2927

30-
export interface TokenListOptionsType extends TokenListType {
31-
label: string
32-
value: string
33-
description: string
34-
}
35-
3628
export interface TokenPermissionType {
3729
projectName: string
3830
environmentName: string

0 commit comments

Comments
 (0)