diff --git a/web/src/framework/strings/stringTypes.ts b/web/src/framework/strings/stringTypes.ts index 4b6a7f020..43e7ee755 100644 --- a/web/src/framework/strings/stringTypes.ts +++ b/web/src/framework/strings/stringTypes.ts @@ -86,6 +86,7 @@ export interface StringsMap { confirmation: string content: string contents: string + contributor: string conversation: string copy: string copyBranch: string @@ -161,6 +162,7 @@ export interface StringsMap { enterTagPlaceholder: string enterUser: string error404Text: string + executor: string existingAccount: string expiration: string expirationDate: string @@ -244,6 +246,8 @@ export interface StringsMap { noCommits: string noCommitsMessage: string noCommitsPR: string + noExpiration: string + noExpirationDate: string noOptionalReviewers: string noRequiredReviewers: string noResultMessage: string @@ -261,6 +265,7 @@ export interface StringsMap { optional: string optionalExtendedDescription: string overview: string + owner: string pageLoading: string pageNotFound: string 'pageTitle.accessControl': string @@ -369,6 +374,7 @@ export interface StringsMap { quote: string reactivate: string readMe: string + reader: string refresh: string reject: string rejected: string diff --git a/web/src/i18n/strings.en.yaml b/web/src/i18n/strings.en.yaml index da5e45e9c..5165b6c12 100644 --- a/web/src/i18n/strings.en.yaml +++ b/web/src/i18n/strings.en.yaml @@ -507,6 +507,8 @@ confirmNewPassword: Confirm the NEW password accountSetting: Account Setting nDays: '{{number}} Days' expiration: Expiration +noExpiration: No Expiration +noExpirationDate: The token will never expire! token: Token expired: Expired expirationDate: Expiration Date @@ -571,3 +573,7 @@ deleteSpace: Delete Space spaceSetting: intentText: This will permanently delete the space named '{{space}}', and everything contained in it. All repositories in this space will be deleted. setting: Space Setting +contributor: Contributor +reader: Reader +executor: Executor +owner: Owner diff --git a/web/src/pages/SpaceAccessControl/AddNewMember/AddNewMember.tsx b/web/src/pages/SpaceAccessControl/AddNewMember/AddNewMember.tsx index 2bdcc86c8..f20b0ee7d 100644 --- a/web/src/pages/SpaceAccessControl/AddNewMember/AddNewMember.tsx +++ b/web/src/pages/SpaceAccessControl/AddNewMember/AddNewMember.tsx @@ -2,7 +2,6 @@ import React, { useMemo, useState } from 'react' import { Button, ButtonVariation, Dialog, FormikForm, FormInput, SelectOption, useToaster } from '@harness/uicore' import { useModalHook } from '@harness/use-modal' import { Formik } from 'formik' -import { capitalize } from 'lodash-es' import * as Yup from 'yup' @@ -17,7 +16,9 @@ import { } from 'services/code' import { getErrorMessage } from 'utils/Utils' -const roles = ['contributor', 'executor', 'reader', 'space_owner'] as const +import { roleStringKeyMap } from '../SpaceAccessControl' + +const roles = ['reader', 'executor', 'contributor', 'space_owner'] as const const useAddNewMember = ({ onClose }: { onClose: () => void }) => { const [isEditFlow, setIsEditFlow] = useState(false) @@ -37,7 +38,7 @@ const useAddNewMember = ({ onClose }: { onClose: () => void }) => { () => roles.map(role => ({ value: role, - label: capitalize(role) + label: getString(roleStringKeyMap[role]) })), [] ) diff --git a/web/src/pages/SpaceAccessControl/SpaceAccessControl.module.scss b/web/src/pages/SpaceAccessControl/SpaceAccessControl.module.scss index 5601de039..8caa9ba8d 100644 --- a/web/src/pages/SpaceAccessControl/SpaceAccessControl.module.scss +++ b/web/src/pages/SpaceAccessControl/SpaceAccessControl.module.scss @@ -3,7 +3,6 @@ background-color: var(--primary-bg) !important; .roleBadge { - text-transform: capitalize; padding: var(--spacing-xsmall) 6px; border-radius: 4px; border: 1px solid var(--grey-200); diff --git a/web/src/pages/SpaceAccessControl/SpaceAccessControl.tsx b/web/src/pages/SpaceAccessControl/SpaceAccessControl.tsx index d1527c8ce..2f73145b2 100644 --- a/web/src/pages/SpaceAccessControl/SpaceAccessControl.tsx +++ b/web/src/pages/SpaceAccessControl/SpaceAccessControl.tsx @@ -3,10 +3,10 @@ import { Avatar, Button, ButtonVariation, Container, Layout, Page, TableV2, Text import { Color, FontVariation } from '@harness/design-system' import type { CellProps, Column } from 'react-table' -import { useStrings } from 'framework/strings' +import { StringKeys, useStrings } from 'framework/strings' import { useConfirmAct } from 'hooks/useConfirmAction' import { useGetSpaceParam } from 'hooks/useGetSpaceParam' -import { TypesMembership, useMembershipDelete, useMembershipList } from 'services/code' +import { EnumMembershipRole, TypesMembership, useMembershipDelete, useMembershipList } from 'services/code' import { getErrorMessage } from 'utils/Utils' import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner' import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButton' @@ -15,6 +15,13 @@ import useAddNewMember from './AddNewMember/AddNewMember' import css from './SpaceAccessControl.module.scss' +export const roleStringKeyMap: Record = { + contributor: 'contributor', + executor: 'executor', + reader: 'reader', + space_owner: 'owner' +} + const SpaceAccessControl = () => { const { getString } = useStrings() const { showError, showSuccess } = useToaster() @@ -55,7 +62,13 @@ const SpaceAccessControl = () => { width: '30%', Cell: ({ row }: CellProps) => ( - + {row.original.principal?.display_name} @@ -65,11 +78,15 @@ const SpaceAccessControl = () => { { Header: getString('role'), width: '40%', - Cell: ({ row }: CellProps) => ( - - {row.original.role} - - ) + Cell: ({ row }: CellProps) => { + const stringKey = row.original.role ? roleStringKeyMap[row.original.role] : undefined + + return ( + + {stringKey ? getString(stringKey) : row.original.role} + + ) + } }, { Header: getString('email'), diff --git a/web/src/pages/UserProfile/NewToken/NewToken.tsx b/web/src/pages/UserProfile/NewToken/NewToken.tsx index c7b9720b6..05be2b0c4 100644 --- a/web/src/pages/UserProfile/NewToken/NewToken.tsx +++ b/web/src/pages/UserProfile/NewToken/NewToken.tsx @@ -10,6 +10,7 @@ import { FormikForm, FormInput, Layout, + SelectOption, Text } from '@harness/uicore' import { useModalHook } from '@harness/use-modal' @@ -18,8 +19,10 @@ import { useMutate } from 'restful-react' import moment from 'moment' import * as Yup from 'yup' import { Else, Match, Render, Truthy } from 'react-jsx-match' +import { omit } from 'lodash-es' import { useStrings } from 'framework/strings' +import type { OpenapiCreateTokenRequest } from 'services/code' import { REGEX_VALID_REPO_NAME } from 'utils/Utils' import { CodeIcon } from 'utils/GitUtils' import { CopyButton } from 'components/CopyButton/CopyButton' @@ -34,44 +37,49 @@ const useNewToken = ({ onClose }: { onClose: () => void }) => { const [generatedToken, setGeneratedToken] = useState() const isTokenGenerated = Boolean(generatedToken) - const lifeTimeOptions = useMemo( + const lifeTimeOptions: SelectOption[] = useMemo( () => [ { label: getString('nDays', { number: 7 }), value: 604800000000000 }, { label: getString('nDays', { number: 30 }), value: 2592000000000000 }, { label: getString('nDays', { number: 60 }), value: 5184000000000000 }, - { label: getString('nDays', { number: 90 }), value: 7776000000000000 } + { label: getString('nDays', { number: 90 }), value: 7776000000000000 }, + { label: getString('noExpiration'), value: Infinity } ], [getString] ) const onModalClose = () => { + setGeneratedToken('') hideModal() onClose() - setGeneratedToken() } const [openModal, hideModal] = useModalHook(() => { return ( - initialValues={{ - uid: '', - lifeTime: 0 + uid: '' }} validationSchema={Yup.object().shape({ uid: Yup.string() .required(getString('validation.nameIsRequired')) .matches(REGEX_VALID_REPO_NAME, getString('validation.nameInvalid')), - lifeTime: Yup.number().required(getString('validation.expirationDateRequired')) + lifetime: Yup.number().required(getString('validation.expirationDateRequired')) })} onSubmit={async values => { - const res = await mutate(values) + let payload = { ...values } + + if (payload.lifetime === Infinity) { + payload = omit(payload, 'lifetime') + } + + const res = await mutate(payload) setGeneratedToken(res?.access_token) }}> {formikProps => { - const expiresAtString = moment(Date.now() + formikProps.values.lifeTime / 1000000).format( - 'dddd, MMMM DD YYYY' - ) + const lifetime = formikProps.values.lifetime || 0 + const expiresAtString = moment(Date.now() + lifetime / 1000000).format('dddd, MMMM DD YYYY') return ( @@ -82,18 +90,20 @@ const useNewToken = ({ onClose }: { onClose: () => void }) => { disabled={isTokenGenerated} /> - {formikProps.values.lifeTime ? ( + {lifetime ? ( - {getString('newToken.expireOn', { date: expiresAtString })} + {lifetime === Infinity + ? getString('noExpirationDate') + : getString('newToken.expireOn', { date: expiresAtString })} ) : null} diff --git a/web/src/pages/UserProfile/UserProfile.tsx b/web/src/pages/UserProfile/UserProfile.tsx index e2cdf062f..849149120 100644 --- a/web/src/pages/UserProfile/UserProfile.tsx +++ b/web/src/pages/UserProfile/UserProfile.tsx @@ -91,7 +91,7 @@ const UserProfile = () => { Header: getString('status'), width: '20%', Cell: ({ row }: CellProps) => { - const isActive = +Date.now() < Number(row.original.expires_at) + const isActive = !row.original.expires_at || +Date.now() < Number(row.original.expires_at) return ( { Cell: ({ row }: CellProps) => { return ( - {moment(row.original.expires_at).format('MMM Do, YYYY h:mm:ss a')} + {row.original.expires_at + ? moment(row.original.expires_at).format('MMM Do, YYYY h:mm:ss a') + : getString('noExpiration')} ) } @@ -163,7 +165,14 @@ const UserProfile = () => { - + diff --git a/web/src/pages/UsersListing/UsersListing.tsx b/web/src/pages/UsersListing/UsersListing.tsx index 28b16d9d6..a6b65661e 100644 --- a/web/src/pages/UsersListing/UsersListing.tsx +++ b/web/src/pages/UsersListing/UsersListing.tsx @@ -77,7 +77,13 @@ const UsersListing = () => { Cell: ({ row }: CellProps) => { return ( - + {row.original.display_name}