Skip to content
Merged
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"homepage": "/dashboard",
"dependencies": {
"@devtron-labs/devtron-fe-common-lib": "1.17.0-pre-12",
"@devtron-labs/devtron-fe-common-lib": "1.17.0-pre-13",
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@rjsf/core": "^5.13.3",
"@rjsf/utils": "^5.13.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
import emptyGeneratToken from '@Images/ic-empty-generate-token.png'
import { EMPTY_STATE_STATUS } from '@Config/constantMessaging'

import { TokenListType, TokenResponseType } from './apiToken.type'
import { TokenListType } from './apiToken.type'
import APITokenList from './APITokenList'
import CreateAPIToken from './CreateAPIToken'
import EditAPIToken from './EditAPIToken'
Expand Down Expand Up @@ -90,13 +90,6 @@ const ApiTokens = () => {
handleFilterChanges(_searchText)
}

const [tokenResponse, setTokenResponse] = useState<TokenResponseType>({
success: false,
token: '',
userId: 0,
userIdentifier: 'API-TOKEN:test',
})

const renderSearchToken = () => (
<SearchBar
initialSearchText={searchText}
Expand Down Expand Up @@ -131,8 +124,6 @@ const ApiTokens = () => {
handleGenerateTokenActionButton={handleActionButton}
setSelectedExpirationDate={setSelectedExpirationDate}
selectedExpirationDate={selectedExpirationDate}
tokenResponse={tokenResponse}
setTokenResponse={setTokenResponse}
reload={getData}
/>
</Route>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {
usePermissionConfiguration,
} from '../Shared/components/PermissionConfigurationForm'
import { createUserPermissionPayload, validateDirectPermissionForm } from '../utils'
import { FormType, GenerateTokenType } from './apiToken.type'
import { FormType, GenerateTokenType, TokenResponseType } from './apiToken.type'
import { getDateInMilliseconds } from './apiToken.utils'
import ExpirationDate from './ExpirationDate'
import GenerateActionButton from './GenerateActionButton'
Expand All @@ -69,8 +69,6 @@ const CreateAPIToken = ({
handleGenerateTokenActionButton,
setSelectedExpirationDate,
selectedExpirationDate,
tokenResponse,
setTokenResponse,
reload,
}: GenerateTokenType) => {
const history = useHistory()
Expand Down Expand Up @@ -106,6 +104,13 @@ const CreateAPIToken = ({
allowManageAllAccess,
} = usePermissionConfiguration()
const [customDate, setCustomDate] = useState<Moment>(null)
const [tokenResponse, setTokenResponse] = useState<TokenResponseType>({
success: false,
token: '',
userId: 0,
userIdentifier: 'API-TOKEN:test',
hideApiToken: false,
})
const validationRules = new ValidationRules()

// Reset selected expiration date to 30 days on unmount
Expand Down Expand Up @@ -210,6 +215,7 @@ const CreateAPIToken = ({
const userPermissionPayload = createUserPermissionPayload({
id: result.userId,
userIdentifier: result.userIdentifier,
hideApiToken: result.hideApiToken,
userRoleGroups,
serverMode,
directPermission,
Expand Down Expand Up @@ -308,13 +314,13 @@ const CreateAPIToken = ({
buttonText="Generate token"
disabled={isSaveDisabled}
/>

<GenerateModal
close={handleGenerateTokenActionButton}
token={tokenResponse.token}
reload={reload}
redirectToTokenList={redirectToTokenList}
open={showGenerateModal}
hideApiToken={tokenResponse.hideApiToken}
/>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
Button,
ButtonStyleType,
ButtonVariantType,
ClipboardButton,
CustomInput,
Icon,
InfoBlock,
Expand Down Expand Up @@ -243,6 +244,19 @@ const EditAPIToken = ({
placeholder="Enter a description to remember where you have used this token"
error={invalidDescription ? 'Max 350 characters allowed.' : null}
/>
{!!editData?.token?.length && (
<label className="form__row">
<span className="form__label">Token</span>
<div className="flex dc__content-space top cn-9">
<span data-testid="api-token-string" className="mono fs-14 dc__word-break">
{editData.token}
</span>
<div className="icon-dim-16 ml-8">
<ClipboardButton content={editData.token} />
</div>
</div>
</label>
)}
<div className="dc__border-top" />
<PermissionConfigurationForm showUserPermissionGroupSelector isAddMode={false} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@ import {
} from '@devtron-labs/devtron-fe-common-lib'

import { GenerateTokenModalType } from './apiToken.type'
import { getApiTokenHeader } from './apiToken.utils'

const GenerateModal = ({
close,
token,
token = '',
reload,
redirectToTokenList,
isRegenerationModal,
open,
hideApiToken = false,
}: GenerateTokenModalType) => {
const [copyToClipboardPromise, setCopyToClipboardPromise] = useState<ReturnType<typeof copyToClipboard>>(null)
const modelType = isRegenerationModal ? 'Regenerated' : 'Generated'
Expand All @@ -60,9 +62,7 @@ const GenerateModal = ({
<GenericModal.Body>
<div className="flexbox-col dc__gap-20 p-20">
<div className="flexbox-col dc__gap-4">
<h5 className="m-0 cn-9 lh-1-5 fw-6">
Copy and store this token safely, you won’t be able to view it again.
</h5>
<h5 className="m-0 cn-9 lh-1-5 fw-6">{getApiTokenHeader(hideApiToken)}</h5>
<p className="cn-7 fs-12 lh-1-5 m-0">
You can regenerate a token anytime. If you do, remember to update any scripts or
applications using the old token.
Expand All @@ -71,7 +71,11 @@ const GenerateModal = ({

<InfoBlock
heading="API Token"
description={token}
description={
<div className="fs-13 font-roboto flexbox dc__word-break" data-testid="generated-token">
{token}
</div>
}
variant="success"
customIcon={<Icon name="ic-key" color="G500" />}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ const RegeneratedModal = ({
redirectToTokenList={redirectToTokenList}
isRegenerationModal
open={showGenerateModal}
hideApiToken={tokenResponse.hideApiToken}
/>
) : (
<VisibleModal className="regenerate-token-modal">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ export interface FormType {
}
export interface TokenResponseType {
success: boolean
token: string
userId: number
userIdentifier: string
hideApiToken: boolean
token?: string
}

export interface GenerateTokenType {
Expand All @@ -37,25 +38,24 @@ export interface GenerateTokenType {
handleGenerateTokenActionButton: () => void
setSelectedExpirationDate
selectedExpirationDate
tokenResponse: TokenResponseType
setTokenResponse: React.Dispatch<React.SetStateAction<TokenResponseType>>
reload: () => void
}

export interface TokenListType {
export interface TokenListType extends Pick<TokenResponseType, 'token' | 'userIdentifier' | 'userId' | 'hideApiToken'> {
expireAtInMs: number
id: number
name: string
userId: number
userIdentifier: string
description: string
lastUsedByIp?: string
lastUsedAt?: string
updatedAt?: string
}

export interface EditDataType
extends Pick<TokenListType, 'name' | 'description' | 'expireAtInMs' | 'id' | 'userId' | 'userIdentifier'> {}
extends Pick<
TokenListType,
'name' | 'description' | 'expireAtInMs' | 'token' | 'id' | 'userId' | 'userIdentifier' | 'hideApiToken'
> {}
export interface EditTokenType {
setShowRegeneratedModal: React.Dispatch<React.SetStateAction<boolean>>
showRegeneratedModal: boolean
Expand All @@ -77,11 +77,12 @@ export interface GenerateActionButtonType {

export interface GenerateTokenModalType {
close: () => void
token: string
token: TokenListType['token']
reload: () => void
redirectToTokenList: () => void
isRegenerationModal?: boolean
open: GenericModalProps['open']
hideApiToken: TokenListType['hideApiToken']
}

export interface APITokenListType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

import { TokenListType } from './apiToken.type'

export function getOptions(customDate) {
return [
{ value: 7, label: '7 days' },
Expand All @@ -36,3 +38,6 @@ export const isTokenExpired = (expiredDate: number): boolean => {

return getDateInMilliseconds(new Date().valueOf()) > getDateInMilliseconds(expiredDate)
}

export const getApiTokenHeader = (hideApiToken: TokenListType['hideApiToken']) =>
`Copy and store this token safely ${hideApiToken ? ', you won’t be able to view it again.' : ''}`
4 changes: 3 additions & 1 deletion src/Pages/GlobalConfigurations/Authorization/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
} from '@devtron-labs/devtron-fe-common-lib'

import { SERVER_MODE } from '../../../config'
import { TokenResponseType } from './APITokens/apiToken.type'
import { PermissionType, UserRoleType } from './constants'

export interface UserAndGroupPermissionsWrapProps {
Expand Down Expand Up @@ -311,7 +312,8 @@ export interface CreateUserPermissionPayloadParams
extends Pick<User, 'userStatus' | 'timeToLive' | 'userRoleGroups' | 'canManageAllAccess'> {
id: number
userGroups: Pick<UserGroupType, 'name' | 'userGroupId'>[]
userIdentifier: string
hideApiToken?: TokenResponseType['hideApiToken']
userIdentifier: TokenResponseType['userIdentifier']
serverMode: SERVER_MODE
directPermission: DirectPermissionsRoleFilter[]
chartPermission: ChartGroupPermissionsFilter
Expand Down
Loading