Skip to content

Commit

Permalink
fix: Metadata UI improvements (#4327)
Browse files Browse the repository at this point in the history
  • Loading branch information
novakzaballa authored Jul 30, 2024
1 parent 8e2db7c commit d4006c0
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 93 deletions.
4 changes: 4 additions & 0 deletions frontend/common/stores/feature-list-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ const controller = {
})
.then((res) => {
// onComplete calls back preserving the order of multivariate_options with their updated ids
if (res.error) {
store.saved({ error: res.error })
return
}
if (onComplete) {
onComplete(res)
}
Expand Down
33 changes: 24 additions & 9 deletions frontend/common/stores/project-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,30 @@ const controller = {

editEnv: (env) => {
API.trackEvent(Constants.events.EDIT_ENVIRONMENT)
data.put(`${Project.api}environments/${env.api_key}/`, env).then((res) => {
const index = _.findIndex(store.model.environments, { id: env.id })
store.model.environments[index] = res
store.saved()
getStore().dispatch(
environmentService.util.invalidateTags(['Environment']),
)
AppActions.refreshOrganisation()
})
data
.put(`${Project.api}environments/${env.api_key}/`, env)
.then((res) => {
const index = _.findIndex(store.model.environments, { id: env.id })
store.model.environments[index] = res
store.saved()
getStore().dispatch(
environmentService.util.invalidateTags(['Environment']),
)
AppActions.refreshOrganisation()
})
.catch((e) => {
e.json()
.then((result) => {
if (result?.metadata?.[0]) {
toast(result.metadata[0], 'danger')
} else {
toast('Error updating the environment', 'danger')
}
})
.catch((e) => {
API.ajaxHandler(store, e)
})
})
},
editProject: (project) => {
store.saving()
Expand Down
16 changes: 6 additions & 10 deletions frontend/common/utils/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,10 @@ const Utils = Object.assign({}, require('./base/_utils'), {
valid = isEnterprise
break
}
case 'METADATA': {
valid = isEnterprise
break
}
default:
valid = true
break
Expand Down Expand Up @@ -536,16 +540,8 @@ const Utils = Object.assign({}, require('./base/_utils'), {
return /^-?\d*\.?\d+$/.test(`${value}`)
},
isValidURL(value: any) {
const pattern = new RegExp(
'^(https?:\\/\\/)?' + // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
'(\\#[-a-z\\d_]*)?$',
'i',
)
return !!pattern.test(value)
const regex = /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/i
return regex.test(value)
},
loadScriptPromise(url: string) {
return new Promise((resolve) => {
Expand Down
8 changes: 5 additions & 3 deletions frontend/web/components/base/forms/InputGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ const InputGroup = class extends Component {
const { inputProps, size } = this.props
return (
<div
className={`${
this.props.className ? this.props.className : ''
} form-group ${this.props.isInvalid ? 'invalid' : ''}`}
className={`${this.props.className ? this.props.className : ''} ${
this.props.noMargin ? '' : 'form-group'
} ${this.props.isInvalid ? 'invalid' : ''}`}
>
{this.props.tooltip ? (
<Tooltip
Expand Down Expand Up @@ -83,6 +83,7 @@ const InputGroup = class extends Component {
type={props.type || 'text'}
id={id}
placeholder={props.placeholder}
onBlur={props.onBlur}
/>
) : (
<Input
Expand All @@ -96,6 +97,7 @@ const InputGroup = class extends Component {
onChange={props.onChange}
type={props.type || 'text'}
id={id}
onBlur={props.onBlur}
placeholder={props.placeholder}
size={size}
/>
Expand Down
55 changes: 25 additions & 30 deletions frontend/web/components/metadata/AddMetadataToEntity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ import {
useUpdateEnvironmentMutation,
} from 'common/services/useEnvironment'
import { MetadataField, Metadata } from 'common/types/responses'
import Input from 'components/base/forms/Input'
import Utils from 'common/utils/utils'
import { useGetProjectFlagQuery } from 'common/services/useProjectFlag'
import Tooltip from 'components/Tooltip'
import { sortBy } from 'lodash'
import Switch from 'components/Switch'
import InputGroup from 'components/base/forms/InputGroup'

export type CustomMetadataField = MetadataField & {
metadataModelFieldId: number | string | null
Expand Down Expand Up @@ -247,8 +246,8 @@ const AddMetadataToEntity: FC<AddMetadataToEntityType> = ({
}}
renderNoResults={
<FormGroup>
No custom fields configured for {entity} entity. Add custom fields in
your{' '}
No custom fields configured for {entity} entity. Add custom fields
in your{' '}
<a
href={`/project/${projectId}/settings?tab=metadata`}
target='_blank'
Expand Down Expand Up @@ -334,32 +333,7 @@ const MetadataRow: FC<MetadataRowType> = ({
<Flex className='table-column'>{`${metadata?.name} ${
metadata?.isRequiredFor ? '*' : ''
}`}</Flex>
{metadata?.type !== 'bool' ? (
<Flex className='flex-row' style={{ minWidth: '300px' }}>
<Tooltip
title={
<Input
value={metadataValue}
onBlur={saveMetadata}
onChange={(e: InputEvent) => {
setMetadataValue(Utils.safeParseEventValue(e))
setMetadataValueChanged(true)
}}
className='mr-2'
style={{ width: '250px' }}
placeholder='Field Value'
isValid={Utils.validateMetadataType(
metadata?.type,
metadataValue,
)}
/>
}
place='top'
>
{`This value has to be of type ${metadata?.type}`}
</Tooltip>
</Flex>
) : (
{metadata?.type === 'bool' ? (
<Flex className='flex-row'>
<Switch
checked={!!metadataValue}
Expand All @@ -370,6 +344,27 @@ const MetadataRow: FC<MetadataRowType> = ({
}}
/>
</Flex>
) : (
<Flex className='flex-row mt-1' style={{ minWidth: '300px' }}>
<InputGroup
textarea={metadata?.type === 'multiline_str'}
onBlur={saveMetadata}
value={metadataValue}
inputProps={{
style: {
height: metadata?.type === 'multiline_str' ? '65px' : '44px',
width: '250px',
},
}}
noMargin
isValid={Utils.validateMetadataType(metadata?.type, metadataValue)}
onChange={(e: InputEvent) => {
setMetadataValue(Utils.safeParseEventValue(e))
setMetadataValueChanged(true)
}}
type='text'
/>
</Flex>
)}
</Row>
)
Expand Down
73 changes: 40 additions & 33 deletions frontend/web/components/modals/CreateFlag.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import { getSupportedContentType } from 'common/services/useSupportedContentType
import { getGithubIntegration } from 'common/services/useGithubIntegration'
import { removeUserOverride } from 'components/RemoveUserOverride'
import ExternalResourcesLinkTab from 'components/ExternalResourcesLinkTab'
import MetadataTitle from 'components/metadata/MetadataTitle'
import { saveFeatureWithValidation } from 'components/saveFeatureWithValidation'

const CreateFlag = class extends Component {
Expand Down Expand Up @@ -182,7 +181,10 @@ const CreateFlag = class extends Component {
) {
this.getFeatureUsage()
}
if (Utils.getFlagsmithHasFeature('enable_metadata')) {
if (
Utils.getPlansPermission('METADATA') &&
Utils.getFlagsmithHasFeature('enable_metadata')
) {
getSupportedContentType(getStore(), {
organisation_id: AccountStore.getOrganisation().id,
}).then((res) => {
Expand Down Expand Up @@ -550,7 +552,9 @@ const CreateFlag = class extends Component {
const hideIdentityOverridesTab = Utils.getShouldHideIdentityOverridesTab()
const noPermissions = this.props.noPermissions
let regexValid = true
const metadataEnable = Utils.getFlagsmithHasFeature('enable_metadata')
const metadataEnable =
Utils.getPlansPermission('METADATA') &&
Utils.getFlagsmithHasFeature('enable_metadata')
try {
if (!isEdit && name && regex) {
regexValid = name.match(new RegExp(regex))
Expand Down Expand Up @@ -580,32 +584,24 @@ const CreateFlag = class extends Component {
)}
{metadataEnable && featureContentType?.id && (
<>
<MetadataTitle
visible={this.state.visible}
onVisibleChange={(v) => {
this.setState({ visible: v })
<label className='mt-1'>Custom Fields</label>
<AddMetadataToEntity
organisationId={AccountStore.getOrganisation().id}
projectId={this.props.projectId}
entityId={projectFlag?.id}
entityContentType={featureContentType?.id}
entity={featureContentType?.model}
setHasMetadataRequired={(b) => {
this.setState({
hasMetadataRequired: b,
})
}}
onChange={(m) => {
this.setState({
metadata: m,
})
}}
hasRequiredMetadata={this.state.hasMetadataRequired}
/>
{(this.state.hasMetadataRequired || this.state.visible) && (
<AddMetadataToEntity
organisationId={AccountStore.getOrganisation().id}
projectId={this.props.projectId}
entityId={projectFlag?.id}
entityContentType={featureContentType?.id}
entity={featureContentType?.model}
setHasMetadataRequired={(b) => {
this.setState({
hasMetadataRequired: b,
})
}}
onChange={(m) => {
this.setState({
metadata: m,
})
}}
/>
)}
</>
)}
{!identity && projectFlag && (
Expand Down Expand Up @@ -1971,12 +1967,23 @@ const FeatureProvider = (WrappedComponent) => {
this.listenTo(
FeatureListStore,
'saved',
({ changeRequest, createdFlag, isCreate } = {}) => {
toast(
`${createdFlag || isCreate ? 'Created' : 'Updated'} ${
changeRequest ? 'Change Request' : 'Feature'
}`,
)
({ changeRequest, createdFlag, error, isCreate } = {}) => {
if (error?.data?.metadata) {
error.data.metadata?.forEach((m) => {
if (Object.keys(m).length > 0) {
toast(m.non_field_errors[0], 'danger')
}
})
} else if (error?.data) {
toast('Error updating the Flag', 'danger')
return
} else {
toast(
`${createdFlag || isCreate ? 'Created' : 'Updated'} ${
changeRequest ? 'Change Request' : 'Feature'
}`,
)
}
const envFlags = FeatureListStore.getEnvironmentFlags()

if (createdFlag) {
Expand Down
8 changes: 6 additions & 2 deletions frontend/web/components/modals/CreateSegment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ const CreateSegment: FC<CreateSegmentType> = ({
const [metadata, setMetadata] = useState<CustomMetadataField[]>(
segment.metadata,
)
const metadataEnable = Utils.getFlagsmithHasFeature('enable_metadata')
const metadataEnable =
Utils.getPlansPermission('METADATA') &&
Utils.getFlagsmithHasFeature('enable_metadata')

const error = createError || updateError
const totalSegments = ProjectStore.getTotalSegments() ?? 0
Expand Down Expand Up @@ -763,7 +765,9 @@ const CreateSegment: FC<CreateSegmentType> = ({
</TabItem>
<TabItem
tabLabelString='Custom Fields'
tabLabel={<Row className='justify-content-center'>Custom Fields</Row>}
tabLabel={
<Row className='justify-content-center'>Custom Fields</Row>
}
>
<div className={className || 'my-3 mx-4'}>{MetadataTab}</div>
</TabItem>
Expand Down
8 changes: 6 additions & 2 deletions frontend/web/components/pages/CreateEnvironmentPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ const CreateEnvironmentPage = class extends Component {
componentDidMount = () => {
API.trackPage(Constants.pages.CREATE_ENVIRONMENT)

if (Utils.getFlagsmithHasFeature('enable_metadata')) {
if (
Utils.getPlansPermission('METADATA') &&
Utils.getFlagsmithHasFeature('enable_metadata')
) {
getSupportedContentType(getStore(), {
organisation_id: AccountStore.getOrganisation().id,
}).then((res) => {
Expand Down Expand Up @@ -196,7 +199,8 @@ const CreateEnvironmentPage = class extends Component {
</CondensedRow>
)}
</div>
{Utils.getFlagsmithHasFeature('enable_metadata') &&
{Utils.getPlansPermission('METADATA') &&
Utils.getFlagsmithHasFeature('enable_metadata') &&
envContentType?.id && (
<CondensedRow>
<FormGroup className='mt-5 setting'>
Expand Down
9 changes: 7 additions & 2 deletions frontend/web/components/pages/EnvironmentSettingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ const EnvironmentSettingsPage = class extends Component {
})
})

if (Utils.getFlagsmithHasFeature('enable_metadata')) {
if (
Utils.getPlansPermission('METADATA') &&
Utils.getFlagsmithHasFeature('enable_metadata')
) {
getSupportedContentType(getStore(), {
organisation_id: AccountStore.getOrganisation().id,
}).then((res) => {
Expand Down Expand Up @@ -260,7 +263,9 @@ const EnvironmentSettingsPage = class extends Component {
},
} = this
const has4EyesPermission = Utils.getPlansPermission('4_EYES')
const metadataEnable = Utils.getFlagsmithHasFeature('enable_metadata')
const metadataEnable =
Utils.getPlansPermission('METADATA') &&
Utils.getFlagsmithHasFeature('enable_metadata')

return (
<div className='app-container container'>
Expand Down
4 changes: 3 additions & 1 deletion frontend/web/components/pages/ProjectSettingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,9 @@ const ProjectSettingsPage = class extends Component {
const { name, stale_flags_limit_days } = this.state
const hasStaleFlagsPermission = Utils.getPlansPermission('STALE_FLAGS')

const metadataEnable = Utils.getFlagsmithHasFeature('enable_metadata')
const metadataEnable =
Utils.getPlansPermission('METADATA') &&
Utils.getFlagsmithHasFeature('enable_metadata')

return (
<div className='app-container container'>
Expand Down
2 changes: 1 addition & 1 deletion frontend/web/components/pages/SegmentsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import PageTitle from 'components/PageTitle'
import Switch from 'components/Switch'
import { setModalTitle } from 'components/modals/base/ModalDefault'
import classNames from 'classnames'
import InfoMessage from 'components/InfoMessage';
import InfoMessage from 'components/InfoMessage'

const CodeHelp = require('../../components/CodeHelp')
type SegmentsPageType = {
Expand Down

0 comments on commit d4006c0

Please sign in to comment.