fix: [CODE-615]: Misc. UX Feedback (#240)

This commit is contained in:
rajarshee.chatterjee@harness.io 2023-07-26 18:14:31 +00:00 committed by Harness
parent ea5ed851d1
commit 5232615e0a
8 changed files with 84 additions and 30 deletions

View File

@ -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

View File

@ -507,6 +507,8 @@ confirmNewPassword: Confirm the <b>NEW</b> 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

View File

@ -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])
})),
[]
)

View File

@ -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);

View File

@ -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<EnumMembershipRole, StringKeys> = {
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<TypesMembership>) => (
<Layout.Horizontal style={{ alignItems: 'center' }}>
<Avatar name={row.original.principal?.display_name} size="normal" hoverCard={false} />
<Avatar
name={row.original.principal?.display_name}
size="normal"
hoverCard={false}
color={Color.WHITE}
backgroundColor={Color.PRIMARY_7}
/>
<Text font={{ variation: FontVariation.SMALL_SEMI }} lineClamp={1}>
{row.original.principal?.display_name}
</Text>
@ -65,11 +78,15 @@ const SpaceAccessControl = () => {
{
Header: getString('role'),
width: '40%',
Cell: ({ row }: CellProps<TypesMembership>) => (
<Text font={{ variation: FontVariation.TINY_SEMI }} color={Color.PRIMARY_9} className={css.roleBadge}>
{row.original.role}
</Text>
)
Cell: ({ row }: CellProps<TypesMembership>) => {
const stringKey = row.original.role ? roleStringKeyMap[row.original.role] : undefined
return (
<Text font={{ variation: FontVariation.TINY_SEMI }} color={Color.PRIMARY_9} className={css.roleBadge}>
{stringKey ? getString(stringKey) : row.original.role}
</Text>
)
}
},
{
Header: getString('email'),

View File

@ -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<string>()
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 (
<Dialog isOpen enforceFocus={false} onClose={onModalClose} title={getString('createNewToken')}>
<Formik
<Formik<OpenapiCreateTokenRequest>
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 (
<FormikForm>
@ -82,18 +90,20 @@ const useNewToken = ({ onClose }: { onClose: () => void }) => {
disabled={isTokenGenerated}
/>
<FormInput.Select
name="lifeTime"
name="lifetime"
label={getString('expiration')}
items={lifeTimeOptions}
usePortal
disabled={isTokenGenerated}
/>
{formikProps.values.lifeTime ? (
{lifetime ? (
<Text
font={{ variation: FontVariation.SMALL_SEMI }}
color={Color.GREY_400}
margin={{ bottom: 'medium' }}>
{getString('newToken.expireOn', { date: expiresAtString })}
{lifetime === Infinity
? getString('noExpirationDate')
: getString('newToken.expireOn', { date: expiresAtString })}
</Text>
) : null}
<Render when={isTokenGenerated}>

View File

@ -91,7 +91,7 @@ const UserProfile = () => {
Header: getString('status'),
width: '20%',
Cell: ({ row }: CellProps<TypesToken>) => {
const isActive = +Date.now() < Number(row.original.expires_at)
const isActive = !row.original.expires_at || +Date.now() < Number(row.original.expires_at)
return (
<Text
@ -111,7 +111,9 @@ const UserProfile = () => {
Cell: ({ row }: CellProps<TypesToken>) => {
return (
<Text font={{ variation: FontVariation.SMALL }} color={Color.GREY_500} lineClamp={1}>
{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')}
</Text>
)
}
@ -163,7 +165,14 @@ const UserProfile = () => {
<Page.Body>
<Container className={css.pageCtn}>
<Card className={css.profileCard}>
<Avatar name={currentUser?.display_name} size="large" hoverCard={false} />
<Avatar
name={currentUser?.display_name}
size="large"
hoverCard={false}
color={Color.WHITE}
backgroundColor={Color.PRIMARY_7}
borderColor={Color.PRIMARY_8}
/>
<Container className={css.detailsCtn}>
<Layout.Horizontal className={css.detailField}>
<Text width={150} font={{ variation: FontVariation.SMALL }} color={Color.GREY_600}>

View File

@ -77,7 +77,13 @@ const UsersListing = () => {
Cell: ({ row }: CellProps<TypesUser>) => {
return (
<Layout.Horizontal style={{ alignItems: 'center' }}>
<Avatar name={row.original.display_name} size="normal" hoverCard={false} />
<Avatar
name={row.original.display_name}
size="normal"
hoverCard={false}
color={Color.WHITE}
backgroundColor={Color.PRIMARY_7}
/>
<Text font={{ variation: FontVariation.SMALL_SEMI }} margin={{ right: 'small' }} lineClamp={1}>
{row.original.display_name}
</Text>