mirror of
https://github.com/harness/drone.git
synced 2025-05-31 11:43:15 +00:00
fix: [CODE-615]: Misc. UX Feedback (#240)
This commit is contained in:
parent
ea5ed851d1
commit
5232615e0a
@ -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
|
||||
|
@ -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
|
||||
|
@ -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])
|
||||
})),
|
||||
[]
|
||||
)
|
||||
|
@ -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);
|
||||
|
@ -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'),
|
||||
|
@ -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}>
|
||||
|
@ -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}>
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user